diff --git a/virtrust/.keep b/virtrust/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/virtrust/src/virtrust/dllib/common.h b/virtrust/src/virtrust/dllib/common.h new file mode 100644 index 0000000000000000000000000000000000000000..56ef490dbcd4fa3a269e3b1e9575580aabcbe361 --- /dev/null +++ b/virtrust/src/virtrust/dllib/common.h @@ -0,0 +1,122 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +#include "virtrust/base/str_utils.h" + +namespace virtrust { + +// Dllib Return Code +enum class DllibRc : uint32_t { + OK = 0, + ERROR = 1, +}; + +template class DlFun { +public: + using FunTy = R (*) (Args...); + + DlFun() = default; + + DlFun(std::string_view name, FunTy funcptr) + : funcName_(name), funcptr_(funcptr ? std::function(funcptr) : std::function(nullptr)) + {} + + std::function Get() const + { + return funcptr_; + } + + R operator()(Args... args) const + { + if (!funcptr_) { + throw std::runtime_error(std::string("[") + __FILE__ + ":" + std::to_string(__LINE__) + + "]: Fatal Error: function " + funcName_ + + " is nullptr, maybe previous dlsym failed."); + } + return funcptr_(args...); + } + + +private: + std::string funcName_ = "unknown"; + std::function funcptr_ = nullptr; +}; + +class DlLibBase { +public: + // Check weather dlopen and dlsym has succeed + DllibRc CheckOk() const + { + return ok_ ? DllibRc::OK : DllibRc::ERROR; + } + + size_t Size() const + { + return size_; + } + +protected: + explicit DlLibBase(std::string_view lib) : libname_(lib) + {} + + virtual ~DlLibBase() + { + SelfDlClose(); + } + + void SelfDlClose() + { + // the stored pointer + if (libptr_ != nullptr) { + dlclose(libptr_); + libptr_ = nullptr; + } + + // reset to default + size_ = 0; + ok_ = true; + } + + DllibRc SelfDlOpen() + { + libptr_ = dlopen(libname_.data(), RTLD_NOW | RTLD_GLOBAL); + return libptr_ != nullptr ? DllibRc::OK : DllibRc::ERROR; + } + + template void SelfDlSym(std::string_view funName, DlFun &outFun) + { + if (libptr_ == nullptr || funName.empty()) { + return; + } + + void *funPtr = dlsym(libptr_, funName.data()); + if (funPtr == nullptr) { + ok_ = false; + } + size_++; // always add up internal size counter + outFun = DlFun(funName, reinterpret_cast(funPtr)); + } + +private: + void *libptr_ = nullptr; + const std::string libname_ = "unknown"; + + // duncCache_ store all dlsym function raw pointers + // WARNING: DO NOT manually manipulate those pointers + std::vector funcCache_; // cache DO NOT own pointers, those pointers should read only + size_t size_ = 0; + bool ok_ = true; +}; + +// The second argument is the templateHelper which helps template deduction +#define DLLIB_SELF_DLSYM(NAME) SelfDlSym(#NAME, NAME) + +} // namespace virtrust \ No newline at end of file diff --git a/virtrust/src/virtrust/dllib/libguestfs.h b/virtrust/src/virtrust/dllib/libguestfs.h new file mode 100644 index 0000000000000000000000000000000000000000..238938555cb446b56ae40ffcfabc8dd4f55478a6 --- /dev/null +++ b/virtrust/src/virtrust/dllib/libguestfs.h @@ -0,0 +1,98 @@ +#pragma once + +#include + +#include +#include +#include +#include + +#include "virtrust/dllib/common.h" +#include "virtrust/dllib/libguestfs_defines.h" + +namespace virtrust { + +// libguestfs api +class Libguestfs : public DlLibBase { +public: + ~Libguestfs() = default; + Libguestfs(const Libguestfs &) = delete; + void operator=(const Libguestfs &) = delete; + + // Singleton instance + static Libguestfs &GetInstance() + { + static Libguestfs instance; + return instance; + } + + // Reload all functions + DllibRc Reload() + { + SelfDlClose(); + LoadAll(); + return CheckOk(); + } + + // Declare all functions that you need + // NOTE Please make sure the class instance is inited before calling those functions + + // Create guestfs context + DlFun guestfs_create; + + DlFun guestfs_set_backend; + + DlFun guestfs_add_drive_opts_argv; + + DlFun guestfs_launch; + + DlFun guestfs_inspect_os; + + DlFun guestfs_inspect_get_mountpoints; + + DlFun guestfs_mount_ro; + + DlFun guestfs_unmount_all; + + DlFun guestfs_close; + + DlFun guestfs_set_trace; + + DlFun guestfs_exists; + + DlFun guestfs_is_file; + + DlFun guestfs_read_file; + +private: + void LoadAll() + { + // NOTE explicitly dlopen shared library + auto ret = SelfDlOpen(); + if (ret != DllibRc::OK) { + return; + } + DLLIB_SELF_DLSYM(guestfs_create); + DLLIB_SELF_DLSYM(guestfs_set_backend); + DLLIB_SELF_DLSYM(guestfs_add_drive_opts_argv); + DLLIB_SELF_DLSYM(guestfs_launch); + DLLIB_SELF_DLSYM(guestfs_inspect_os); + DLLIB_SELF_DLSYM(guestfs_inspect_get_mountpoints); + DLLIB_SELF_DLSYM(guestfs_mount_ro); + DLLIB_SELF_DLSYM(guestfs_unmount_all); + DLLIB_SELF_DLSYM(guestfs_close); + DLLIB_SELF_DLSYM(guestfs_set_trace); + DLLIB_SELF_DLSYM(guestfs_exists); + DLLIB_SELF_DLSYM(guestfs_is_file); + DLLIB_SELF_DLSYM(guestfs_read_file); + } + + Libguestfs() : DlLibBase(LIB_NAME) + { + LoadAll(); + } + + static constexpr std::string_view LIB_NAME = "libguestfs.so"; +}; + +} // namespace virtrust \ No newline at end of file diff --git a/virtrust/src/virtrust/dllib/libguestfs_defines.h b/virtrust/src/virtrust/dllib/libguestfs_defines.h new file mode 100644 index 0000000000000000000000000000000000000000..cf4aa4515ca998a26fad8170cf67be2a025f075f --- /dev/null +++ b/virtrust/src/virtrust/dllib/libguestfs_defines.h @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include +#include +#include + +namespace virtrust { + +// see: libguestfs.h, it's a forward declaration in original header file +struct guestfs_h; + +struct guestfs_add_drive_opts_argv { + uint64_t bitmask; +# define GUESTFS_ADD_DRIVE_OPTS_READONLY_BITMASK (UINT64_C(1)<<0) + int readonly; +# define GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK (UINT64_C(1)<<1) + const char *format; +# define GUESTFS_ADD_DRIVE_OPTS_IFACE_BITMASK (UINT64_C(1)<<2) + const char *iface; +# define GUESTFS_ADD_DRIVE_OPTS_NAME_BITMASK (UINT64_C(1)<<3) + const char *name; +# define GUESTFS_ADD_DRIVE_OPTS_LABEL_BITMASK (UINT64_C(1)<<4) + const char *label; +# define GUESTFS_ADD_DRIVE_OPTS_PROTOCOL_BITMASK (UINT64_C(1)<<5) + const char *protocol; +# define GUESTFS_ADD_DRIVE_OPTS_SERVER_BITMASK (UINT64_C(1)<<6) + char *const *server; +# define GUESTFS_ADD_DRIVE_OPTS_USERNAME_BITMASK (UINT64_C(1)<<7) + const char *username; +# define GUESTFS_ADD_DRIVE_OPTS_SECRET_BITMASK (UINT64_C(1)<<8) + const char *secret; +# define GUESTFS_ADD_DRIVE_OPTS_CACHEMODE_BITMASK (UINT64_C(1)<<9) + const char *cachemode; +# define GUESTFS_ADD_DRIVE_OPTS_DISCARD_BITMASK (UINT64_C(1)<<10) + const char *discard; +# define GUESTFS_ADD_DRIVE_OPTS_COPYONREAD_BITMASK (UINT64_C(1)<<11) + int copyonread; +# define GUESTFS_ADD_DRIVE_OPTS_BLOCKSIZE_BITMASK (UINT64_C(1)<<12) + int blocksize; +}; + +} // namespace virtrust \ No newline at end of file diff --git a/virtrust/src/virtrust/dllib/libvirt.h b/virtrust/src/virtrust/dllib/libvirt.h new file mode 100644 index 0000000000000000000000000000000000000000..6d26996d6e75667af6cc82fa8a0f467985bbe93b --- /dev/null +++ b/virtrust/src/virtrust/dllib/libvirt.h @@ -0,0 +1,98 @@ +#pragma once + +#include + +#include +#include + +#include "virtrust/dllib/common.h" +#include "virtrust/dllib/libvirt_defines.h" + +namespace virtrust { + +// libvirt api +class Libvirt : public DlLibBase { + ~Libvirt() = default; + Libvirt(const Libvirt &) = delete; + void operator=(const Libvirt &) = delete; + + // Singleton instance + static Libvirt &GetInstance() + { + static Libvirt instance; + return instance; + } + + // Reload all functions + DllibRc Reload() + { + SelfDlClose(); + LoadAll(); + return CheckOk(); + } + + DllibRc SetErrorFunction(virErrorFunc func) + { + auto ret = GetInstance().CheckOk(); + if (ret != DllibRc::OK) { + return ret; + } + virSetErrorFunc(nullptr, func); + return DllibRc::OK; + } + + // Declare all functions that you need + // NOTE Please make sure the class instance is inited before calling those functions + DlFun virConnectOpen; + DlFun virDomainLookupByName; + DlFun virDomainCreateWithFlags; + DlFun virConnectClose; + DlFun virDomainFree; + DlFun virDomainShutDownFlags; + DlFun virConnectNumOfDomains; + DlFun virConnectListAllDomains; + DlFun virDomainGetID; + DlFun virDomainGetName; + DlFun virDomainGetInfo; + DlFun virDomainDestroyFlags; + DlFun virDomainUndefineFlags; + DlFun virSetErrorFunc; + DlFun virDomainGetUUIDString; + DlFun + virDomainMigrate3; + +private: + void LoadAll() + { + // NOTE explicitly dlopen shared library + auto ret = SelfDlOpen(); + if (ret != DllibRc::OK) { + return; + } + DLLIB_SELF_DLSYM(virConnectOpen); + DLLIB_SELF_DLSYM(virDomainLookupByName); + DLLIB_SELF_DLSYM(virDomainCreateWithFlags); + DLLIB_SELF_DLSYM(virConnectClose); + DLLIB_SELF_DLSYM(virDomainFree); + DLLIB_SELF_DLSYM(virDomainShutDownFlags); + DLLIB_SELF_DLSYM(virConnectNumOfDomains); + DLLIB_SELF_DLSYM(virConnectListAllDomains); + DLLIB_SELF_DLSYM(virDomainGetID); + DLLIB_SELF_DLSYM(virDomainGetName); + DLLIB_SELF_DLSYM(virDomainGetInfo); + DLLIB_SELF_DLSYM(virDomainDestroyFlags); + DLLIB_SELF_DLSYM(virDomainUndefineFlags); + DLLIB_SELF_DLSYM(virSetErrorFunc); + DLLIB_SELF_DLSYM(virDomainGetUUIDString); + DLLIB_SELF_DLSYM(virDomainMigrate3); + } + + Libvirt() : DlLibBase(LIB_NAME) + { + LoadAll(); + } + + static constexpr std::string_view LIB_NAME = "libvirt.so"; +}; + +} // namespace virtrust \ No newline at end of file diff --git a/virtrust/src/virtrust/dllib/libvirt_defines.h b/virtrust/src/virtrust/dllib/libvirt_defines.h new file mode 100644 index 0000000000000000000000000000000000000000..2b3f5c0034359c3692d1fa9033c6fbe1c750baf0 --- /dev/null +++ b/virtrust/src/virtrust/dllib/libvirt_defines.h @@ -0,0 +1,193 @@ +#pragma once + +#include + +#include "virtrust/base/custom_logger.h" + +namespace virtrust { + +using virConnectPtr = int *; +using virDomainPtr = int *; +using virNetworkPtr = int *; +using virTypeParameterPtr = int *; + +/** + * virDomainState: + * + * A domain may be in different states at a given point in time + * + * Since: 0.0.1 + */ +typedef enum { + VIR_DOMAIN_NOSTATE = 0, /* no state (Since: 0.0.1) */ + VIR_DOMAIN_RUNNING = 1, /* the domain is running (Since: 0.0.1) */ + VIR_DOMAIN_BLOCKED = 2, /* the domain is blocked on resource (Since: 0.0.1) */ + VIR_DOMAIN_PAUSED = 3, /* the domain is paused by user (Since: 0.0.1) */ + VIR_DOMAIN_SHUTDOWN= 4, /* the domain is being shut down (Since: 0.0.1) */ + VIR_DOMAIN_SHUTOFF = 5, /* the domain is shut off (Since: 0.0.1) */ + VIR_DOMAIN_CRASHED = 6, /* the domain is crashed (Since: 0.0.2) */ + VIR_DOMAIN_PMSUSPENDED = 7, /* the domain is suspended by guest + power management (Since: 0.9.11) */ +} virDomainState; + +/** + * virDomainInfo: + * + * a virDomainInfo is a structure filled by virDomainGetInfo() and extracting + * runtime information for a given active Domain + * + * Since: 0.0.1 + */ +typedef struct _virDomainInfo virDomainInfo; + +struct _virDomainInfo { + unsigned char state; /* the running state, one of virDomainState */ + unsigned long maxMem; /* the maximum memory in KBytes allowed */ + unsigned long memory; /* the memory in KBytes used by the domain */ + unsigned short nrVirtCpu; /* the number of virtual CPUs for the domain */ + unsigned long long cpuTime; /* the CPU time used in nanoseconds */ +}; + +/** + * virConnectListAllDomainsFlags: + * + * Flags used to tune which domains are listed by virConnectListAllDomains(). + * Note that these flags come in groups; if all bits from a group are 0, + * then that group is not used to filter results. + * + * Since: 0.9.13 + */ +typedef enum { + VIR_CONNECT_LIST_DOMAINS_ACTIVE = 1 << 0, /* (Since: 0.9.13) */ + VIR_CONNECT_LIST_DOMAINS_INACTIVE = 1 << 1, /* (Since: 0.9.13) */ + + VIR_CONNECT_LIST_DOMAINS_PERSISTENT = 1 << 2, /* (Since: 0.9.13) */ + VIR_CONNECT_LIST_DOMAINS_TRANSIENT = 1 << 3, /* (Since: 0.9.13) */ + + VIR_CONNECT_LIST_DOMAINS_RUNNING = 1 << 4, /* (Since: 0.9.13) */ + VIR_CONNECT_LIST_DOMAINS_PAUSED = 1 << 5, /* (Since: 0.9.13) */ + VIR_CONNECT_LIST_DOMAINS_SHUTOFF = 1 << 6, /* (Since: 0.9.13) */ + VIR_CONNECT_LIST_DOMAINS_OTHER = 1 << 7, /* (Since: 0.9.13) */ + + VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE = 1 << 8, /* (Since: 0.9.13) */ + VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE = 1 << 9, /* (Since: 0.9.13) */ + + VIR_CONNECT_LIST_DOMAINS_AUTOSTART = 1 << 10, /* (Since: 0.9.13) */ + VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART = 1 << 11, /* (Since: 0.9.13) */ + + VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT = 1 << 12, /* (Since: 0.9.13) */ + VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT = 1 << 13, /* (Since: 0.9.13) */ + + VIR_CONNECT_LIST_DOMAINS_HAS_CHECKPOINT = 1 << 14, /* (Since: 5.6.0) */ + VIR_CONNECT_LIST_DOMAINS_NO_CHECKPOINT = 1 << 15, /* (Since: 5.6.0) */ +} virConnectListAllDomainsFlags; + +/** + * virDomainCreateFlags: + * + * Flags OR'ed together to provide specific behaviour when creating a + * Domain. + * + * Since: 0.0.1 + */ +typedef enum { + VIR_DOMAIN_NONE = 0, /* Default behavior (Since: 0.0.1) */ + VIR_DOMAIN_START_PAUSED = 1 << 0, /* Launch guest in paused state (Since: 0.8.2) */ + VIR_DOMAIN_START_AUTODESTROY = 1 << 1, /* Automatically kill guest when virConnectPtr is closed (Since: 0.9.3) */ + VIR_DOMAIN_START_BYPASS_CACHE = 1 << 2, /* Avoid file system cache pollution (Since: 0.9.4) */ + VIR_DOMAIN_START_FORCE_BOOT = 1 << 3, /* Boot, discarding any managed save (Since: 0.9.5) */ + VIR_DOMAIN_START_VALIDATE = 1 << 4, /* Validate the XML document against schema (Since: 1.2.12) */ + VIR_DOMAIN_START_RESET_NVRAM = 1 << 5, /* Re-initialize NVRAM from template (Since: 8.1.0) */ +} virDomainCreateFlags; + +/** + * virDomainUndefineFlagsValues: + * + * Since: 0.9.4 + */ +typedef enum { + VIR_DOMAIN_UNDEFINE_MANAGED_SAVE = (1 << 0), /* Also remove any + managed save (Since: 0.9.4) */ + VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA = (1 << 1), /* If last use of domain, + then also remove any + snapshot metadata (Since: 0.9.5) */ + VIR_DOMAIN_UNDEFINE_NVRAM = (1 << 2), /* Also remove any + nvram file (Since: 1.2.9) */ + VIR_DOMAIN_UNDEFINE_KEEP_NVRAM = (1 << 3), /* Keep nvram file (Since: 2.3.0) */ + VIR_DOMAIN_UNDEFINE_CHECKPOINTS_METADATA = (1 << 4), /* If last use of domain, + then also remove any + checkpoint metadata (Since: 5.6.0) */ + VIR_DOMAIN_UNDEFINE_TPM = (1 << 5), /* Also remove any + TPM state (Since: 8.9.0) */ + VIR_DOMAIN_UNDEFINE_KEEP_TPM = (1 << 6), /* Keep TPM state (Since: 8.9.0) */ + /* Future undefine control flags should come here. */ +} virDomainUndefineFlagsValues; + +/** + * virErrorLevel: + * + * Indicates the level of an error + * + * Since: 0.1.0 + */ +typedef enum { + VIR_ERR_NONE = 0, /* (Since: 0.1.0) */ + VIR_ERR_WARNING = 1, /* A simple warning (Since: 0.1.0) */ + VIR_ERR_ERROR = 2 /* An error (Since: 0.1.0) */ +} virErrorLevel; + +inline LogLevel virErrorLevelToLogLevel(virErrorLevel level) +{ + switch (level) { + case VIR_ERR_WARNING: { + return LogLevel::WARN; + } + case VIR_ERR_ERROR: { + return LogLevel::WARN; + } + default: + return LogLevel::UNKNOWN; + } +} + +/** + * virError: + * + * A libvirt Error instance. + * + * The conn, dom and net fields should be used with extreme care. + * Reference counts are not incremented so the underlying objects + * may be deleted without notice after the error has been delivered. + * + * Since: 0.1.0 + */ +using virError = struct _virError; + +/** + * virErrorPtr: + * + * Since: 0.1.0 + */ +using virErrorPtr = virError *; + +struct _virError { + int code; /* The error code, a virErrorNumber */ + int domain; /* What part of the library raised this error */ + char *message; /* human-readable informative error message */ + virErrorLevel level; /* how consequent is the error */ + virConnectPtr conn; /* connection if available, deprecated + see note above */ + virDomainPtr dom; /* domain if available, deprecated + see note above */ + char *str1; /* extra string information */ + char *str2; /* extra string information */ + char *str3; /* extra string information */ + int int1; /* extra number information */ + int int2; /* extra number information */ + virNetworkPtr net; /* network if available, deprecated + see note above */ +}; + +using virErrorFunc = void (*)(void *userData, virErrorPtr error); + +} // namespace virtrust \ No newline at end of file diff --git a/virtrust/src/virtrust/dllib/libxml2.h b/virtrust/src/virtrust/dllib/libxml2.h new file mode 100644 index 0000000000000000000000000000000000000000..d71e6db22c755f2d1661c4c8a4499e32d743947b --- /dev/null +++ b/virtrust/src/virtrust/dllib/libxml2.h @@ -0,0 +1,65 @@ +#pragma once + +#include + +#include + +#include "virtrust/dllib/common.h" +#include "virtrust/dllib/libxml2_defines.h" + +namespace virtrust { + +// libxml2 api +class Libxml2 : public DlLibBase { +public: + ~Libxml2() = default; + Libxml2(const Libxml2 &) = delete; + void operator=(const Libxml2 &) = delete; + + // Singleton instance + static Libxml2 &GetInstance() + { + static Libxml2 instance; + return instance; + } + + // Reload all functions + DllibRc Reload() + { + SelfDlClose(); + LoadAll(); + return CheckOk(); + } + + // Declare all functions that you need + // NOTE Please make sure the class instance is inited before calling those functions + DlFun xmlParseFile; + DlFun xmlFreeDoc; + DlFun xmlDocGetRootElement; + DlFun xmlGetProp; + DlFun xmlFree; + +private: + void LoadAll() + { + // NOTE explicitly dlopen shared library + auto ret = SelfDlOpen(); + if (ret != DllibRc::OK) { + return; + } + DLLIB_SELF_DLSYM(xmlParseFile); + DLLIB_SELF_DLSYM(xmlFreeDoc); + DLLIB_SELF_DLSYM(xmlDocGetRootElement); + DLLIB_SELF_DLSYM(xmlGetProp); + DLLIB_SELF_DLSYM(xmlFree); + } + + Libxml2() : DlLibBase(LIB_NAME) + { + LoadAll(); + } + + static constexpr std::string_view LIB_NAME = "libxml2.so"; +}; + +} // namespace virtrust \ No newline at end of file diff --git a/virtrust/src/virtrust/dllib/libxml2_defines.h b/virtrust/src/virtrust/dllib/libxml2_defines.h new file mode 100644 index 0000000000000000000000000000000000000000..ebf74564fcabed082ba03bc42b87ef4c9553e1eb --- /dev/null +++ b/virtrust/src/virtrust/dllib/libxml2_defines.h @@ -0,0 +1,139 @@ +#pragma once + +namespace virtrust { + +using xmlChar = unsigned char; + +// --------------------------------------------------------------------------- +// Type definition from libxml2/libxml/tree.h +// --------------------------------------------------------------------------- + +/* + * The different element types carried by an XML tree. + * + * NOTE: This is synchronized with DOM Level1 values + * See http://www.w3.org/TR/REC-DOM-Level-1/ + * + * Actually this had diverged a bit, and now XML_DOCUMENT_TYPE_NODE should + * be deprecated to use an XML_DTD_NODE. + */ +typedef enum { + XML_ELEMENT_NODE = 1, + XML_ATTRIBUTE_NODE = 2, + XML_TEXT_NODE = 3, + XML_CDATA_SECTION_NODE = 4, + XML_ENTITY_REF_NODE = 5, + XML_ENTITY_NODE = 6, + XML_PI_NODE = 7, + XML_COMMENT_NODE = 8, + XML_DOCUMENT_NODE = 9, + XML_DOCUMENT_TYPE_NODE = 10, + XML_DOCUMENT_FRAG_NODE = 11, + XML_NOTATION_NODE = 12, + XML_HTML_DOCUMENT_NODE = 13, + XML_DTD_NODE = 14, + XML_ELEMENT_DECL = 15, + XML_ATTRIBUTE_DECL = 16, + XML_ENTITY_DECL = 17, + XML_NAMESPACE_DECL = 18, + XML_XINCLUDE_START = 19, + XML_XINCLUDE_END = 20 + /* XML_DOCB_DOCUMENT_NODE= 21 */ /* removed */ +} xmlElementType; + +/** + * xmlNs: + * + * An XML namespace. + * Note that prefix == NULL is valid, it defines the default namespace + * within the subtree (until overridden). + * + * xmlNsType is unified with xmlElementType. + */ +using xmlNs = struct _xmlNs; +using xmlNsType = xmlElementType; + +struct _xmlNs { + struct _xmlNs *next; /* next Ns link for this node */ + xmlNsType type; /* global or local */ + const xmlChar *href; /* URL for the namespace */ + const xmlChar *prefix; /* prefix for the namespace */ + void *_private; /* application data */ + struct _xmlDoc *context; /* normally an xmlDoc */ +}; + +/** + * xmlDoc: + * + * An XML document. + */ +using xmlDoc = struct _xmlDoc; +using xmlDocPtr = xmlDoc *; + +struct _xmlDoc { + void *_private; /* application data */ + xmlElementType type; /* XML_DOCUMENT_NODE, must be second ! */ + char *name; /* name/filename/URI of the document */ + struct _xmlNode *children; /* the document tree */ + struct _xmlNode *last; /* last child link */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* autoreference to itself */ + + /* End of common part */ + int compression;/* level of zlib compression */ + int standalone; /* standalone document (no external refs) + 1 if standalone="yes" + 0 if standalone="no" + -1 if there is no XML declaration + -2 if there is an XML declaration, but no + standalone attribute was specified */ + struct _xmlDtd *intSubset; /* the document internal subset */ + struct _xmlDtd *extSubset; /* the document external subset */ + struct _xmlNs *oldNs; /* Global namespace, the old way */ + const xmlChar *version; /* the XML version string */ + const xmlChar *encoding; /* external initial encoding, if any */ + void *ids; /* Hash table for ID attributes if any */ + void *refs; /* Hash table for IDREFs attributes if any */ + const xmlChar *URL; /* The URI for that document */ + int charset; /* Internal flag for charset handling, + actually an xmlCharEncoding */ + struct _xmlDict *dict; /* dict used to allocate names or NULL */ + void *psvi; /* for type/PSVI information */ + int parseFlags; /* set of xmlParserOption used to parse the + document */ + int properties; /* set of xmlDocProperties for this document + set at the end of parsing */ +}; + +/** + * xmlNode: + * + * A node in an XML tree. + */ +using xmlNode = struct _xmlNode; +using xmlNodePtr = xmlNode *; + +struct _xmlNode { + void *_private; /* application data */ + xmlElementType type; /* type number, must be second ! */ + const xmlChar *name; /* the name of the node, or the entity */ + struct _xmlNode *children; /* parent->childs link */ + struct _xmlNode *last; /* last child link */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + /* End of common part */ + xmlNs *ns; /* pointer to the associated namespace */ + xmlChar *content; /* the content */ + struct _xmlAttr *properties;/* properties list */ + xmlNs *nsDef; /* namespace definitions on this node */ + void *psvi; /* for type/PSVI information */ + unsigned short line; /* line number */ + unsigned short extra; /* extra data for XPath/XSLT */ +}; + +} // namespace virtrust diff --git a/virtrust/src/virtrust/dllib/openssl.h b/virtrust/src/virtrust/dllib/openssl.h new file mode 100644 index 0000000000000000000000000000000000000000..3763a8d1c71f8375f0ec4e9320a4f57b347106ae --- /dev/null +++ b/virtrust/src/virtrust/dllib/openssl.h @@ -0,0 +1,95 @@ +#pragma once + +#include + +#include +#include +#include + +#include "virtrust/dllib/common.h" +#include "virtrust/dllib/openssl_defines.h" + +namespace virtrust { + +// openssl api +class Openssl : public DlLibBase { +public: + ~Openssl() = default; + Openssl(const Openssl &) = delete; + void operator=(const Openssl &) = delete; + + // Singleton instance + static Openssl &GetInstance() + { + static Openssl instance; + return instance; + } + + // Reload all functions + DllibRc Reload() + { + SelfDlClose(); + LoadAll(); + return CheckOk(); + } + + // Declare all functions that you need + // NOTE Please make sure the class instance is inited before calling those functions + + // Fetch openssl message disgest context + DlFun EVP_MD_fetch; + + // Get the output size of the message disgest algorithm (e.g. SM3), this function is the same as EVP_MD_size + DlFun EVP_MD_get_size; + + // Create new message digest context + DlFun EVP_MD_CTX_new; + + // Reset md context + DlFun EVP_MD_CTX_reset; + + // Copy md context + DlFun EVP_MD_CTX_copy_ex; + + // Init + DlFun EVP_DigestInit; + + // Update + DlFun EVP_Digest_Update; + + // Final + DlFun EVP_DigestFinal_ex; + + // Free + DlFun EVP_MD_free; + DlFun EVP_MD_CTX_free; + +private: + void LoadAll() + { + // NOTE explicitly dlopen shared library + auto ret = SelfDlOpen(); + if (ret != DllibRc::OK) { + return; + } + DLLIB_SELF_DLSYM(EVP_MD_fetch); + DLLIB_SELF_DLSYM(EVP_MD_get_size); + DLLIB_SELF_DLSYM(EVP_MD_CTX_new); + DLLIB_SELF_DLSYM(EVP_MD_CTX_reset); + DLLIB_SELF_DLSYM(EVP_MD_CTX_copy_ex); + DLLIB_SELF_DLSYM(EVP_DigestInit); + DLLIB_SELF_DLSYM(EVP_Digest_Update); + DLLIB_SELF_DLSYM(EVP_DigestFinal_ex); + DLLIB_SELF_DLSYM(EVP_MD_free); + DLLIB_SELF_DLSYM(EVP_MD_CTX_free); + } + + Openssl() : DlLibBase(LIB_NAME) + { + LoadAll(); + } + + static constexpr std::string_view LIB_NAME = "libcrypto.so"; +}; + +} // namespace virtrust diff --git a/virtrust/src/virtrust/dllib/openssl_defines.h b/virtrust/src/virtrust/dllib/openssl_defines.h new file mode 100644 index 0000000000000000000000000000000000000000..6e8743acede0fad05347b3c923ece7a563b31740 --- /dev/null +++ b/virtrust/src/virtrust/dllib/openssl_defines.h @@ -0,0 +1,12 @@ +#pragma once + +namespace virtrust { + +using EVP_MD = struct evp_md_st; +using EVP_MD_CTX = struct evp_md_ctx_st; +using OSSL_LIB_CTX = struct ossl_lib_ctx_st; + +// openssl return value check +constexpr int OPENSSL_OK = 1; + +} // namespace virtrust \ No newline at end of file diff --git a/virtrust/src/virtrust/utils/enum_check.h b/virtrust/src/virtrust/utils/enum_check.h new file mode 100644 index 0000000000000000000000000000000000000000..4c3ca5b1f391fb4861375fdfd7adfc020adb3d5c --- /dev/null +++ b/virtrust/src/virtrust/utils/enum_check.h @@ -0,0 +1,28 @@ +#pragma once + +namespace virtrust { + +// Define templates for enum range check + +template class EnumCheck {}; + +template class EnumCheck { +public: + template static bool constexpr IsValue(IntType) + { + return false; + } +}; + +template +class EnumCheck : private EnumCheck { + using Super = EnumCheck; + +public: + template static bool constexpr IsValue(IntType v) + { + return v == static_cast(v) || Super::IsValue(v); + } +}; + +} // namespace virtrust \ No newline at end of file diff --git a/virtrust/src/virtrust/utils/file_io.cpp b/virtrust/src/virtrust/utils/file_io.cpp new file mode 100644 index 0000000000000000000000000000000000000000..81ffd1dd7c91f233bbc80224b5cf4eb07bbf8906 --- /dev/null +++ b/virtrust/src/virtrust/utils/file_io.cpp @@ -0,0 +1,237 @@ +#include "virtrust/utils/file_io.h" + +#include +#include +#include +#include +#include +#include + +#include "spdlog/fmt/fmt.h" +#include "spdlog/spdlog.h" + +#include "virtrust/base/exception.h" +#include "virtrust/base/logger.h" + +namespace virtrust { +#define FILE_IO_THROW(msg_prefix) \ + VIRTRUST_ENFORCE(false, fmt::format("|{}|END|||error on file {}, failure {}", msg_prefix, fileName_, e.what, \ + std::strerror(errno), errno)) + +FileInputStream::FileInputStream(std::string fileName) : fileName_(std::move(fileName)), fileLen_(0) +{ +#ifndef __arm64__ + in_.exceptions(std::ifstream::badbit | std::ios::failbit); +#endif + try { + in_.open(fileName_, std::ios::binary | std::ios::ate); + } catch (const std::ifstream::failure &e) { + FILE_IO_THROW(("Open for read")); + } + fileLen_ = Tellg(); + Seekg(0); +} + +bool FileInputStream::operator!() const +{ + return !static_cast(in_); +} + +FileInputStream::operator bool() const +{ + return static_cast(in_); +} + +bool FileInputStream::Eof() const +{ + return in_.eof(); +} + +FileInputStream &FileInputStream::GetLine(std::string *ret, char delim) +{ + try { + std::getline(in_, *ret, delim); + } catch (const std::ifstream::failure &e) { + if (!in_.eof() || in_.bad()) { + FILE_IO_THROW("GetLine"); + } + } + return *this; +} + +FileInputStream &FileInputStream::Read(void *buf, size_t length) +{ + try { + in_.read(static_cast(buf), length); + } catch (const std::ifstream::failure &e) { + FILE_IO_THROW("Read"); + } + return *this; +} + +FileInputStream &FileInputStream::Seekg(size_t pos) +{ + try { + // clear EOF/FAIL bit + in_.clear(); + in_.seekg(pos); + } catch (const std::ifstream::failure &e) { + FILE_IO_THROW("Seekg"); + } + return *this; +} + +size_t FileInputStream::Tellg() +{ + size_t ret = 0; + try { + auto backup = in_.rdstate(); + in_.clear(); + // tellg fail if eofbit is set. + ret = in_.tellg(); + in_.clear(backup); + } catch (const std::ifstream::failure &e) { + if (!in_.bad()) { + FILE_IO_THROW("Tellg"); + } + } + return ret; +} + +void FileInputStream::TransferTo(std::ostringstream &oss) +{ + try { + // clear EOF/FAIL bit + in_.clear(); + in_.seekg(0); + oss << in_.rdbuf(); + } catch (const std::ifstream::failure &e) { + FILE_IO_THROW("TransferTo"); + } +} + +std::string FileInputStream::ReadAll() +{ + try { + std::ostringstream oss; + TransferTo(oss); + return oss.str(); + } catch (const std::ifstream::failure &e) { + FILE_IO_THROW("ReadAll"); + } + return ""; +} + +size_t FileInputStream::GetLength() const +{ + return fileLen_; +} + +const std::string &FileInputStream::GetName() const +{ + return fileName_; +} + +void FileInputStream::Close() +{ + try { + in_.close(); + } catch (const std::ifstream::failure &e) { + FILE_IO_THROW("Close"); + } + fileLen_ = 0; +} + +std::unique_ptr FileInputStream::Spawn() +{ + auto ret = std::make_unique(fileName_); + ret->Seekg(Tellg()); + return ret; +} + +FileOutputStream::FileOutputStream(std::string fileName, bool trunc, bool exitFailInDestructor) + : fileName_(std::move(fileName)), exitFailInDestructor_(exitFailInDestructor) +{ + std::filesystem::path fp(fileName_); + // empty if relative path to pwd. + if (!fp.parent_path().empty() && !std::filesystem::exists(fp.parent_path())) { + VIRTRUST_ENFORCE(std::filesystem::create_directories(fp.parent_path()), "Failed to create dir {}", + fp.parent_path().string()); + } + out_.exceptions(std::ifstream::badbit | std::ifstream::failbit); + try { + out_.open(fileName_, std::ofstream::binary | (trunc ? std::ofstream::trunc : std::ofstream::app)); + } catch (const std::ofstream::failure &e) { + FILE_IO_THROW("Open for write"); + } +} + +FileOutputStream::~FileOutputStream() +{ + try { + Close(); + } catch (const std::ofstream::failure &e) { + SPDLOG_ERROR("IO error in destructor: < {} >", e.what()); + if (exitFailInDestructor_) { + _exit(-1); + } + } +} + +void FileOutputStream::Write(const void *buf, size_t length) +{ + try { + out_.write(static_cast(buf), length); + } catch (const std::ofstream::failure &e) { + FILE_IO_THROW("Write"); + } +} + +void FileOutputStream::Write(std::string_view buf) +{ + try { + out_.write(buf.data(), buf.size()); + } catch (const std::ofstream::failure &e) { + FILE_IO_THROW("Write"); + } +} + +const std::string FileOutputStream::GetName() const +{ + return fileName_; +} + +size_t FileOutputStream::Tellp() +{ + size_t ret = 0; + try { + ret = out_.tellp(); + } catch (const std::ofstream::failure &e) { + FILE_IO_THROW("Tellp"); + } + return ret; +} + +void FileOutputStream::Flush() +{ + try { + if (out_.is_open() && out_.good()) { + out_.flush(); + } + } catch (const std::ofstream::failure &e) { + FILE_IO_THROW("Flush"); + } +} + +void FileOutputStream::Close() +{ + try { + if (out_.is_open() && out_.good()) { + out_.close(); + } + } catch (const std::ofstream::failure &e) { + FILE_IO_THROW("Close"); + } +} + +} // namespace virtrust diff --git a/virtrust/src/virtrust/utils/file_io.h b/virtrust/src/virtrust/utils/file_io.h new file mode 100644 index 0000000000000000000000000000000000000000..5e169090f217a46ac504d47136e77ff44a600f93 --- /dev/null +++ b/virtrust/src/virtrust/utils/file_io.h @@ -0,0 +1,80 @@ +#pragma once + +#include +#include +#include + +namespace virtrust { +class FileInputStream { +public: + + explicit FileInputStream(std::string fileName); + + ~FileInputStream() = default; + + bool operator!() const; + + explicit operator bool() const; + + bool Eof() const; + + FileInputStream &GetLine(std::string *ret, char delim); + + FileInputStream &Read(void *buf, size_t length); + + FileInputStream &Seekg(size_t pos); + + size_t Tellg(); + + void TransferTo(std::ostringstream &oss); + + std::string ReadAll(); + + size_t GetLength() const; + + const std::string &GetName() const; + + void Close(); + + static bool IsStreaming() + { + return false; + } + + std::unique_ptr Spawn(); + +private: + const std::string fileName_; + std::ifstream in_; + size_t fileLen_; +}; + +class FileOutputStream { +public: + explicit FileOutputStream(std::string fileName, bool trunc = true, bool exitFailInDestructor = true); + + ~FileOutputStream(); + + void Write(const void *buf, size_t lenth); + void Write(std::string_view buf); + + const std::string GetName() const; + + size_t Tellp(); + + void Close(); + + void Flush(); + + static bool IsStreaming() + { + return false; + } + +private: + const std::string fileName_; + const bool exitFailInDestructor_; + std::ofstream out_; +}; + +} // namespace virtrust \ No newline at end of file diff --git a/virtrust/src/virtrust/utils/foreign_mounter.cpp b/virtrust/src/virtrust/utils/foreign_mounter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7c55aa0ede51f5286cc56bafcb2933266da1021 --- /dev/null +++ b/virtrust/src/virtrust/utils/foreign_mounter.cpp @@ -0,0 +1,353 @@ +#include "virtrust/utils/foreign_mounter.h" + +#include +#include +#include + +#include "spdlog/fmt/fmt.h" + +#include "virtrust/base/logger.h" +#include "virtrust/base/str_utils.h" +#include "virtrust/crypto/sm3.h" +#include "virtrust/dllib/common.h" + +namespace virtrust { + +constexpr std::string_view DEFAULT_SHIM_EFI_REGEX_PATH = "/boot/efi/EFI/{}/shimaa64.efi"; +constexpr std::string_view DEFAULT_GRUB_EFI_REGEX_PATH = "/boot/efi/EFI/{}/grubaa64.efi"; +constexpr std::string_view DEFAULT_GRUB_CFG_REGEX_PATH = "/boot/efi/EFI/{}/grub.cfg"; +constexpr std::string_view DEFAULT_BOOT_PATH = "/boot"; +constexpr std::string_view DEFAULT_INITRD_PREFIX = "initrd"; +constexpr std::string_view DEFAULT_LINUZ_PREFIX = "linux"; +constexpr char PATH_SEPARATOR = '/'; +constexpr std::string_view BACKEND_VALUE = "direct"; + +inline ForeignMounterRc ParseRc(DllibRc rc) +{ + switch (rc) { + case DllibRc::OK: + return ForeignMounterRc::OK; + default: + return ForeignMounterRc::ERROR; + } +} + +std::string LinuxDistroToString(LinuxDistro distro) +{ + switch (distro) { + case LinuxDistro::OPENEULER: + return "openEuler"; + case LinuxDistro::CENTOS: + return "centos"; + case LinuxDistro::UBUNTU: + return "ubuntu"; + case LinuxDistro::DEBIAN: + return "debian"; + case LinuxDistro::FEDORA: + return "fedora"; + default: + return "unknown"; + } +} + +size_t CountStrings(char **strs) +{ + size_t c = 0; + if (strs != nullptr) { + while (strs[c] != nullptr) { + c++; + } + } + return c; +} + +void GuestfsFreeStringList(char **strs) +{ + if (strs == nullptr) { + return; + } + for (size_t i = 0; strs[i] != nullptr; ++i) { + free(strs[i]); + } + free(strs); +} + +VerifyConfig::VerifyConfig(const std::string &guestName, const std::string &diskPath, const std::string &loaderPath, + const LinuxDistro distro) + : guestName_(guestName), diskPath_(diskPath), loaderPath_(loaderPath), linuxDistro_(distro) +{} + +std::string VerifyConfig::GetGuestName() +{ + return guestName_; +} + +std::string VerifyConfig::GetDiskPath() +{ + return diskPath_; +} + +std::string VerifyConfig::GetLoaderPath() +{ + return loaderPath_; +} + + +std::string VerifyConfig::GetShimPath() +{ + if (shimPath_.empty()) { + shimPath_ = fmt::format(DEFAULT_SHIM_EFI_REGEX_PATH, LinuxDistroToString(linuxDistro_)); + } + return shimPath_; +} + +std::string VerifyConfig::GetGrubPath() +{ + if (grubPath_.empty()) { + grubPath_ = fmt::format(DEFAULT_GRUB_EFI_REGEX_PATH, LinuxDistroToString(linuxDistro_)); + } + return grubPath_; +} + +std::string VerifyConfig::GetGrubCfgPath() +{ + if (grubCfgPath_.empty()) { + grubCfgPath_ = fmt::format(DEFAULT_GRUB_CFG_REGEX_PATH, LinuxDistroToString(linuxDistro_)); + } + return grubCfgPath_; +} + +std::string VerifyConfig::GetInitrdPath() +{ + return initrdPath_; +} + +std::string VerifyConfig::GetLinuzPath() +{ + return linuzPath_; +} + +void VerifyConfig::ParseGrubCfgContent(const std::string &content) +{ + std::istringstream iss(content); + std::string line; + bool findInitrd = false; + bool findLinuz = false; + while (std::getline(iss, line)) { + line = StrTrimWhitespace(line); + if (line.empty()) { + continue; + } + // find line which starts woth "initrd" or "linux" + if (StrStartsWith(line, DEFAULT_INITRD_PREFIX)) { + initrdPath_ = ParseGrubCfgLine(line); + if (initrdPath_.empty()) { + VIRTRUST_LOG_ERROR("|ParseGrubCfgContent|END|||Get initrd path from grub.cfg failed."); + return; + } + findInitrd = true; + } else if (StrStartsWith(line, DEFAULT_LINUZ_PREFIX)) { + linuzPath_ = ParseGrubCfgLine(line); + if (linuzPath_.empty()) { + VIRTRUST_LOG_ERROR("|ParseGrubCfgContent|END|||Get linuz path from grub.cfg failed."); + return; + } + findLinuz = true; + } + // found all + if (findInitrd || findLinuz) { + return; + } + } +} + +std::string VerifyConfig::ParseGrubCfgLine(const std::string &line) +{ + constexpr int lineSplitLimit = 2; + + auto parts = StrSplit(line); + // if there are fewer than two substrings + if (parts.size() < lineSplitLimit) { + return ""; + } + // the second substring is file name or path + std::string filename = parts[1]; + + // NOTE by cjm. We should check if the path is absolute + // prefix already exists + if (StrStartsWith(filename, DEFAULT_BOOT_PATH)) { + return filename; + } + // add prefix + return fmt::format("{}/{}", DEFAULT_BOOT_PATH, StrTrim(filename, PATH_SEPARATOR)); +} + +ForeignMounterRc ForeignMounter::TryInit() +{ + if (libguestfs_.CheckOk() != DllibRc::OK) { + return ParseRc(libguestfs_.Reload()); + } + + if (handle_ == nullptr) { + handle_ = libguestfs_.guestfs_create(); + } + + if (handle_ == nullptr) { + VIRTRUST_LOG_ERROR("|TryInit|END|returnF||Failed to create the guestfs handle."); + return ForeignMounterRc::ERROR; + } + return ForeignMounterRc::OK; +} + +ForeignMounterRc ForeignMounter::Mount(std::string_view imgPath, size_t osIndex) +{ + // Check whether our dllib has been successfully loaded + if (!CheckOk()) { + return ForeignMounterRc::ERROR; + } + + auto res = libguestfs_.guestfs_set_backend(handle_, BACKEND_VALUE.data()); + if (res != -1) { + VIRTRUST_LOG_ERROR("|Mount|END|returnF||Guestfs set backend failed."); + return ForeignMounterRc::ERROR; + } + + struct guestfs_add_drive_opts_argv optargs = { + .bitmask = GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK | GUESTFS_ADD_DRIVE_OPTS_CACHEMODE_BITMASK, + .format = "qcow2", + .cachemode = "unsafe" // quick but unsafe + }; + // Load qcow2 format image from imgPath + // see: https://gitee.com/openeule/qemu/issues/IADWBA + res = libguestfs_.guestfs_add_drive_opts_argv(handle_, imgPath.data(), optargs); + if (res == -1) { + VIRTRUST_LOG_ERROR("|Mount|END|returnF||Guestfs add drive opts failed."); + return ForeignMounterRc::ERROR; + } + + res = libguestfs_.guestfs_launch(handle_); + if (res == -1) { + VIRTRUST_LOG_ERROR("|Mount|END|returnF||Guestfs launch failed."); + return ForeignMounterRc::ERROR; + } + + char **roots = libguestfs_.guestfs_inspect_os(handle_); + if (roots == nullptr) { + VIRTRUST_LOG_ERROR("|Mount|END|returnF||No operating system found in image."); + return ForeignMounterRc::ERROR; + } + + size_t osCnt = CountStrings(roots); + if (osIndex >= osCnt) { + VIRTRUST_LOG_ERROR("|Mount|END|returnF||There are {} os in image, index out of range: {}.", osCnt, osIndex); + return ForeignMounterRc::ERROR; + } + + char *root = roots[osIndex]; + ForeignMounterRc rc = MountFileSystems(root); + GuestfsFreeStringList(roots); + + if (rc == ForeignMounterRc::OK) { + isMount_ = true; + } + return rc; +} + +ForeignMounterRc ForeignMounter::MountFileSystems(const std::string &root) +{ + // collect mountpoints and devices + char **mountpoints = libguestfs_.guestfs_inspect_get_mountpoints(handle_, root.c_str()); + if (mountpoints == nullptr) { + VIRTRUST_LOG_ERROR("|MountFileSystems|END|returnF||Get mountpoints failed."); + return ForeignMounterRc::ERROR; + } + std::vector mps; + constexpr int stepLen = 2; + for (int i =0; mountpoints[i] != nullptr && mountpoints[i + 1] != nullptr; i += stepLen) { + mps.push_back(MounterInfo{mountpoints[i], mountpoints[i + 1], StrCountChar(mountpoints[i], PATH_SEPARATOR)}); + } + + // sort by derectory level in ascending + std::sort(mps.begin(), mps.end(), [](auto &a, auto &b) { + return a.dirLevel != b.dirLevel ? a.dirLevel < b.dirLevel : a.mpt.size() < b.mpt.size(); + }); + + // mount all file system + for (auto &mp : mps) { + auto &mountpoint = mp.mpt; + auto &device = mp.device; + // mount device to mountpoint + int ret = libguestfs_.guestfs_mount_ro(handle_, device.c_str(), mountpoint.c_str()); + if (ret == -1) { + VIRTRUST_LOG_ERROR("|MountFileSystems|END|returnF||Mount {} to {} failed.", device, mountpoint); + return ForeignMounterRc::ERROR; + } + } + + GuestfsFreeStringList(mountpoints); + return ForeignMounterRc::OK; +} + +ForeignMounterRc ForeignMounter::ReadFile(std::string_view filePath, std::string &fileContent) +{ + if (!isMount_) { + VIRTRUST_LOG_ERROR("|ReadFile|END|||The image has not been loaded."); + return ForeignMounterRc::ERROR; + } + + // check file whether exist in image + int exists = libguestfs_.guestfs_exists(handle_, filePath.data()); + if (exists == -1) { + VIRTRUST_LOG_ERROR("|ReadFile|END||file path is: {}|File not exist in image.", filePath); + return ForeignMounterRc::ERROR; + } + + // check whether is a file + int isFile = libguestfs_.guestfs_is_file(handle_, filePath.data()); + if (isFile == -1) { + VIRTRUST_LOG_ERROR("|ReadFile|END||file path is: {}|It is not a file.", filePath); + return ForeignMounterRc::ERROR; + } + + // read content + size_t size; + char *content = libguestfs_.guestfs_read_file(handle_, filePath.data(), &size); + if (content == nullptr) { + VIRTRUST_LOG_ERROR("|ReadFile|END||file path is: {}|Read this file failed.", filePath); + return ForeignMounterRc::ERROR; + } + + fileContent = std::string(content, size); + free(content); + return ForeignMounterRc::OK; +} + +ForeignMounterRc ForeignMounter::DoSm3OnVmFile(std::string_view filePath, std::vector &sm3Data) +{ + std::string fileContent; + ForeignMounterRc rc = ReadFile(filePath, fileContent); + if (rc == ForeignMounterRc::FILE_NOT_EXIST) { + return rc; + } + + if (rc != ForeignMounterRc::OK) { + VIRTRUST_LOG_ERROR("|DoSm3OnVmFile|END|returnF||Read file failed: {}.", filePath); + return ForeignMounterRc::ERROR; + } + if (virtrust::DoSm3(fileContent, sm3Data) != Sm3Rc::OK) { + return ForeignMounterRc::ERROR; + } + return ForeignMounterRc::OK; +} + +ForeignMounterRc ForeignMounter::EnableStrErrTrace() +{ + return libguestfs_.guestfs_set_trace(handle_, 1) == 0 ? ForeignMounterRc::OK : ForeignMounterRc::ERROR; +} + +ForeignMounterRc ForeignMounter::DisableStrErrTrace() +{ + return libguestfs_.guestfs_set_trace(handle_, 0) == 0 ? ForeignMounterRc::OK : ForeignMounterRc::ERROR; +} + +} // namespace virtrust diff --git a/virtrust/src/virtrust/utils/foreign_mounter.h b/virtrust/src/virtrust/utils/foreign_mounter.h new file mode 100644 index 0000000000000000000000000000000000000000..ef0295de4bef3f92d6c6eb10ffd6371f531b0b1b --- /dev/null +++ b/virtrust/src/virtrust/utils/foreign_mounter.h @@ -0,0 +1,128 @@ +#pragma once + +#include +#include +#include + +#include "virtrust/base/logger.h" +#include "virtrust/dllib/libguestfs.h" + +namespace virtrust { + +enum class LinuxDistro { + OPENEULER, + CENTOS, + UBUNTU, + DEBIAN, + FEDORA +}; + +class VerifyConfig { +public: + VerifyConfig() = default; + + VerifyConfig(const std::string &guestName, const std::string &diskPath, const std::string &loaderPath, + LinuxDistro distro = LinuxDistro::OPENEULER); + + std::string GetGuestName(); + std::string GetDiskPath(); + std::string GetLoaderPath(); + std::string GetShimPath(); + std::string GetGrubPath(); + std::string GetGrubCfgPath(); + std::string GetInitrdPath(); + std::string GetLinuzPath(); + + void ParseGrubCfgContent(const std::string &content); + +private: + std::string guestName_; + std::string diskPath_; + std::string loaderPath_; + std::string shimPath_; + std::string grubPath_; + std::string grubCfgPath_; + std::string initrdPath_; + std::string linuzPath_; + LinuxDistro linuxDistro_; + + std::string ParseGrubCfgLine(const std::string &line); +}; + +enum class ForeignMounterRc : uint32_t { + OK = 0, + ERROR = 1, + FILE_NOT_EXIST = 2, +}; + +struct MounterInfo { + std::string mpt; // mount point + std::string device; // mount device + size_t dirLevel; +}; + +class ForeignMounter { +public: + ForeignMounter() + { + // try to init handle, discarding the return process + TryInit(); + }; + + ~ForeignMounter() noexcept + { + Unmount(); + if (handle_ != nullptr) { + libguestfs_.guestfs_close(handle_); + handle_ = nullptr; + } + }; + + ForeignMounter(const ForeignMounter &) = delete; + ForeignMounter &operator=(const ForeignMounter &) = delete; + ForeignMounter(ForeignMounter &&) = delete; + ForeignMounter &operator=(ForeignMounter &&) = delete; + + // low-level api, try to initialize handle + ForeignMounterRc TryInit(); + + // Mount virtual machine img path to filesystem + ForeignMounterRc Mount(std::string_view imgPath, size_t osIndex = 0); + + // Read file content to string + ForeignMounterRc ReadFile(std::string_view filePath, std::string &content); + + // Get file sm3 + ForeignMounterRc DoSm3OnVmFile(std::string_view filePath, std::vector &sm3Data); + + // Unmount + ForeignMounterRc Unmount() noexcept; + + // Check if everything is okay + bool CheckOk() + { + return handle_ != nullptr && libguestfs_.CheckOk() == DllibRc::OK; + } + + bool CheckMount() const + { + return isMount_; + } + + // Enable trace from libguestfs + ForeignMounterRc EnableStrErrTrace(); + + // Disable trace from libguestfs + ForeignMounterRc DisableStrErrTrace(); + + + +private: + bool isMount_ = false; + guestfs_h *handle_ = nullptr; + Libguestfs &libguestfs_ = Libguestfs::GetInstance(); + + ForeignMounterRc MountFileSystems(const std::string &root); +}; + +} // namespace virtrust diff --git a/virtrust/src/virtrust/utils/hello.cpp b/virtrust/src/virtrust/utils/hello.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ef42b9d33bd708054f6bcd20e735bfd31a35db3 --- /dev/null +++ b/virtrust/src/virtrust/utils/hello.cpp @@ -0,0 +1,14 @@ +#include "file_io.h" +#include "migrate_helper.h" +#include +#include +#include +#include +#include +#include "virtrust/utils/smart_deleter.h" + + +void func() +{ + +} \ No newline at end of file diff --git a/virtrust/src/virtrust/utils/migrate_helper.cpp b/virtrust/src/virtrust/utils/migrate_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6c0d781d4141161f0fdfd3570428d72718656dc4 --- /dev/null +++ b/virtrust/src/virtrust/utils/migrate_helper.cpp @@ -0,0 +1,3 @@ +#include "virtrust/utils/migrate_helper.h" + +namespace virtrust {} // namespace virtrust \ No newline at end of file diff --git a/virtrust/src/virtrust/utils/migrate_helper.h b/virtrust/src/virtrust/utils/migrate_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..1bf6a86964fa1eea61c3bc211bd75f3acaf8ca85 --- /dev/null +++ b/virtrust/src/virtrust/utils/migrate_helper.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +#include "virtrust/api/context.h" + +namespace virtrust { + +class MigrateHelper { +public: + explicit MigrateHelper() = default; + ~MigrateHelper() = default; + + explicit MigrateHelper(std::string destUri) : destUri_(destUri) + {} + + void SetDstUri(const std::string &destUri) + { + destUri_ = destUri; + } + + std::string GetDestUri() + { + return destUri_; + } + + // step 1: get report that the hardware is okay + void GetReport(); + + // step 2: get the private shared key pair + void GetKet(); + + // step 3: key exchange to get a shared key + void ExchangeKey(); + + +private: + ConnCtx conn_; + std::string destUri_; +}; + +} // namespace virtrust \ No newline at end of file diff --git a/virtrust/src/virtrust/utils/smart_deleter.h b/virtrust/src/virtrust/utils/smart_deleter.h new file mode 100644 index 0000000000000000000000000000000000000000..fefb3670272f116dd57b2e704135f9311a060f7a --- /dev/null +++ b/virtrust/src/virtrust/utils/smart_deleter.h @@ -0,0 +1,49 @@ +#pragma once + +namespace virtrust { + +template +class SmartDeleter { +public: + SmartDeleter() + { + core_ = nullptr; + } + + explicit SmartDeleter(T *ptr) + { + core_ = ptr; + } + + T *Get() const + { + return core_; + } + +protected: + T *core_ = nullptr; +}; + +#define VIRTRUST_MAKE_DESTRUCTOR(NAME, DELETER) \ + ~NAME() \ + { \ + if (this->core_ != nullptr) { \ + DELETER(this->core_); \ + this->core_ = nullptr; \ + } \ + } + +#define CONCAT_IMPL(x, y) x##y + +#define CONCAT(x, y) CONCAT_IMPL(x, y) + +#define VIRTRUST_MAKE_SMART(T, DELETER) \ + class CONCAT(Smart, T) : public SmartDeleter { \ + public: \ + using SmartDeleter::SmartDeleter; \ + CONCAT(Smart, T)(const CONCAT(Smart, T) &) = delete; \ + CONCAT(Smart, T) &operator=(const CONCAT(Smart, T) &) = delete; \ + VIRTRUST_MAKE_DESTRUCTOR(CONCAT(Smart, T), DELETER) \ + } + +} // namespace virtrust diff --git a/virtrust/src/virtrust/utils/virt_xml_parser.cpp b/virtrust/src/virtrust/utils/virt_xml_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..38bf3db91f0dbe6813634a8114941fdada79fefb --- /dev/null +++ b/virtrust/src/virtrust/utils/virt_xml_parser.cpp @@ -0,0 +1,164 @@ +#include "virt_xml_parser.h" + +#include + +namespace virtrust { + +namespace { +constexpr std::string_view VIRT_XML_DISK_PATH = "/domain/devices/disk/source"; +const xmlChar VIRT_XML_FILE_PROP[] = "file"; +const std::string_view VIRT_XML_LOADER_PATH = "/domain/os/loader"; +const std::string_view VIRT_XML_NAME_PATH = "/domain/name"; +const std::string_view PATH_SEPARATOR = "/"; +} // namespace + +void VirtXmlParser::SearchCurrLevel(std::vector &currLevel, std::vector &nextLevel, + const std::string &nodeName) +{ + for (xmlNodePtr parent : currLevel) { + for (xmlNodePtr node = parent->children; node != nullptr; node = node->next) { + bool pathMatch = node->type == XML_ELEMENT_NODE && nodeName == MakeString(node->name); + if (pathMatch) { + nextLevel.push_back(node); + } + } + } +} + +std::vector VirtXmlParser::FindNodesByPath(std::string_view absPath) +{ + std::vector ret; + auto root = libxml2_.xmlDocGetRootElement(doc_); + if (root == nullptr) { + VIRTRUST_LOG_ERROR("|FindNodesByPath|END|||Get xml root node failed."); + return ret; + } + if (absPath.empty()) { + VIRTRUST_LOG_ERROR("|FindNodesByPath|END|||Input path is empty."); + return ret; + } + if (absPath[0] != '/') { + VIRTRUST_LOG_ERROR("|FindNodesByPath|END||file path : {}|It's not a absolutely path.", absPath); + return ret; + } + + std::vector parts = StrSplit(StrTrim(std::string(absPath), PATH_SEPARATOR[0]), PATH_SEPARATOR); + + std::vector currLevel = {root}; + if (parts[0] != MakeString(root->name)) { + VIRTRUST_LOG_ERROR("|FindNodesByPath|END||file path: {}|The name of root node in xml file is wrong.", absPath); + return ret; + } + + for (size_t i = 1; i < parts.size(); ++i) { + const auto &nodeName = parts[i]; + std::vector nextLevel; + SearchCurrLevel(currLevel, nextLevel, nodeName); + if (nextLevel.empty()) { // No matchs found + return ret; + } + currLevel = std::move(nextLevel); + } + return currLevel; +} + +bool VirtXmlParser::LoadFile(std::string_view filename) +{ + if (filename.empty()) { + VIRTRUST_LOG_ERROR("|LoadFile|END|returnF||File name is empty."); + return false; + } + + if (!std::filesystem::exists(filename) || !std::filesystem::is_regular_file(filename)) { + VIRTRUST_LOG_ERROR("|LoadFile|END|returnF||The file does not exist: {}.", filename); + return false; + } + + // the reamining document tree if the file was wellformed, nullptr otherwise + if (doc_ != nullptr) { + VIRTRUST_LOG_WARN("|LoadFile|END|||Already load file, will load new one."); + libxml2_.xmlFreeDoc(doc_); + doc_ = nullptr; + } + doc_ = libxml2_.xmlParseFile(filename.data()); + return doc_ != nullptr; +} + +std::string VirtXmlParser::GetDiskPath() +{ + auto nodes = FindNodesByPath(VIRT_XML_DISK_PATH); + if (nodes.empty()) { + VIRTRUST_LOG_ERROR("|GetDiskPath|END||node path: {}|Get disk path from xml failed.", VIRT_XML_DISK_PATH); + return ""; + } + + if (nodes.size() != 1) { + VIRTRUST_LOG_ERROR("|GetDiskPath|END|||The node of disk path in xml is not only."); + return ""; + } + + xmlNodePtr node = nodes[0]; + xmlChar *diskPath = libxml2_.xmlGetProp(node, VIRT_XML_FILE_PROP); + if (diskPath == nullptr) { + VIRTRUST_LOG_ERROR("|GetDiskPath|END||node path: {}|Target node does not have property: {}.", VIRT_XML_DISK_PATH, + reinterpret_cast(VIRT_XML_FILE_PROP)); + return ""; + } + + std::string ret = MakeString(diskPath); + free(diskPath); + return ret; +} + +std::string VirtXmlParser::GetLoaderPath() +{ + auto nodes = FindNodesByPath(VIRT_XML_LOADER_PATH); + if (nodes.empty()) { + VIRTRUST_LOG_ERROR("|GetLoaderPath|END|||Get loader path from xml failed: {}.", VIRT_XML_LOADER_PATH); + return ""; + } + + if (nodes.size() != 1) { + VIRTRUST_LOG_ERROR("|GetLoaderPath|END|||The node of loader path in xml is not only."); + return ""; + } + + xmlNodePtr node = nodes[0]; + if (node->children == nullptr || node->children->content == nullptr) { + VIRTRUST_LOG_ERROR("|GetLoaderPath|END||node path: {}|Target node does not have any child nodes.", + VIRT_XML_LOADER_PATH); + return ""; + } + return MakeString(node->children->content); +} + +std::string VirtXmlParser::GetVmName() +{ + auto nodes = FindNodesByPath(VIRT_XML_NAME_PATH); + if (nodes.empty()) { + VIRTRUST_LOG_ERROR("|GetVmName|END|||Get VM name from xml failed."); + return ""; + } + + if (nodes.size() != 1) { + VIRTRUST_LOG_ERROR("|GetVmName|END|||The node of VM name in xml is not only."); + return ""; + } + + xmlNodePtr node = nodes[0]; + if (node->children == nullptr || node->children->content == nullptr) { + VIRTRUST_LOG_ERROR("|GetVmName|END||node path: {}|Target node does not have any child nodes.", + VIRT_XML_NAME_PATH); + return ""; + } + return MakeString(node->children->content); +} + +VerifyConfig VirtXmlParser::Parse(const std::string &filePath) +{ + LoadFile(filePath); + VerifyConfig config(GetVmName(), GetDiskPath(), GetLoaderPath()); + return config; +} + +} // namespace virtrust diff --git a/virtrust/src/virtrust/utils/virt_xml_parser.h b/virtrust/src/virtrust/utils/virt_xml_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..84131cd547d73ff2f6bcb715b75aa886c55a856c --- /dev/null +++ b/virtrust/src/virtrust/utils/virt_xml_parser.h @@ -0,0 +1,45 @@ +#pragma once + +#include + +#include "virtrust/base/logger.h" +#include "virtrust/dllib/libxml2.h" +#include "virtrust/utils/foreign_mounter.h" + +namespace virtrust { + +using NodeConditionMatchFunc = std::function; + +class VirtXmlParser { +public: + VirtXmlParser() = default; + + ~VirtXmlParser() + { + if (doc_ != nullptr) { + libxml2_.xmlFreeDoc(doc_); + } + } + + std::vector FindNodesByPath(std::string_view absPath); + + // Load the VM xml file, the function reloads the file each time it is called. + bool LoadFile(std::string_view filename); + + std::string GetVmName(); + + std::string GetDiskPath(); + + std::string GetLoaderPath(); + + VerifyConfig Parse(const std::string &filePath); + +private: + Libxml2 &libxml2_ = Libxml2::GetInstance(); + xmlDocPtr doc_ = nullptr; + + void SearchCurrLevel(std::vector &currLevel, std::vector &nextLevel, + const std::string &nodeName); +}; + +} // namespace virtrust \ No newline at end of file