diff options
Diffstat (limited to 'src/core/ppp/nm-pppd-compat.c')
| -rw-r--r-- | src/core/ppp/nm-pppd-compat.c | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/src/core/ppp/nm-pppd-compat.c b/src/core/ppp/nm-pppd-compat.c new file mode 100644 index 00000000..f7940c55 --- /dev/null +++ b/src/core/ppp/nm-pppd-compat.c @@ -0,0 +1,308 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023 Eivind Næss, eivnaes@yahoo.com + */ + +/*****************************************************************************/ + +/* PPP headers define some symbols as we do. We need to be careful to handle + * the conflict, and include stuff in a certain order. */ + +#include <config.h> +#define ___CONFIG_H__ + +/*****************************************************************************/ + +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +_Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wstrict-prototypes\"") +#define _NM_PRAGMA_WARNING_REENABLE _Pragma("GCC diagnostic pop") +#elif defined(__clang__) +_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunknown-warning-option\"") + _Pragma("clang diagnostic ignored \"-Wstrict-prototypes\"") +#define _NM_PRAGMA_WARNING_REENABLE _Pragma("clang diagnostic pop") +#else +#define _NM_PRAGMA_WARNING_REENABLE +#endif + +/*****************************************************************************/ + +#define INET6 1 + +#include <pppd/pppd.h> + +#ifdef DATE +/* Before ppp 2.5, pppd/patchlevel.h defined "DATE". Use that for detection. */ +#define PPP_VERSION_2_5_OR_NEWER 0 +#else +#define PPP_VERSION_2_5_OR_NEWER 1 +#endif + +#include <pppd/eui64.h> +#include <pppd/fsm.h> +#include <pppd/ipcp.h> +#include <pppd/ipv6cp.h> +#include <pppd/upap.h> + +#if PPP_VERSION_2_5_OR_NEWER +#include <pppd/chap.h> +#else +#include <pppd/chap-new.h> +#include <pppd/chap_ms.h> +#endif + + char pppd_version[] = ( +#if PPP_VERSION_2_5_OR_NEWER + PPPD_VERSION +#else + VERSION +#endif + ); + +#undef VERSION + +_NM_PRAGMA_WARNING_REENABLE; + +/*****************************************************************************/ + +#include "libnm-glib-aux/nm-default-glib.h" + +#include "nm-pppd-compat.h" + +#include <net/if.h> +#include <dlfcn.h> + +#include "nm-ppp-status.h" + +/*****************************************************************************/ + +G_STATIC_ASSERT(PPP_VERSION_2_5_OR_NEWER == NM_PPP_VERSION_2_5_OR_NEWER); + +/*****************************************************************************/ + +G_STATIC_ASSERT((gint64) NM_PPP_STATUS_DEAD == PHASE_DEAD); +G_STATIC_ASSERT((gint64) NM_PPP_STATUS_INITIALIZE == PHASE_INITIALIZE); +G_STATIC_ASSERT((gint64) NM_PPP_STATUS_SERIALCONN == PHASE_SERIALCONN); +G_STATIC_ASSERT((gint64) NM_PPP_STATUS_DORMANT == PHASE_DORMANT); +G_STATIC_ASSERT((gint64) NM_PPP_STATUS_ESTABLISH == PHASE_ESTABLISH); +G_STATIC_ASSERT((gint64) NM_PPP_STATUS_AUTHENTICATE == PHASE_AUTHENTICATE); +G_STATIC_ASSERT((gint64) NM_PPP_STATUS_CALLBACK == PHASE_CALLBACK); +G_STATIC_ASSERT((gint64) NM_PPP_STATUS_NETWORK == PHASE_NETWORK); +G_STATIC_ASSERT((gint64) NM_PPP_STATUS_RUNNING == PHASE_RUNNING); +G_STATIC_ASSERT((gint64) NM_PPP_STATUS_TERMINATE == PHASE_TERMINATE); +G_STATIC_ASSERT((gint64) NM_PPP_STATUS_DISCONNECT == PHASE_DISCONNECT); +G_STATIC_ASSERT((gint64) NM_PPP_STATUS_HOLDOFF == PHASE_HOLDOFF); +G_STATIC_ASSERT((gint64) NM_PPP_STATUS_MASTER == PHASE_MASTER); + +G_STATIC_ASSERT(NM_PPPD_COMPAT_MAXNAMELEN == MAXNAMELEN); +G_STATIC_ASSERT(NM_PPPD_COMPAT_MAXSECRETLEN == MAXSECRETLEN); + +/*****************************************************************************/ + +int +nm_pppd_compat_get_ifunit(void) +{ + int i; + +#if PPP_VERSION_2_5_OR_NEWER + i = ppp_ifunit(); +#else + i = ifunit; +#endif + + return i; +} + +const char * +nm_pppd_compat_get_ifname(void) +{ + const char *s; + +#if PPP_VERSION_2_5_OR_NEWER + s = ppp_ifname(); +#else + s = ifname; +#endif + + nm_assert(s); + nm_assert(strlen(s) < IFNAMSIZ); + return s; +} + +void +nm_pppd_compat_set_ifname(const char *arg_ifname) +{ + nm_assert(arg_ifname); + nm_assert(strlen(arg_ifname) < IFNAMSIZ); + +#if PPP_VERSION_2_5_OR_NEWER + ppp_set_ifname(arg_ifname); +#else + g_strlcpy(ifname, arg_ifname, IFNAMSIZ); +#endif +} + +const char * +nm_pppd_compat_get_ipparam(void) +{ + const char *s; + +#if PPP_VERSION_2_5_OR_NEWER + s = ppp_ipparam(); +#else + s = ipparam; +#endif + + return s; +} + +void +nm_pppd_compat_get_ipcp_options(NMPppdCompatIPCPOptions *out_got, NMPppdCompatIPCPOptions *out_his) +{ + const ipcp_options *const got = &ipcp_gotoptions[0]; + const ipcp_options *const his = &ipcp_hisoptions[0]; + + nm_assert(out_got); + nm_assert(out_his); + + *out_got = (NMPppdCompatIPCPOptions){ + .ouraddr = got->ouraddr, + .hisaddr = got->hisaddr, + .dnsaddr = {got->dnsaddr[0], got->dnsaddr[1]}, + .winsaddr = {got->winsaddr[0], got->winsaddr[1]}, + }; + + *out_his = (NMPppdCompatIPCPOptions){ + .ouraddr = his->ouraddr, + .hisaddr = his->hisaddr, + .dnsaddr = {his->dnsaddr[0], his->dnsaddr[1]}, + .winsaddr = {his->winsaddr[0], his->winsaddr[1]}, + }; +} + +void +nm_pppd_compat_get_ipv6cp_options(NMPppdCompatIPV6CPOptions *out_got, + NMPppdCompatIPV6CPOptions *out_his) +{ + const ipv6cp_options *const his = &ipv6cp_hisoptions[0]; + const ipv6cp_options *const got = &ipv6cp_gotoptions[0]; + + G_STATIC_ASSERT(sizeof(guint64) == sizeof(eui64_t)); + + nm_assert(out_got); + nm_assert(out_his); + + *out_got = (NMPppdCompatIPV6CPOptions){}; + memcpy(&out_got->ourid, &got->ourid, sizeof(guint64)); + memcpy(&out_got->hisid, &got->hisid, sizeof(guint64)); + + *out_his = (NMPppdCompatIPV6CPOptions){}; + memcpy(&out_his->ourid, &his->ourid, sizeof(guint64)); + memcpy(&out_his->hisid, &his->hisid, sizeof(guint64)); +} + +void +nm_pppd_compat_set_chap_passwd_hook(int (*hook)(char *user, char *password)) +{ + chap_passwd_hook = hook; +} + +void +nm_pppd_compat_set_chap_check_hook(int (*hook)(void)) +{ + chap_check_hook = hook; +} + +void +nm_pppd_compat_set_pap_passwd_hook(int (*hook)(char *user, char *passwd)) +{ + pap_passwd_hook = hook; +} + +void +nm_pppd_compat_set_pap_check_hook(int (*hook)(void)) +{ + pap_check_hook = hook; +} + +gboolean +nm_pppd_compat_add_notify(NMPppdCompatNotifyT type, void (*func)(void *ctx, int arg), void *ctx) +{ + nm_assert(NM_IN_SET(type, + NM_PPPD_COMPAT_NF_PID_CHANGE, + NM_PPPD_COMPAT_NF_PHASE_CHANGE, + NM_PPPD_COMPAT_NF_EXIT, + NM_PPPD_COMPAT_NF_SIGNALED, + NM_PPPD_COMPAT_NF_IP_UP, + NM_PPPD_COMPAT_NF_IP_DOWN, + NM_PPPD_COMPAT_NF_IPV6_UP, + NM_PPPD_COMPAT_NF_IPV6_DOWN, + NM_PPPD_COMPAT_NF_AUTH_UP, + NM_PPPD_COMPAT_NF_LINK_DOWN, + NM_PPPD_COMPAT_NF_FORK)); + nm_assert(func); + +#if PPP_VERSION_2_5_OR_NEWER + { + G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_PID_CHANGE == NF_PID_CHANGE); + G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_PHASE_CHANGE == NF_PHASE_CHANGE); + G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_EXIT == NF_EXIT); + G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_SIGNALED == NF_SIGNALED); + G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_IP_UP == NF_IP_UP); + G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_IP_DOWN == NF_IP_DOWN); + G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_IPV6_UP == NF_IPV6_UP); + G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_IPV6_DOWN == NF_IPV6_DOWN); + G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_AUTH_UP == NF_AUTH_UP); + G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_LINK_DOWN == NF_LINK_DOWN); + G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_FORK == NF_FORK); + + ppp_add_notify((gint64) type, func, ctx); + return TRUE; + } +#else + { + static struct notifier **list[] = { + [NM_PPPD_COMPAT_NF_PID_CHANGE] = &pidchange, + [NM_PPPD_COMPAT_NF_PHASE_CHANGE] = &phasechange, + [NM_PPPD_COMPAT_NF_EXIT] = &exitnotify, + [NM_PPPD_COMPAT_NF_SIGNALED] = &sigreceived, + [NM_PPPD_COMPAT_NF_IP_UP] = &ip_up_notifier, + [NM_PPPD_COMPAT_NF_IP_DOWN] = &ip_down_notifier, + [NM_PPPD_COMPAT_NF_IPV6_UP] = NULL /* ipv6_up_notifier */, + [NM_PPPD_COMPAT_NF_IPV6_DOWN] = NULL /* ipv6_down_notifier */, + [NM_PPPD_COMPAT_NF_AUTH_UP] = &auth_up_notifier, + [NM_PPPD_COMPAT_NF_LINK_DOWN] = &link_down_notifier, + [NM_PPPD_COMPAT_NF_FORK] = &fork_notifier, + }; + struct notifier **notifier; + + nm_assert(_NM_INT_NOT_NEGATIVE(type) && type < G_N_ELEMENTS(list)); + + if (NM_IN_SET(type, NM_PPPD_COMPAT_NF_IPV6_UP, NM_PPPD_COMPAT_NF_IPV6_DOWN)) { + static gsize load_once = 0; + + /* pppd might be build without IPv6 support. Load the symbols dynamically. */ + if (g_once_init_enter(&load_once)) { + void *handle; + + handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); + if (handle) { + list[NM_PPPD_COMPAT_NF_IPV6_UP] = dlsym(handle, "ipv6_up_notifier"); + list[NM_PPPD_COMPAT_NF_IPV6_DOWN] = dlsym(handle, "ipv6_down_notifier"); + dlclose(handle); + } + g_once_init_leave(&load_once, 1); + } + + notifier = list[type]; + } else { + notifier = list[type]; + nm_assert(notifier); + } + + if (notifier) + add_notifier(notifier, func, ctx); + + return !!notifier; + } +#endif +} |