Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,15 @@ AX_CHECK_ATM
AX_CHECK_PAM(AC_DEFINE([PPP_WITH_PAM], 1, [Support for Pluggable Authentication Modules]))
AM_CONDITIONAL(PPP_WITH_PAM, test "x${with_pam}" = "xyes")

#
# With libcap support for capability-based privilege management (Linux only, Solaris uses geteuid check)
AM_COND_IF([LINUX], [
AX_CHECK_CAP(AC_DEFINE([USE_CAP], 1, [Use libcap for capability checking]))
AM_CONDITIONAL(WITH_LIBCAP, test "x${with_libcap}" = "xyes")
], [
AM_CONDITIONAL(WITH_LIBCAP, false)
])

#
# With libpcap support, activate pppd on network activity
AX_CHECK_PCAP
Expand Down Expand Up @@ -347,6 +356,7 @@ $PACKAGE_NAME version $PACKAGE_VERSION
System CA Path ......: ${SYSTEM_CA_PATH:-not set}
With OpenSSL.........: ${with_openssl:-yes}
With libatm..........: ${with_atm:-no}
With libcap..........: ${with_libcap:-no}
With libpam..........: ${with_pam:-no}
With libpcap.........: ${with_pcap:-no}
With libsrp..........: ${with_srp:-no}
Expand Down
89 changes: 89 additions & 0 deletions m4/ax_check_cap.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# SYNOPSIS
#
# AX_CHECK_CAP([action-if-found[, action-if-not-found]])
#
# DESCRIPTION
#
# Look for libcap in a number of default locations, or in a provided location
# (via --with-libcap=). Sets
# CAP_CFLAGS
# CAP_LDFLAGS
# CAP_LIBS
#
# and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately
#
# LICENSE
#
# Copyright (c) 2025 PPP Project
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.

#serial 1

AC_DEFUN([AX_CHECK_CAP], [
AC_ARG_WITH([libcap],
[AS_HELP_STRING([--with-libcap=yes|no|DIR],
[With libcap (capabilities) support for fine-grained privilege management])])

AS_CASE(["$with_libcap"],
[ye|y], [with_libcap=yes],
[n], [with_libcap=no])

AS_IF([test "x$with_libcap" != "xno"], [
AS_CASE(["$with_libcap"],
[""|yes], [PKG_CHECK_MODULES([CAP], [libcap], [capdirs=],
[capdirs="/usr/local /usr/lib /usr"])],
[capdirs="$with_libcap"])

AS_IF([test -n "$capdirs"], [
CAP_LIBS="-lcap"
for capdir in $capdirs; do
AC_MSG_CHECKING([for sys/capability.h in $capdir])
if test -f "$capdir/include/sys/capability.h"; then
CAP_CFLAGS="-I$capdir/include"
CAP_LDFLAGS="-L$capdir/lib"
AC_MSG_RESULT([yes])
break
else
AC_MSG_RESULT([no])
fi
done
])

# try the preprocessor and linker with our new flags,
# being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS

AC_MSG_CHECKING([if compiling and linking against libcap works])

save_LIBS="$LIBS"
save_LDFLAGS="$LDFLAGS"
save_CPPFLAGS="$CPPFLAGS"
LDFLAGS="$LDFLAGS $CAP_LDFLAGS"
LIBS="$CAP_LIBS $LIBS"
CPPFLAGS="$CAP_CFLAGS $CPPFLAGS"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[#include <sys/capability.h>],
[cap_t cap = cap_get_pid(0);])],
[
AC_MSG_RESULT([yes])
with_libcap=yes
$1
], [
AC_MSG_RESULT([no])
with_libcap="no"
$2
])
CPPFLAGS="$save_CPPFLAGS"
LDFLAGS="$save_LDFLAGS"
LIBS="$save_LIBS"

AC_SUBST([CAP_CFLAGS])
AC_SUBST([CAP_LIBS])
AC_SUBST([CAP_LDFLAGS])
])
AM_CONDITIONAL(WITH_LIBCAP, test "x${with_libcap}" = "xyes")
])
6 changes: 6 additions & 0 deletions pppd/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,12 @@ pppd_CPPFLAGS += $(SYSTEMD_CFLAGS)
pppd_LIBS += $(SYSTEMD_LIBS)
endif

if WITH_LIBCAP
pppd_CPPFLAGS += $(CAP_CFLAGS)
pppd_LIBS += $(CAP_LIBS)
pppd_LDFLAGS += $(CAP_LDFLAGS)
endif

if WITH_SRP
srp_entry_SOURCES = srp-entry.c
srp_entry_CPPFLAGS = $(OPENSSL_INCLUDES) $(SRP_CFLAGS)
Expand Down
11 changes: 7 additions & 4 deletions pppd/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,11 +449,14 @@ main(int argc, char *argv[])
}

/*
* Check that we are running as root.
* Check that we are capable to admin the network.
*/
if (geteuid() != 0) {
ppp_option_error("must be root to run %s, since it is not setuid-root",
argv[0]);
if (!net_capable()) {
#ifdef USE_CAP
ppp_option_error("must have CAP_NET_ADMIN or root privilege to run %s", argv[0]);
#else
ppp_option_error("must be root to run %s, since it is not setuid-root", argv[0]);
#endif /* USE_CAP */
exit(EXIT_NOT_ROOT);
}

Expand Down
5 changes: 5 additions & 0 deletions pppd/pppd.h
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,11 @@ void ppp_script_setenv(char *, char *, int);
*/
void ppp_script_unsetenv(char *);

/*
* Test for network management capability
*/
int net_capable(void);

/*
* Test whether ppp kernel support exists
*/
Expand Down
46 changes: 46 additions & 0 deletions pppd/sys-linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@
#include <sys/locks.h>
#endif

#ifdef USE_CAP
#include <sys/types.h>
#include <sys/capability.h>
#endif /* USE_CAP */

/*
* Instead of system header file <termios.h> use local "termios_linux.h" header
* file as it provides additional support for arbitrary baud rates via BOTHER.
Expand Down Expand Up @@ -2842,6 +2847,47 @@ ppp_registered(void)
return ret;
}

/***********************************************************
*
* net_capable - check for any access to the net management
*/

int net_capable(void)
{
/*
* Check if we are running as root first, as this is the most common case.
*/
if (geteuid() == 0)
return 1;

#ifdef USE_CAP
/*
* If not root, check for CAP_NET_ADMIN capability.
*/
cap_t cap;
cap_flag_value_t cap_flag_value;
int ok = 0;

cap = cap_get_pid(getpid());
if (cap != NULL) {
if (cap_get_flag(cap, CAP_NET_ADMIN, CAP_EFFECTIVE, &cap_flag_value) == 0) {
if (cap_flag_value == CAP_SET) {
cap_free(cap);
return 1;
}
}
if (cap_get_flag(cap, CAP_NET_ADMIN, CAP_PERMITTED, &cap_flag_value) == 0) {
if (cap_flag_value == CAP_SET)
ok = 1;
}
cap_free(cap);
}
return ok;
#else
return 0;
#endif /* USE_CAP */
}

/********************************************************************
*
* ppp_check_kernel_support - check whether the system has any ppp interfaces
Expand Down
13 changes: 13 additions & 0 deletions pppd/sys-solaris.c
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,19 @@ sys_check_options(void)
return 1;
}

/***********************************************************
*
* net_capable - check for any access to the net management
*/

int net_capable(void)
{
/*
* On Solaris, always check that we are running as root.
*/
return (geteuid() == 0);
}

/*
* ppp_check_kernel_support - check whether the system has any ppp interfaces
*/
Expand Down