diff --git a/acinclude.m4 b/acinclude.m4 index 6376d47b..e790611d 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -149,6 +149,94 @@ else AC_MSG_ERROR([Cannot find a type with size of 64 bits]) fi]) +dnl +dnl Macro: unet_TLS +dnl +dnl Set unet_cv_with_tls and TLS_C to an available TLS implementation. +dnl +AC_DEFUN([unet_TLS], +[dnl Perform some preliminary checks for system TLS libraries. +AX_CHECK_OPENSSL(, [:]) +PKG_CHECK_MODULES([GNUTLS], [gnutls], , [:]) + +dnl --with-tls allows selection of the TLS library. +AC_MSG_CHECKING([for a TLS library]) +AC_ARG_WITH([tls], +[ --with-tls=library TLS library to use (none, openssl, gnutls, libtls)], +[unet_cv_with_tls=$with_tls], +[AC_CACHE_VAL(unet_cv_with_tls, +[unet_cv_with_tls=yes])]) +TLS_C="" + +dnl If --with-tls or --with-tls=yes, try to autodetect: OpenSSL first. +if test x"$unet_cv_with_tls" = xyes ; then + if test x"$OPENSSL_LIBS" != x ; then + unet_cv_with_tls=openssl + fi +fi +dnl Try gnutls next. +if test x"$unet_cv_with_tls" = xyes ; then + if test x"$GNUTLS_LIBS" != x ; then + unet_cv_with_tls=gnutls + fi +fi +dnl Try libtls next. +if test x"$unet_cv_with_tls" = xyes ; then + dnl Temporarily disable pkg-config to force fallback path + dnl PKG_CHECK_MODULES([LIBTLS], [libtls], [ + dnl unet_cv_with_tls=libtls + dnl ], [ + dnl Fallback for OpenBSD base (no .pc): header + symbol link test. + AC_CHECK_HEADER([tls.h], [ + AC_CHECK_LIB([tls], [tls_init], [ + unet_cv_with_tls=libtls + LIBTLS_LIBS="-ltls" + LIBTLS_CFLAGS="" + LIBTLS_LDFLAGS="" + ]) + ]) + dnl ]) +fi + +case x"$unet_cv_with_tls" in +xopenssl) + CFLAGS="$CFLAGS $OPENSSL_CFLAGS" + LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" + LIBS="$LIBS $OPENSSL_LIBS" + TLS_C="tls_openssl.c" + ;; +xgnutls) + CFLAGS="$CFLAGS $GNUTLS_CFLAGS" + LDFLAGS="$LDFLAGS $GNUTLS_LDFLAGS" + LIBS="$LIBS $GNUTLS_LIBS" + TLS_C="tls_gnutls.c" + ;; +xlibtls) + # Ensure LIBTLS_LIBS is set even when explicitly specified + if test x"$LIBTLS_LIBS" = x ; then + LIBTLS_LIBS="-ltls" + fi + CFLAGS="$CFLAGS $LIBTLS_CFLAGS" + LDFLAGS="$LDFLAGS $LIBTLS_LDFLAGS" + LIBS="$LIBS $LIBTLS_LIBS" + TLS_C="tls_libtls.c" + ;; +xyes|xno) + unet_cv_with_tls="none" + TLS_C="tls_none.c" + ;; +esac +if test x"$TLS_C" = x ; then + AC_MSG_WARN([Unknown TLS library $unet_cv_with_tls]) + TLS_C="tls_none.c" +fi +AC_MSG_RESULT([$unet_cv_with_tls]) +AC_SUBST([TLS_C]) + +if test x"$unet_cv_with_tls" = xopenssl ; then + AC_CHECK_FUNCS([SSL_set_ciphersuites]) +fi]) + dnl Written by John Hawkinson . This code is in the Public dnl Domain. dnl diff --git a/aclocal.m4 b/aclocal.m4 index f803d95c..8e371103 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -12,6 +12,131 @@ # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_openssl.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_OPENSSL([action-if-found[, action-if-not-found]]) +# +# DESCRIPTION +# +# Look for OpenSSL in a number of default spots, or in a user-selected +# spot (via --with-openssl). Sets +# +# OPENSSL_INCLUDES to the include directives required +# OPENSSL_LIBS to the -l directives required +# OPENSSL_LDFLAGS to the -L or -R flags required +# +# and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately +# +# This macro sets OPENSSL_INCLUDES such that source files should use the +# openssl/ directory in include directives: +# +# #include +# +# LICENSE +# +# Copyright (c) 2009,2010 Zmanda Inc. +# Copyright (c) 2009,2010 Dustin J. Mitchell +# +# 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 11 + +AU_ALIAS([CHECK_SSL], [AX_CHECK_OPENSSL]) +AC_DEFUN([AX_CHECK_OPENSSL], [ + found=false + AC_ARG_WITH([openssl], + [AS_HELP_STRING([--with-openssl=DIR], + [root of the OpenSSL directory])], + [ + case "$withval" in + "" | y | ye | yes | n | no) + AC_MSG_ERROR([Invalid --with-openssl value]) + ;; + *) ssldirs="$withval" + ;; + esac + ], [ + # if pkg-config is installed and openssl has installed a .pc file, + # then use that information and don't search ssldirs + AC_CHECK_TOOL([PKG_CONFIG], [pkg-config]) + if test x"$PKG_CONFIG" != x""; then + OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null` + if test $? = 0; then + OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null` + OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null` + found=true + fi + fi + + # no such luck; use some default ssldirs + if ! $found; then + ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" + fi + ] + ) + + + # note that we #include , so the OpenSSL headers have to be in + # an 'openssl' subdirectory + + if ! $found; then + OPENSSL_INCLUDES= + for ssldir in $ssldirs; do + AC_MSG_CHECKING([for include/openssl/ssl.h in $ssldir]) + if test -f "$ssldir/include/openssl/ssl.h"; then + OPENSSL_INCLUDES="-I$ssldir/include" + OPENSSL_LDFLAGS="-L$ssldir/lib" + OPENSSL_LIBS="-lssl -lcrypto" + found=true + AC_MSG_RESULT([yes]) + break + else + AC_MSG_RESULT([no]) + fi + done + + # if the file wasn't found, well, go ahead and try the link anyway -- maybe + # it will just work! + fi + + # try the preprocessor and linker with our new flags, + # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS + + AC_MSG_CHECKING([whether compiling and linking against OpenSSL works]) + echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ + "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&AS_MESSAGE_LOG_FD + + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + save_CPPFLAGS="$CPPFLAGS" + LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" + LIBS="$OPENSSL_LIBS $LIBS" + CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([#include ], [SSL_new(NULL)])], + [ + AC_MSG_RESULT([yes]) + $1 + ], [ + AC_MSG_RESULT([no]) + $2 + ]) + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + + AC_SUBST([OPENSSL_INCLUDES]) + AC_SUBST([OPENSSL_LIBS]) + AC_SUBST([OPENSSL_LDFLAGS]) +]) + # pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*- # serial 12 (pkg-config-0.29.2) diff --git a/config.guess b/config.guess index f7727026..48a68460 100755 --- a/config.guess +++ b/config.guess @@ -1,12 +1,14 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2021 Free Software Foundation, Inc. +# Copyright 1992-2024 Free Software Foundation, Inc. -timestamp='2021-01-01' +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2024-07-27' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or +# the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but @@ -32,12 +34,20 @@ timestamp='2021-01-01' # Please send patches to . -me=$(echo "$0" | sed -e 's,.*/,,') +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + + +me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] -Output the configuration name of the system \`$me' is run on. +Output the configuration name of the system '$me' is run on. Options: -h, --help print this help, then exit @@ -50,13 +60,13 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2021 Free Software Foundation, Inc. +Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" -Try \`$me --help' for more information." +Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do @@ -84,13 +94,16 @@ if test $# != 0; then exit 1 fi +# Just in case it came from the environment. +GUESS= + # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. -# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still -# use `HOST_CC' if defined, but it is deprecated. +# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still +# use 'HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. @@ -102,17 +115,17 @@ set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" - # shellcheck disable=SC2039 - { tmp=$( (umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null) && test -n "$tmp" && test -d "$tmp" ; } || + # shellcheck disable=SC2039,SC3028 + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" - for driver in cc gcc c89 c99 ; do + for driver in cc gcc c17 c99 c89 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then - CC_FOR_BUILD="$driver" + CC_FOR_BUILD=$driver break fi done @@ -131,17 +144,20 @@ if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi -UNAME_MACHINE=$( (uname -m) 2>/dev/null) || UNAME_MACHINE=unknown -UNAME_RELEASE=$( (uname -r) 2>/dev/null) || UNAME_RELEASE=unknown -UNAME_SYSTEM=$( (uname -s) 2>/dev/null) || UNAME_SYSTEM=unknown -UNAME_VERSION=$( (uname -v) 2>/dev/null) || UNAME_VERSION=unknown +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown -case "$UNAME_SYSTEM" in +case $UNAME_SYSTEM in Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" + #if defined(__ANDROID__) + LIBC=android + #else #include #if defined(__UCLIBC__) LIBC=uclibc @@ -149,6 +165,8 @@ Linux|GNU|GNU/*) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu + #elif defined(__LLVM_LIBC__) + LIBC=llvm #else #include /* First heuristic to detect musl libc. */ @@ -156,8 +174,10 @@ Linux|GNU|GNU/*) LIBC=musl #endif #endif + #endif EOF - eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g')" + cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + eval "$cc_set_libc" # Second heuristic to detect musl libc. if [ "$LIBC" = unknown ] && @@ -176,7 +196,7 @@ esac # Note: order is significant - the case branches are not exclusive. -case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in +case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, @@ -188,12 +208,11 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". - sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \ - "/sbin/$sysctl" 2>/dev/null || \ - "/usr/sbin/$sysctl" 2>/dev/null || \ - echo unknown)) - case "$UNAME_MACHINE_ARCH" in + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + echo unknown)` + case $UNAME_MACHINE_ARCH in aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; @@ -201,15 +220,15 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) - arch=$(echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,') - endian=$(echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p') - machine="${arch}${endian}"-unknown + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown ;; - *) machine="$UNAME_MACHINE_ARCH"-unknown ;; + *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. - case "$UNAME_MACHINE_ARCH" in + case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; @@ -230,10 +249,10 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in ;; esac # Determine ABI tags. - case "$UNAME_MACHINE_ARCH" in + case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' - abi=$(echo "$UNAME_MACHINE_ARCH" | sed -e "$expr") + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release @@ -241,76 +260,82 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. - case "$UNAME_VERSION" in + case $UNAME_VERSION in Debian*) release='-gnu' ;; *) - release=$(echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2) + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "$machine-${os}${release}${abi-}" - exit ;; + GUESS=$machine-${os}${release}${abi-} + ;; *:Bitrig:*:*) - UNAME_MACHINE_ARCH=$(arch | sed 's/Bitrig.//') - echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" - exit ;; + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE + ;; *:OpenBSD:*:*) - UNAME_MACHINE_ARCH=$(arch | sed 's/OpenBSD.//') - echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" - exit ;; + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE + ;; + *:SecBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE + ;; *:LibertyBSD:*:*) - UNAME_MACHINE_ARCH=$(arch | sed 's/^.*BSD\.//') - echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" - exit ;; + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE + ;; *:MidnightBSD:*:*) - echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE + ;; *:ekkoBSD:*:*) - echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE + ;; *:SolidBSD:*:*) - echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE + ;; *:OS108:*:*) - echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE + ;; macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd"$UNAME_RELEASE" - exit ;; + GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE + ;; *:MirBSD:*:*) - echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE + ;; *:Sortix:*:*) - echo "$UNAME_MACHINE"-unknown-sortix - exit ;; + GUESS=$UNAME_MACHINE-unknown-sortix + ;; *:Twizzler:*:*) - echo "$UNAME_MACHINE"-unknown-twizzler - exit ;; + GUESS=$UNAME_MACHINE-unknown-twizzler + ;; *:Redox:*:*) - echo "$UNAME_MACHINE"-unknown-redox - exit ;; + GUESS=$UNAME_MACHINE-unknown-redox + ;; mips:OSF1:*.*) - echo mips-dec-osf1 - exit ;; + GUESS=mips-dec-osf1 + ;; alpha:OSF1:*:*) + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + trap '' 0 case $UNAME_RELEASE in *4.0) - UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $3}') + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) - UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $4}') + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. - ALPHA_CPU_TYPE=$(/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1) - case "$ALPHA_CPU_TYPE" in + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") @@ -347,68 +372,69 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo "$UNAME_MACHINE"-dec-osf"$(echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)" - # Reset EXIT trap before exiting to avoid spurious non-zero exit code. - exitcode=$? - trap '' 0 - exit $exitcode ;; + OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + GUESS=$UNAME_MACHINE-dec-osf$OSF_REL + ;; Amiga*:UNIX_System_V:4.0:*) - echo m68k-unknown-sysv4 - exit ;; + GUESS=m68k-unknown-sysv4 + ;; *:[Aa]miga[Oo][Ss]:*:*) - echo "$UNAME_MACHINE"-unknown-amigaos - exit ;; + GUESS=$UNAME_MACHINE-unknown-amigaos + ;; *:[Mm]orph[Oo][Ss]:*:*) - echo "$UNAME_MACHINE"-unknown-morphos - exit ;; + GUESS=$UNAME_MACHINE-unknown-morphos + ;; *:OS/390:*:*) - echo i370-ibm-openedition - exit ;; + GUESS=i370-ibm-openedition + ;; *:z/VM:*:*) - echo s390-ibm-zvmoe - exit ;; + GUESS=s390-ibm-zvmoe + ;; *:OS400:*:*) - echo powerpc-ibm-os400 - exit ;; + GUESS=powerpc-ibm-os400 + ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix"$UNAME_RELEASE" - exit ;; + GUESS=arm-acorn-riscix$UNAME_RELEASE + ;; arm*:riscos:*:*|arm*:RISCOS:*:*) - echo arm-unknown-riscos - exit ;; + GUESS=arm-unknown-riscos + ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) - echo hppa1.1-hitachi-hiuxmpp - exit ;; + GUESS=hppa1.1-hitachi-hiuxmpp + ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - if test "$( (/bin/universe) 2>/dev/null)" = att ; then - echo pyramid-pyramid-sysv3 - else - echo pyramid-pyramid-bsd - fi - exit ;; + case `(/bin/universe) 2>/dev/null` in + att) GUESS=pyramid-pyramid-sysv3 ;; + *) GUESS=pyramid-pyramid-bsd ;; + esac + ;; NILE*:*:*:dcosx) - echo pyramid-pyramid-svr4 - exit ;; + GUESS=pyramid-pyramid-svr4 + ;; DRS?6000:unix:4.0:6*) - echo sparc-icl-nx6 - exit ;; + GUESS=sparc-icl-nx6 + ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) - case $(/usr/bin/uname -p) in - sparc) echo sparc-icl-nx7; exit ;; - esac ;; + case `/usr/bin/uname -p` in + sparc) GUESS=sparc-icl-nx7 ;; + esac + ;; s390x:SunOS:*:*) - echo "$UNAME_MACHINE"-ibm-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL + ;; sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-hal-solaris2$SUN_REL + ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris2$SUN_REL + ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) - echo i386-pc-auroraux"$UNAME_RELEASE" - exit ;; + GUESS=i386-pc-auroraux$UNAME_RELEASE + ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 @@ -417,47 +443,50 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # This test works for both compilers. if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi - echo "$SUN_ARCH"-pc-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$SUN_ARCH-pc-solaris2$SUN_REL + ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris3$SUN_REL + ;; sun4*:SunOS:*:*) - case "$(/usr/bin/arch -k)" in + case `/usr/bin/arch -k` in Series*|S4*) - UNAME_RELEASE=$(uname -v) + UNAME_RELEASE=`uname -v` ;; esac - # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/')" - exit ;; + # Japanese Language versions have a version number like '4.1.3-JL'. + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` + GUESS=sparc-sun-sunos$SUN_REL + ;; sun3*:SunOS:*:*) - echo m68k-sun-sunos"$UNAME_RELEASE" - exit ;; + GUESS=m68k-sun-sunos$UNAME_RELEASE + ;; sun*:*:4.2BSD:*) - UNAME_RELEASE=$( (sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 - case "$(/bin/arch)" in + case `/bin/arch` in sun3) - echo m68k-sun-sunos"$UNAME_RELEASE" + GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) - echo sparc-sun-sunos"$UNAME_RELEASE" + GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac - exit ;; + ;; aushp:SunOS:*:*) - echo sparc-auspex-sunos"$UNAME_RELEASE" - exit ;; + GUESS=sparc-auspex-sunos$UNAME_RELEASE + ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor @@ -467,41 +496,41 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-milan-mint$UNAME_RELEASE + ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-hades-mint$UNAME_RELEASE + ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-unknown-mint$UNAME_RELEASE + ;; m68k:machten:*:*) - echo m68k-apple-machten"$UNAME_RELEASE" - exit ;; + GUESS=m68k-apple-machten$UNAME_RELEASE + ;; powerpc:machten:*:*) - echo powerpc-apple-machten"$UNAME_RELEASE" - exit ;; + GUESS=powerpc-apple-machten$UNAME_RELEASE + ;; RISC*:Mach:*:*) - echo mips-dec-mach_bsd4.3 - exit ;; + GUESS=mips-dec-mach_bsd4.3 + ;; RISC*:ULTRIX:*:*) - echo mips-dec-ultrix"$UNAME_RELEASE" - exit ;; + GUESS=mips-dec-ultrix$UNAME_RELEASE + ;; VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix"$UNAME_RELEASE" - exit ;; + GUESS=vax-dec-ultrix$UNAME_RELEASE + ;; 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix"$UNAME_RELEASE" - exit ;; + GUESS=clipper-intergraph-clix$UNAME_RELEASE + ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" @@ -526,85 +555,87 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && - dummyarg=$(echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p') && - SYSTEM_NAME=$("$dummy" "$dummyarg") && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos"$UNAME_RELEASE" - exit ;; + GUESS=mips-mips-riscos$UNAME_RELEASE + ;; Motorola:PowerMAX_OS:*:*) - echo powerpc-motorola-powermax - exit ;; + GUESS=powerpc-motorola-powermax + ;; Motorola:*:4.3:PL8-*) - echo powerpc-harris-powermax - exit ;; + GUESS=powerpc-harris-powermax + ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) - echo powerpc-harris-powermax - exit ;; + GUESS=powerpc-harris-powermax + ;; Night_Hawk:Power_UNIX:*:*) - echo powerpc-harris-powerunix - exit ;; + GUESS=powerpc-harris-powerunix + ;; m88k:CX/UX:7*:*) - echo m88k-harris-cxux7 - exit ;; + GUESS=m88k-harris-cxux7 + ;; m88k:*:4*:R4*) - echo m88k-motorola-sysv4 - exit ;; + GUESS=m88k-motorola-sysv4 + ;; m88k:*:3*:R3*) - echo m88k-motorola-sysv3 - exit ;; + GUESS=m88k-motorola-sysv3 + ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=$(/usr/bin/uname -p) + UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then - echo m88k-dg-dgux"$UNAME_RELEASE" + GUESS=m88k-dg-dgux$UNAME_RELEASE else - echo m88k-dg-dguxbcs"$UNAME_RELEASE" + GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else - echo i586-dg-dgux"$UNAME_RELEASE" + GUESS=i586-dg-dgux$UNAME_RELEASE fi - exit ;; + ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) - echo m88k-dolphin-sysv3 - exit ;; + GUESS=m88k-dolphin-sysv3 + ;; M88*:*:R3*:*) # Delta 88k system running SVR3 - echo m88k-motorola-sysv3 - exit ;; + GUESS=m88k-motorola-sysv3 + ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - echo m88k-tektronix-sysv3 - exit ;; + GUESS=m88k-tektronix-sysv3 + ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - echo m68k-tektronix-bsd - exit ;; + GUESS=m68k-tektronix-bsd + ;; *:IRIX*:*:*) - echo mips-sgi-irix"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/g')" - exit ;; + IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` + GUESS=mips-sgi-irix$IRIX_REL + ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit ;; # Note that: echo "'$(uname -s)'" gives 'AIX ' + GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id + ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) - echo i386-ibm-aix - exit ;; + GUESS=i386-ibm-aix + ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then - IBM_REV=$(/usr/bin/oslevel) + IBM_REV=`/usr/bin/oslevel` else - IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi - echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" - exit ;; + GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV + ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include - main() + int + main () { if (!__power_pc()) exit(1); @@ -612,68 +643,68 @@ EOF exit(0); } EOF - if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then - echo "$SYSTEM_NAME" + GUESS=$SYSTEM_NAME else - echo rs6000-ibm-aix3.2.5 + GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - echo rs6000-ibm-aix3.2.4 + GUESS=rs6000-ibm-aix3.2.4 else - echo rs6000-ibm-aix3.2 + GUESS=rs6000-ibm-aix3.2 fi - exit ;; + ;; *:AIX:*:[4567]) - IBM_CPU_ID=$(/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }') + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if test -x /usr/bin/lslpp ; then - IBM_REV=$(/usr/bin/lslpp -Lqc bos.rte.libc | - awk -F: '{ print $3 }' | sed s/[0-9]*$/0/) + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else - IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi - echo "$IBM_ARCH"-ibm-aix"$IBM_REV" - exit ;; + GUESS=$IBM_ARCH-ibm-aix$IBM_REV + ;; *:AIX:*:*) - echo rs6000-ibm-aix - exit ;; + GUESS=rs6000-ibm-aix + ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) - echo romp-ibm-bsd4.4 - exit ;; + GUESS=romp-ibm-bsd4.4 + ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to - exit ;; # report: romp-ibm BSD 4.3 + GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to + ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) - echo rs6000-bull-bosx - exit ;; + GUESS=rs6000-bull-bosx + ;; DPX/2?00:B.O.S.:*:*) - echo m68k-bull-sysv3 - exit ;; + GUESS=m68k-bull-sysv3 + ;; 9000/[34]??:4.3bsd:1.*:*) - echo m68k-hp-bsd - exit ;; + GUESS=m68k-hp-bsd + ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - echo m68k-hp-bsd4.4 - exit ;; + GUESS=m68k-hp-bsd4.4 + ;; 9000/[34678]??:HP-UX:*:*) - HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//') - case "$UNAME_MACHINE" in + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + case $UNAME_MACHINE in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if test -x /usr/bin/getconf; then - sc_cpu_version=$(/usr/bin/getconf SC_CPU_VERSION 2>/dev/null) - sc_kernel_bits=$(/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null) - case "$sc_cpu_version" in + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 - case "$sc_kernel_bits" in + case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 @@ -688,7 +719,8 @@ EOF #include #include - int main () + int + main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); @@ -715,7 +747,7 @@ EOF exit (0); } EOF - (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=$("$dummy") + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac @@ -740,12 +772,12 @@ EOF HP_ARCH=hppa64 fi fi - echo "$HP_ARCH"-hp-hpux"$HPUX_REV" - exit ;; + GUESS=$HP_ARCH-hp-hpux$HPUX_REV + ;; ia64:HP-UX:*:*) - HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//') - echo ia64-hp-hpux"$HPUX_REV" - exit ;; + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + GUESS=ia64-hp-hpux$HPUX_REV + ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" @@ -773,38 +805,38 @@ EOF exit (0); } EOF - $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") && + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } - echo unknown-hitachi-hiuxwe2 - exit ;; + GUESS=unknown-hitachi-hiuxwe2 + ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) - echo hppa1.1-hp-bsd - exit ;; + GUESS=hppa1.1-hp-bsd + ;; 9000/8??:4.3bsd:*:*) - echo hppa1.0-hp-bsd - exit ;; + GUESS=hppa1.0-hp-bsd + ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) - echo hppa1.0-hp-mpeix - exit ;; + GUESS=hppa1.0-hp-mpeix + ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) - echo hppa1.1-hp-osf - exit ;; + GUESS=hppa1.1-hp-osf + ;; hp8??:OSF1:*:*) - echo hppa1.0-hp-osf - exit ;; + GUESS=hppa1.0-hp-osf + ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then - echo "$UNAME_MACHINE"-unknown-osf1mk + GUESS=$UNAME_MACHINE-unknown-osf1mk else - echo "$UNAME_MACHINE"-unknown-osf1 + GUESS=$UNAME_MACHINE-unknown-osf1 fi - exit ;; + ;; parisc*:Lites*:*:*) - echo hppa1.1-hp-lites - exit ;; + GUESS=hppa1.1-hp-lites + ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - echo c1-convex-bsd - exit ;; + GUESS=c1-convex-bsd + ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd @@ -812,17 +844,18 @@ EOF fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - echo c34-convex-bsd - exit ;; + GUESS=c34-convex-bsd + ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - echo c38-convex-bsd - exit ;; + GUESS=c38-convex-bsd + ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - echo c4-convex-bsd - exit ;; + GUESS=c4-convex-bsd + ;; CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=ymp-cray-unicos$CRAY_REL + ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ @@ -830,114 +863,155 @@ EOF -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) - echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=t90-cray-unicos$CRAY_REL + ;; CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=alphaev5-cray-unicosmk$CRAY_REL + ;; CRAY*SV1:*:*:*) - echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=sv1-cray-unicos$CRAY_REL + ;; *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=craynv-cray-unicosmp$CRAY_REL + ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=$(uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz) - FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///') - FUJITSU_REL=$(echo "$UNAME_RELEASE" | sed -e 's/ /_/') - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` + GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///') - FUJITSU_REL=$(echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/') - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE + ;; sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi"$UNAME_RELEASE" - exit ;; + GUESS=sparc-unknown-bsdi$UNAME_RELEASE + ;; *:BSD/OS:*:*) - echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE + ;; arm:FreeBSD:*:*) - UNAME_PROCESSOR=$(uname -p) + UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then - echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabi + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else - echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabihf + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi - exit ;; + ;; *:FreeBSD:*:*) - UNAME_PROCESSOR=$(/usr/bin/uname -p) - case "$UNAME_PROCESSOR" in + UNAME_PROCESSOR=`uname -p` + case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac - echo "$UNAME_PROCESSOR"-unknown-freebsd"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')" - exit ;; + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL + ;; i*:CYGWIN*:*) - echo "$UNAME_MACHINE"-pc-cygwin - exit ;; + GUESS=$UNAME_MACHINE-pc-cygwin + ;; *:MINGW64*:*) - echo "$UNAME_MACHINE"-pc-mingw64 - exit ;; + GUESS=$UNAME_MACHINE-pc-mingw64 + ;; *:MINGW*:*) - echo "$UNAME_MACHINE"-pc-mingw32 - exit ;; + GUESS=$UNAME_MACHINE-pc-mingw32 + ;; *:MSYS*:*) - echo "$UNAME_MACHINE"-pc-msys - exit ;; + GUESS=$UNAME_MACHINE-pc-msys + ;; i*:PW*:*) - echo "$UNAME_MACHINE"-pc-pw32 - exit ;; + GUESS=$UNAME_MACHINE-pc-pw32 + ;; + *:SerenityOS:*:*) + GUESS=$UNAME_MACHINE-pc-serenity + ;; *:Interix*:*) - case "$UNAME_MACHINE" in + case $UNAME_MACHINE in x86) - echo i586-pc-interix"$UNAME_RELEASE" - exit ;; + GUESS=i586-pc-interix$UNAME_RELEASE + ;; authenticamd | genuineintel | EM64T) - echo x86_64-unknown-interix"$UNAME_RELEASE" - exit ;; + GUESS=x86_64-unknown-interix$UNAME_RELEASE + ;; IA64) - echo ia64-unknown-interix"$UNAME_RELEASE" - exit ;; + GUESS=ia64-unknown-interix$UNAME_RELEASE + ;; esac ;; i*:UWIN*:*) - echo "$UNAME_MACHINE"-pc-uwin - exit ;; + GUESS=$UNAME_MACHINE-pc-uwin + ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - echo x86_64-pc-cygwin - exit ;; + GUESS=x86_64-pc-cygwin + ;; prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=powerpcle-unknown-solaris2$SUN_REL + ;; *:GNU:*:*) # the GNU system - echo "$(echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,')-unknown-$LIBC$(echo "$UNAME_RELEASE"|sed -e 's,/.*$,,')" - exit ;; + GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` + GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL + ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo "$UNAME_MACHINE-unknown-$(echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]")$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')-$LIBC" - exit ;; + GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC + ;; + x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) + GUESS="$UNAME_MACHINE-pc-managarm-mlibc" + ;; + *:[Mm]anagarm:*:*) + GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" + ;; *:Minix:*:*) - echo "$UNAME_MACHINE"-unknown-minix - exit ;; + GUESS=$UNAME_MACHINE-unknown-minix + ;; aarch64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + set_cc_for_build + CPU=$UNAME_MACHINE + LIBCABI=$LIBC + if test "$CC_FOR_BUILD" != no_compiler_found; then + ABI=64 + sed 's/^ //' << EOF > "$dummy.c" + #ifdef __ARM_EABI__ + #ifdef __ARM_PCS_VFP + ABI=eabihf + #else + ABI=eabi + #endif + #endif +EOF + cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` + eval "$cc_set_abi" + case $ABI in + eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;; + esac + fi + GUESS=$CPU-unknown-linux-$LIBCABI + ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; alpha:Linux:*:*) - case $(sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null) in + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; @@ -948,63 +1022,72 @@ EOF esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - arc:Linux:*:* | arceb:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi - exit ;; + ;; avr32*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; cris:Linux:*:*) - echo "$UNAME_MACHINE"-axis-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; crisv32:Linux:*:*) - echo "$UNAME_MACHINE"-axis-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; e2k:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; frv:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; hexagon:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; i*86:Linux:*:*) - echo "$UNAME_MACHINE"-pc-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-pc-linux-$LIBC + ;; ia64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; k1om:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + kvx:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + kvx:cos:*:*) + GUESS=$UNAME_MACHINE-unknown-cos + ;; + kvx:mbr:*:*) + GUESS=$UNAME_MACHINE-unknown-mbr + ;; + loongarch32:Linux:*:* | loongarch64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; m32r*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; m68*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 @@ -1049,138 +1132,150 @@ EOF #endif #endif EOF - eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI')" + cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` + eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; openrisc*:Linux:*:*) - echo or1k-unknown-linux-"$LIBC" - exit ;; + GUESS=or1k-unknown-linux-$LIBC + ;; or32:Linux:*:* | or1k*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; padre:Linux:*:*) - echo sparc-unknown-linux-"$LIBC" - exit ;; + GUESS=sparc-unknown-linux-$LIBC + ;; parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-"$LIBC" - exit ;; + GUESS=hppa64-unknown-linux-$LIBC + ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level - case $(grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2) in - PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; - PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; - *) echo hppa-unknown-linux-"$LIBC" ;; + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; + PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; + *) GUESS=hppa-unknown-linux-$LIBC ;; esac - exit ;; + ;; ppc64:Linux:*:*) - echo powerpc64-unknown-linux-"$LIBC" - exit ;; + GUESS=powerpc64-unknown-linux-$LIBC + ;; ppc:Linux:*:*) - echo powerpc-unknown-linux-"$LIBC" - exit ;; + GUESS=powerpc-unknown-linux-$LIBC + ;; ppc64le:Linux:*:*) - echo powerpc64le-unknown-linux-"$LIBC" - exit ;; + GUESS=powerpc64le-unknown-linux-$LIBC + ;; ppcle:Linux:*:*) - echo powerpcle-unknown-linux-"$LIBC" - exit ;; + GUESS=powerpcle-unknown-linux-$LIBC + ;; riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; s390:Linux:*:* | s390x:Linux:*:*) - echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-ibm-linux-$LIBC + ;; sh64*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; sh*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; sparc:Linux:*:* | sparc64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; tile*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; vax:Linux:*:*) - echo "$UNAME_MACHINE"-dec-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-dec-linux-$LIBC + ;; x86_64:Linux:*:*) set_cc_for_build + CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then - if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_X32 >/dev/null - then - LIBCABI="$LIBC"x32 - fi + ABI=64 + sed 's/^ //' << EOF > "$dummy.c" + #ifdef __i386__ + ABI=x86 + #else + #ifdef __ILP32__ + ABI=x32 + #endif + #endif +EOF + cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` + eval "$cc_set_abi" + case $ABI in + x86) CPU=i686 ;; + x32) LIBCABI=${LIBC}x32 ;; + esac fi - echo "$UNAME_MACHINE"-pc-linux-"$LIBCABI" - exit ;; + GUESS=$CPU-pc-linux-$LIBCABI + ;; xtensa*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. - echo i386-sequent-sysv4 - exit ;; + GUESS=i386-sequent-sysv4 + ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. - echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" - exit ;; + GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION + ;; i*86:OS/2:*:*) - # If we were able to find `uname', then EMX Unix compatibility + # If we were able to find 'uname', then EMX Unix compatibility # is probably installed. - echo "$UNAME_MACHINE"-pc-os2-emx - exit ;; + GUESS=$UNAME_MACHINE-pc-os2-emx + ;; i*86:XTS-300:*:STOP) - echo "$UNAME_MACHINE"-unknown-stop - exit ;; + GUESS=$UNAME_MACHINE-unknown-stop + ;; i*86:atheos:*:*) - echo "$UNAME_MACHINE"-unknown-atheos - exit ;; + GUESS=$UNAME_MACHINE-unknown-atheos + ;; i*86:syllable:*:*) - echo "$UNAME_MACHINE"-pc-syllable - exit ;; + GUESS=$UNAME_MACHINE-pc-syllable + ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - echo i386-unknown-lynxos"$UNAME_RELEASE" - exit ;; + GUESS=i386-unknown-lynxos$UNAME_RELEASE + ;; i*86:*DOS:*:*) - echo "$UNAME_MACHINE"-pc-msdosdjgpp - exit ;; + GUESS=$UNAME_MACHINE-pc-msdosdjgpp + ;; i*86:*:4.*:*) - UNAME_REL=$(echo "$UNAME_RELEASE" | sed 's/\/MP$//') + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" + GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else - echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" + GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi - exit ;; + ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. - case $(/bin/uname -X | grep "^Machine") in + case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac - echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}" - exit ;; + GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then - UNAME_REL=$(sed -n 's/.*Version //p' /dev/null >/dev/null ; then - UNAME_REL=$( (/bin/uname -X|grep Release|sed -e 's/.*= //')) + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 @@ -1188,11 +1283,11 @@ EOF && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 - echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" + GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else - echo "$UNAME_MACHINE"-pc-sysv32 + GUESS=$UNAME_MACHINE-pc-sysv32 fi - exit ;; + ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about @@ -1200,37 +1295,37 @@ EOF # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. - echo i586-pc-msdosdjgpp - exit ;; + GUESS=i586-pc-msdosdjgpp + ;; Intel:Mach:3*:*) - echo i386-pc-mach3 - exit ;; + GUESS=i386-pc-mach3 + ;; paragon:*:*:*) - echo i860-intel-osf1 - exit ;; + GUESS=i860-intel-osf1 + ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 + GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 + GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi - exit ;; + ;; mini*:CTIX:SYS*5:*) # "miniframe" - echo m68010-convergent-sysv - exit ;; + GUESS=m68010-convergent-sysv + ;; mc68k:UNIX:SYSTEM5:3.51m) - echo m68k-convergent-sysv - exit ;; + GUESS=m68k-convergent-sysv + ;; M680?0:D-NIX:5.3:*) - echo m68k-diab-dnix - exit ;; + GUESS=m68k-diab-dnix + ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ - && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid) + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ @@ -1241,7 +1336,7 @@ EOF NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ - && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid) + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ @@ -1249,118 +1344,121 @@ EOF /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos"$UNAME_RELEASE" - exit ;; + GUESS=m68k-unknown-lynxos$UNAME_RELEASE + ;; mc68030:UNIX_System_V:4.*:*) - echo m68k-atari-sysv4 - exit ;; + GUESS=m68k-atari-sysv4 + ;; TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos"$UNAME_RELEASE" - exit ;; + GUESS=sparc-unknown-lynxos$UNAME_RELEASE + ;; rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos"$UNAME_RELEASE" - exit ;; + GUESS=rs6000-unknown-lynxos$UNAME_RELEASE + ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - echo powerpc-unknown-lynxos"$UNAME_RELEASE" - exit ;; + GUESS=powerpc-unknown-lynxos$UNAME_RELEASE + ;; SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv"$UNAME_RELEASE" - exit ;; + GUESS=mips-dde-sysv$UNAME_RELEASE + ;; RM*:ReliantUNIX-*:*:*) - echo mips-sni-sysv4 - exit ;; + GUESS=mips-sni-sysv4 + ;; RM*:SINIX-*:*:*) - echo mips-sni-sysv4 - exit ;; + GUESS=mips-sni-sysv4 + ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then - UNAME_MACHINE=$( (uname -p) 2>/dev/null) - echo "$UNAME_MACHINE"-sni-sysv4 + UNAME_MACHINE=`(uname -p) 2>/dev/null` + GUESS=$UNAME_MACHINE-sni-sysv4 else - echo ns32k-sni-sysv + GUESS=ns32k-sni-sysv fi - exit ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + ;; + PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort # says - echo i586-unisys-sysv4 - exit ;; + GUESS=i586-unisys-sysv4 + ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm - echo hppa1.1-stratus-sysv4 - exit ;; + GUESS=hppa1.1-stratus-sysv4 + ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. - echo i860-stratus-sysv4 - exit ;; + GUESS=i860-stratus-sysv4 + ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. - echo "$UNAME_MACHINE"-stratus-vos - exit ;; + GUESS=$UNAME_MACHINE-stratus-vos + ;; *:VOS:*:*) # From Paul.Green@stratus.com. - echo hppa1.1-stratus-vos - exit ;; + GUESS=hppa1.1-stratus-vos + ;; mc68*:A/UX:*:*) - echo m68k-apple-aux"$UNAME_RELEASE" - exit ;; + GUESS=m68k-apple-aux$UNAME_RELEASE + ;; news*:NEWS-OS:6*:*) - echo mips-sony-newsos6 - exit ;; + GUESS=mips-sony-newsos6 + ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then - echo mips-nec-sysv"$UNAME_RELEASE" + GUESS=mips-nec-sysv$UNAME_RELEASE else - echo mips-unknown-sysv"$UNAME_RELEASE" + GUESS=mips-unknown-sysv$UNAME_RELEASE fi - exit ;; + ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - echo powerpc-be-beos - exit ;; + GUESS=powerpc-be-beos + ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - echo powerpc-apple-beos - exit ;; + GUESS=powerpc-apple-beos + ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - echo i586-pc-beos - exit ;; + GUESS=i586-pc-beos + ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. - echo i586-pc-haiku - exit ;; - x86_64:Haiku:*:*) - echo x86_64-unknown-haiku - exit ;; + GUESS=i586-pc-haiku + ;; + ppc:Haiku:*:*) # Haiku running on Apple PowerPC + GUESS=powerpc-apple-haiku + ;; + *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) + GUESS=$UNAME_MACHINE-unknown-haiku + ;; SX-4:SUPER-UX:*:*) - echo sx4-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx4-nec-superux$UNAME_RELEASE + ;; SX-5:SUPER-UX:*:*) - echo sx5-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx5-nec-superux$UNAME_RELEASE + ;; SX-6:SUPER-UX:*:*) - echo sx6-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx6-nec-superux$UNAME_RELEASE + ;; SX-7:SUPER-UX:*:*) - echo sx7-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx7-nec-superux$UNAME_RELEASE + ;; SX-8:SUPER-UX:*:*) - echo sx8-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx8-nec-superux$UNAME_RELEASE + ;; SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx8r-nec-superux$UNAME_RELEASE + ;; SX-ACE:SUPER-UX:*:*) - echo sxace-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sxace-nec-superux$UNAME_RELEASE + ;; Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody"$UNAME_RELEASE" - exit ;; + GUESS=powerpc-apple-rhapsody$UNAME_RELEASE + ;; *:Rhapsody:*:*) - echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE + ;; arm64:Darwin:*:*) - echo aarch64-apple-darwin"$UNAME_RELEASE" - exit ;; + GUESS=aarch64-apple-darwin$UNAME_RELEASE + ;; *:Darwin:*:*) - UNAME_PROCESSOR=$(uname -p) + UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac @@ -1394,109 +1492,122 @@ EOF # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi - echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE + ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) - UNAME_PROCESSOR=$(uname -p) + UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi - echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE + ;; *:QNX:*:4*) - echo i386-pc-qnx - exit ;; + GUESS=i386-pc-qnx + ;; NEO-*:NONSTOP_KERNEL:*:*) - echo neo-tandem-nsk"$UNAME_RELEASE" - exit ;; + GUESS=neo-tandem-nsk$UNAME_RELEASE + ;; NSE-*:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk"$UNAME_RELEASE" - exit ;; + GUESS=nse-tandem-nsk$UNAME_RELEASE + ;; NSR-*:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk"$UNAME_RELEASE" - exit ;; + GUESS=nsr-tandem-nsk$UNAME_RELEASE + ;; NSV-*:NONSTOP_KERNEL:*:*) - echo nsv-tandem-nsk"$UNAME_RELEASE" - exit ;; + GUESS=nsv-tandem-nsk$UNAME_RELEASE + ;; NSX-*:NONSTOP_KERNEL:*:*) - echo nsx-tandem-nsk"$UNAME_RELEASE" - exit ;; + GUESS=nsx-tandem-nsk$UNAME_RELEASE + ;; *:NonStop-UX:*:*) - echo mips-compaq-nonstopux - exit ;; + GUESS=mips-compaq-nonstopux + ;; BS2000:POSIX*:*:*) - echo bs2000-siemens-sysv - exit ;; + GUESS=bs2000-siemens-sysv + ;; DS/*:UNIX_System_V:*:*) - echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE + ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. - # shellcheck disable=SC2154 - if test "$cputype" = 386; then + if test "${cputype-}" = 386; then UNAME_MACHINE=i386 - else - UNAME_MACHINE="$cputype" + elif test "x${cputype-}" != x; then + UNAME_MACHINE=$cputype fi - echo "$UNAME_MACHINE"-unknown-plan9 - exit ;; + GUESS=$UNAME_MACHINE-unknown-plan9 + ;; *:TOPS-10:*:*) - echo pdp10-unknown-tops10 - exit ;; + GUESS=pdp10-unknown-tops10 + ;; *:TENEX:*:*) - echo pdp10-unknown-tenex - exit ;; + GUESS=pdp10-unknown-tenex + ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) - echo pdp10-dec-tops20 - exit ;; + GUESS=pdp10-dec-tops20 + ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) - echo pdp10-xkl-tops20 - exit ;; + GUESS=pdp10-xkl-tops20 + ;; *:TOPS-20:*:*) - echo pdp10-unknown-tops20 - exit ;; + GUESS=pdp10-unknown-tops20 + ;; *:ITS:*:*) - echo pdp10-unknown-its - exit ;; + GUESS=pdp10-unknown-its + ;; SEI:*:*:SEIUX) - echo mips-sei-seiux"$UNAME_RELEASE" - exit ;; + GUESS=mips-sei-seiux$UNAME_RELEASE + ;; *:DragonFly:*:*) - echo "$UNAME_MACHINE"-unknown-dragonfly"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')" - exit ;; + DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL + ;; *:*VMS:*:*) - UNAME_MACHINE=$( (uname -p) 2>/dev/null) - case "$UNAME_MACHINE" in - A*) echo alpha-dec-vms ; exit ;; - I*) echo ia64-dec-vms ; exit ;; - V*) echo vax-dec-vms ; exit ;; + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case $UNAME_MACHINE in + A*) GUESS=alpha-dec-vms ;; + I*) GUESS=ia64-dec-vms ;; + V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) - echo i386-pc-xenix - exit ;; + GUESS=i386-pc-xenix + ;; i*86:skyos:*:*) - echo "$UNAME_MACHINE"-pc-skyos"$(echo "$UNAME_RELEASE" | sed -e 's/ .*$//')" - exit ;; + SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` + GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL + ;; i*86:rdos:*:*) - echo "$UNAME_MACHINE"-pc-rdos - exit ;; - i*86:AROS:*:*) - echo "$UNAME_MACHINE"-pc-aros - exit ;; + GUESS=$UNAME_MACHINE-pc-rdos + ;; + i*86:Fiwix:*:*) + GUESS=$UNAME_MACHINE-pc-fiwix + ;; + *:AROS:*:*) + GUESS=$UNAME_MACHINE-unknown-aros + ;; x86_64:VMkernel:*:*) - echo "$UNAME_MACHINE"-unknown-esx - exit ;; + GUESS=$UNAME_MACHINE-unknown-esx + ;; amd64:Isilon\ OneFS:*:*) - echo x86_64-unknown-onefs - exit ;; + GUESS=x86_64-unknown-onefs + ;; *:Unleashed:*:*) - echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE + ;; + *:Ironclad:*:*) + GUESS=$UNAME_MACHINE-unknown-ironclad + ;; esac +# Do we have a guess based on uname results? +if test "x$GUESS" != x; then + echo "$GUESS" + exit +fi + # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < "$dummy.c" </dev/null); + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else @@ -1628,7 +1740,7 @@ main () } EOF -$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=$($dummy) && +$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. @@ -1636,7 +1748,7 @@ test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 -case "$UNAME_MACHINE:$UNAME_SYSTEM" in +case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 </dev/null || echo unknown) -uname -r = $( (uname -r) 2>/dev/null || echo unknown) -uname -s = $( (uname -s) 2>/dev/null || echo unknown) -uname -v = $( (uname -v) 2>/dev/null || echo unknown) +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` -/usr/bin/uname -p = $( (/usr/bin/uname -p) 2>/dev/null) -/bin/uname -X = $( (/bin/uname -X) 2>/dev/null) +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` -hostinfo = $( (hostinfo) 2>/dev/null) -/bin/universe = $( (/bin/universe) 2>/dev/null) -/usr/bin/arch -k = $( (/usr/bin/arch -k) 2>/dev/null) -/bin/arch = $( (/bin/arch) 2>/dev/null) -/usr/bin/oslevel = $( (/usr/bin/oslevel) 2>/dev/null) -/usr/convex/getsysinfo = $( (/usr/convex/getsysinfo) 2>/dev/null) +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" diff --git a/config.h.in b/config.h.in index 7bf98ee0..5f2d9f92 100644 --- a/config.h.in +++ b/config.h.in @@ -51,6 +51,9 @@ /* Define to 1 if you have the 'setrlimit' function. */ #undef HAVE_SETRLIMIT +/* Define to 1 if you have the 'SSL_set_ciphersuites' function. */ +#undef HAVE_SSL_SET_CIPHERSUITES + /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H diff --git a/config.sub b/config.sub index 0cbdae68..4aaae46f 100755 --- a/config.sub +++ b/config.sub @@ -1,12 +1,14 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2021 Free Software Foundation, Inc. +# Copyright 1992-2024 Free Software Foundation, Inc. -timestamp='2021-01-01' +# shellcheck disable=SC2006,SC2268,SC2162 # see below for rationale + +timestamp='2024-05-27' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or +# the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but @@ -50,7 +52,14 @@ timestamp='2021-01-01' # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. -me=$(echo "$0" | sed -e 's,.*/,,') +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + +me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS @@ -67,13 +76,13 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2021 Free Software Foundation, Inc. +Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" -Try \`$me --help' for more information." +Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do @@ -111,15 +120,16 @@ case $# in esac # Split fields of configuration type -# shellcheck disable=SC2162 +saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 + echo "Invalid configuration '$1': more than four components" >&2 exit 1 ;; *-*-*-*) @@ -131,10 +141,21 @@ case $1 in # parts maybe_os=$field2-$field3 case $maybe_os in - nto-qnx* | linux-* | uclinux-uclibc* \ - | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ - | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ - | storm-chaos* | os2-emx* | rtmk-nova*) + cloudabi*-eabi* \ + | kfreebsd*-gnu* \ + | knetbsd*-gnu* \ + | kopensolaris*-gnu* \ + | linux-* \ + | managarm-* \ + | netbsd*-eabi* \ + | netbsd*-gnu* \ + | nto-qnx* \ + | os2-emx* \ + | rtmk-nova* \ + | storm-chaos* \ + | uclinux-gnu* \ + | uclinux-uclibc* \ + | windows-* ) basic_machine=$field1 basic_os=$maybe_os ;; @@ -149,8 +170,12 @@ case $1 in esac ;; *-*) - # A lone config we happen to match not fitting any pattern case $field1-$field2 in + # Shorthands that happen to contain a single dash + convex-c[12] | convex-c3[248]) + basic_machine=$field2-convex + basic_os= + ;; decstation-3100) basic_machine=mips-dec basic_os= @@ -158,24 +183,88 @@ case $1 in *-*) # Second component is usually, but not always the OS case $field2 in - # Prevent following clause from handling this valid os + # Do not treat sunos as a manufacturer sun*os*) basic_machine=$field1 basic_os=$field2 ;; # Manufacturers - dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ - | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ - | unicom* | ibm* | next | hp | isi* | apollo | altos* \ - | convergent* | ncr* | news | 32* | 3600* | 3100* \ - | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ - | ultra | tti* | harris | dolphin | highlevel | gould \ - | cbm | ns | masscomp | apple | axis | knuth | cray \ - | microblaze* | sim | cisco \ - | oki | wec | wrs | winbond) + 3100* \ + | 32* \ + | 3300* \ + | 3600* \ + | 7300* \ + | acorn \ + | altos* \ + | apollo \ + | apple \ + | atari \ + | att* \ + | axis \ + | be \ + | bull \ + | cbm \ + | ccur \ + | cisco \ + | commodore \ + | convergent* \ + | convex* \ + | cray \ + | crds \ + | dec* \ + | delta* \ + | dg \ + | digital \ + | dolphin \ + | encore* \ + | gould \ + | harris \ + | highlevel \ + | hitachi* \ + | hp \ + | ibm* \ + | intergraph \ + | isi* \ + | knuth \ + | masscomp \ + | microblaze* \ + | mips* \ + | motorola* \ + | ncr* \ + | news \ + | next \ + | ns \ + | oki \ + | omron* \ + | pc533* \ + | rebel \ + | rom68k \ + | rombug \ + | semi \ + | sequent* \ + | siemens \ + | sgi* \ + | siemens \ + | sim \ + | sni \ + | sony* \ + | stratus \ + | sun \ + | sun[234]* \ + | tektronix \ + | tti* \ + | ultra \ + | unicom* \ + | wec \ + | winbond \ + | wrs) basic_machine=$field1-$field2 basic_os= ;; + zephyr*) + basic_machine=$field1-unknown + basic_os=$field2 + ;; *) basic_machine=$field1 basic_os=$field2 @@ -256,26 +345,6 @@ case $1 in basic_machine=arm-unknown basic_os=cegcc ;; - convex-c1) - basic_machine=c1-convex - basic_os=bsd - ;; - convex-c2) - basic_machine=c2-convex - basic_os=bsd - ;; - convex-c32) - basic_machine=c32-convex - basic_os=bsd - ;; - convex-c34) - basic_machine=c34-convex - basic_os=bsd - ;; - convex-c38) - basic_machine=c38-convex - basic_os=bsd - ;; cray) basic_machine=j90-cray basic_os=unicos @@ -698,15 +767,26 @@ case $basic_machine in vendor=dec basic_os=tops20 ;; - delta | 3300 | motorola-3300 | motorola-delta \ - | 3300-motorola | delta-motorola) + delta | 3300 | delta-motorola | 3300-motorola | motorola-delta | motorola-3300) cpu=m68k vendor=motorola ;; - dpx2*) + # This used to be dpx2*, but that gets the RS6000-based + # DPX/20 and the x86-based DPX/2-100 wrong. See + # https://oldskool.silicium.org/stations/bull_dpx20.htm + # https://www.feb-patrimoine.com/english/bull_dpx2.htm + # https://www.feb-patrimoine.com/english/unix_and_bull.htm + dpx2 | dpx2[23]00 | dpx2[23]xx) cpu=m68k vendor=bull - basic_os=sysv3 + ;; + dpx2100 | dpx21xx) + cpu=i386 + vendor=bull + ;; + dpx20) + cpu=rs6000 + vendor=bull ;; encore | umax | mmax) cpu=ns32k @@ -769,22 +849,22 @@ case $basic_machine in vendor=hp ;; i*86v32) - cpu=$(echo "$1" | sed -e 's/86.*/86/') + cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) - cpu=$(echo "$1" | sed -e 's/86.*/86/') + cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) - cpu=$(echo "$1" | sed -e 's/86.*/86/') + cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) - cpu=$(echo "$1" | sed -e 's/86.*/86/') + cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; @@ -821,18 +901,6 @@ case $basic_machine in next | m*-next) cpu=m68k vendor=next - case $basic_os in - openstep*) - ;; - nextstep*) - ;; - ns2*) - basic_os=nextstep2 - ;; - *) - basic_os=nextstep3 - ;; - esac ;; np1) cpu=np1 @@ -917,16 +985,17 @@ case $basic_machine in ;; leon-*|leon[3-9]-*) cpu=sparc - vendor=$(echo "$basic_machine" | sed 's/-.*//') + vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) - # shellcheck disable=SC2162 + saved_IFS=$IFS IFS="-" read cpu vendor <&2 + echo "Invalid configuration '$1': machine '$cpu-$vendor' not recognized" 1>&2 exit 1 ;; esac @@ -1280,38 +1491,44 @@ esac # Decode manufacturer-specific aliases for certain operating systems. -if test x$basic_os != x +if test x"$basic_os" != x then -# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just +# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. +obj= case $basic_os in gnu/linux*) kernel=linux - os=$(echo $basic_os | sed -e 's|gnu/linux|gnu|') + os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 - os=$(echo $basic_os | sed -e 's|os2-emx|emx|') + os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto - os=$(echo $basic_os | sed -e 's|nto-qnx|qnx|') + os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) - # shellcheck disable=SC2162 + saved_IFS=$IFS IFS="-" read kernel os <&2 + fi + ;; *) - echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2 + echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2 + exit 1 + ;; +esac + +case $obj in + aout* | coff* | elf* | pe*) + ;; + '') + # empty is fine + ;; + *) + echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2 + exit 1 + ;; +esac + +# Here we handle the constraint that a (synthetic) cpu and os are +# valid only in combination with each other and nowhere else. +case $cpu-$os in + # The "javascript-unknown-ghcjs" triple is used by GHC; we + # accept it here in order to tolerate that, but reject any + # variations. + javascript-ghcjs) + ;; + javascript-* | *-ghcjs) + echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. -case $kernel-$os in - linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* ) +case $kernel-$os-$obj in + linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \ + | linux-mlibc*- | linux-musl*- | linux-newlib*- \ + | linux-relibc*- | linux-uclibc*- | linux-ohos*- ) ;; - uclinux-uclibc* ) + uclinux-uclibc*- | uclinux-gnu*- ) ;; - -dietlibc* | -newlib* | -musl* | -uclibc* ) + managarm-mlibc*- | managarm-kernel*- ) + ;; + windows*-msvc*-) + ;; + -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \ + | -uclibc*- ) # These are just libc implementations, not actual OSes, and thus # require a kernel. - echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 + echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2 + exit 1 + ;; + -kernel*- ) + echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2 exit 1 ;; - kfreebsd*-gnu* | kopensolaris*-gnu*) + *-kernel*- ) + echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2 + exit 1 ;; - nto-qnx*) + *-msvc*- ) + echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2 + exit 1 ;; - os2-emx) + kfreebsd*-gnu*- | knetbsd*-gnu*- | netbsd*-gnu*- | kopensolaris*-gnu*-) + ;; + vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-) + ;; + nto-qnx*-) ;; - *-eabi* | *-gnueabi*) + os2-emx-) ;; - -*) + rtmk-nova-) + ;; + *-eabi*- | *-gnueabi*-) + ;; + none--*) + # None (no kernel, i.e. freestanding / bare metal), + # can be paired with an machine code file format + ;; + -*-) # Blank kernel with real OS is always fine. ;; - *-*) - echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 + --*) + # Blank kernel and OS with real machine code file format is always fine. + ;; + *-*-*) + echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2 exit 1 ;; esac @@ -1774,7 +2273,7 @@ case $vendor in *-riscix*) vendor=acorn ;; - *-sunos*) + *-sunos* | *-solaris*) vendor=sun ;; *-cnk* | *-aix*) @@ -1844,7 +2343,7 @@ case $vendor in ;; esac -echo "$cpu-$vendor-${kernel:+$kernel-}$os" +echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}" exit # Local variables: diff --git a/configure b/configure index a1c24222..07e27f33 100755 --- a/configure +++ b/configure @@ -642,6 +642,14 @@ ac_includes_default="\ ac_header_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS +TLS_C +LIBTLS_LIBS +LIBTLS_CFLAGS +GNUTLS_LIBS +GNUTLS_CFLAGS +OPENSSL_LDFLAGS +OPENSSL_LIBS +OPENSSL_INCLUDES DPATH IRCDGRP IRCDOWN @@ -743,6 +751,8 @@ with_dpath with_cpath with_lpath with_maxcon +with_openssl +with_tls ' ac_precious_vars='build_alias host_alias @@ -756,7 +766,11 @@ PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR YACC -YFLAGS' +YFLAGS +GNUTLS_CFLAGS +GNUTLS_LIBS +LIBTLS_CFLAGS +LIBTLS_LIBS' # Initialize some variables set by options. @@ -1407,6 +1421,8 @@ Optional Packages: --with-cpath=file Set server configuration file --with-lpath=file Set the debugging log file --with-maxcon=maxcon Maximum number of connections server will accept + --with-openssl=DIR root of the OpenSSL directory + --with-tls=library TLS library to use (none, openssl, gnutls, libtls) Some influential environment variables: CC C compiler command @@ -1427,6 +1443,12 @@ Some influential environment variables: YFLAGS The list of arguments that will be passed by default to $YACC. This script will default YFLAGS to the empty string to avoid a default value of '-d' given by some make applications. + GNUTLS_CFLAGS + C compiler flags for GNUTLS, overriding pkg-config + GNUTLS_LIBS linker flags for GNUTLS, overriding pkg-config + LIBTLS_CFLAGS + C compiler flags for LIBTLS, overriding pkg-config + LIBTLS_LIBS linker flags for LIBTLS, overriding pkg-config Use these variables to override the choices made by 'configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -7755,6 +7777,563 @@ printf "%s\n" "$unet_cv_with_maxcon" >&6; } printf "%s\n" "#define MAXCONNECTIONS $unet_cv_with_maxcon" >>confdefs.h + + found=false + +# Check whether --with-openssl was given. +if test ${with_openssl+y} +then : + withval=$with_openssl; + case "$withval" in + "" | y | ye | yes | n | no) + as_fn_error $? "Invalid --with-openssl value" "$LINENO" 5 + ;; + *) ssldirs="$withval" + ;; + esac + +else case e in #( + e) + # if pkg-config is installed and openssl has installed a .pc file, + # then use that information and don't search ssldirs + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_PKG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$PKG_CONFIG"; then + ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_PKG_CONFIG="${ac_tool_prefix}pkg-config" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +PKG_CONFIG=$ac_cv_prog_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +printf "%s\n" "$PKG_CONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_PKG_CONFIG"; then + ac_ct_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_PKG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$ac_ct_PKG_CONFIG"; then + ac_cv_prog_ac_ct_PKG_CONFIG="$ac_ct_PKG_CONFIG" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_PKG_CONFIG="pkg-config" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_PKG_CONFIG=$ac_cv_prog_ac_ct_PKG_CONFIG +if test -n "$ac_ct_PKG_CONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_PKG_CONFIG" >&5 +printf "%s\n" "$ac_ct_PKG_CONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_ct_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_prog_PKG_CONFIG" +fi + + if test x"$PKG_CONFIG" != x""; then + OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null` + if test $? = 0; then + OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null` + OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null` + found=true + fi + fi + + # no such luck; use some default ssldirs + if ! $found; then + ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" + fi + + ;; +esac +fi + + + + # note that we #include , so the OpenSSL headers have to be in + # an 'openssl' subdirectory + + if ! $found; then + OPENSSL_INCLUDES= + for ssldir in $ssldirs; do + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for include/openssl/ssl.h in $ssldir" >&5 +printf %s "checking for include/openssl/ssl.h in $ssldir... " >&6; } + if test -f "$ssldir/include/openssl/ssl.h"; then + OPENSSL_INCLUDES="-I$ssldir/include" + OPENSSL_LDFLAGS="-L$ssldir/lib" + OPENSSL_LIBS="-lssl -lcrypto" + found=true + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + break + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + done + + # if the file wasn't found, well, go ahead and try the link anyway -- maybe + # it will just work! + fi + + # try the preprocessor and linker with our new flags, + # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether compiling and linking against OpenSSL works" >&5 +printf %s "checking whether compiling and linking against OpenSSL works... " >&6; } + echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ + "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&5 + + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + save_CPPFLAGS="$CPPFLAGS" + LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" + LIBS="$OPENSSL_LIBS $LIBS" + CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main (void) +{ +SSL_new(NULL) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + + +else case e in #( + e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + : + ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + + + + + + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnutls" >&5 +printf %s "checking for gnutls... " >&6; } + +if test -n "$GNUTLS_CFLAGS"; then + pkg_cv_GNUTLS_CFLAGS="$GNUTLS_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnutls") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GNUTLS_CFLAGS=`$PKG_CONFIG --cflags "gnutls" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$GNUTLS_LIBS"; then + pkg_cv_GNUTLS_LIBS="$GNUTLS_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnutls") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GNUTLS_LIBS=`$PKG_CONFIG --libs "gnutls" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + GNUTLS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnutls" 2>&1` + else + GNUTLS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnutls" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$GNUTLS_PKG_ERRORS" >&5 + + : +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + : +else + GNUTLS_CFLAGS=$pkg_cv_GNUTLS_CFLAGS + GNUTLS_LIBS=$pkg_cv_GNUTLS_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a TLS library" >&5 +printf %s "checking for a TLS library... " >&6; } + +# Check whether --with-tls was given. +if test ${with_tls+y} +then : + withval=$with_tls; unet_cv_with_tls=$with_tls +else case e in #( + e) if test ${unet_cv_with_tls+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) unet_cv_with_tls=yes ;; +esac +fi + ;; +esac +fi + +TLS_C="" + +if test x"$unet_cv_with_tls" = xyes ; then + if test x"$OPENSSL_LIBS" != x ; then + unet_cv_with_tls=openssl + fi +fi +if test x"$unet_cv_with_tls" = xyes ; then + if test x"$GNUTLS_LIBS" != x ; then + unet_cv_with_tls=gnutls + fi +fi +if test x"$unet_cv_with_tls" = xyes ; then + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libtls" >&5 +printf %s "checking for libtls... " >&6; } + +if test -n "$LIBTLS_CFLAGS"; then + pkg_cv_LIBTLS_CFLAGS="$LIBTLS_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtls\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libtls") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBTLS_CFLAGS=`$PKG_CONFIG --cflags "libtls" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$LIBTLS_LIBS"; then + pkg_cv_LIBTLS_LIBS="$LIBTLS_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtls\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libtls") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBTLS_LIBS=`$PKG_CONFIG --libs "libtls" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + LIBTLS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libtls" 2>&1` + else + LIBTLS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libtls" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$LIBTLS_PKG_ERRORS" >&5 + + + ac_fn_c_check_header_compile "$LINENO" "tls.h" "ac_cv_header_tls_h" "$ac_includes_default" +if test "x$ac_cv_header_tls_h" = xyes +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tls_init in -ltls" >&5 +printf %s "checking for tls_init in -ltls... " >&6; } +if test ${ac_cv_lib_tls_tls_init+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS +LIBS="-ltls $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char tls_init (void); +int +main (void) +{ +return tls_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_tls_tls_init=yes +else case e in #( + e) ac_cv_lib_tls_tls_init=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tls_tls_init" >&5 +printf "%s\n" "$ac_cv_lib_tls_tls_init" >&6; } +if test "x$ac_cv_lib_tls_tls_init" = xyes +then : + + unet_cv_with_tls=libtls + +fi + + +fi + + +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + + ac_fn_c_check_header_compile "$LINENO" "tls.h" "ac_cv_header_tls_h" "$ac_includes_default" +if test "x$ac_cv_header_tls_h" = xyes +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tls_init in -ltls" >&5 +printf %s "checking for tls_init in -ltls... " >&6; } +if test ${ac_cv_lib_tls_tls_init+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS +LIBS="-ltls $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char tls_init (void); +int +main (void) +{ +return tls_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_tls_tls_init=yes +else case e in #( + e) ac_cv_lib_tls_tls_init=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tls_tls_init" >&5 +printf "%s\n" "$ac_cv_lib_tls_tls_init" >&6; } +if test "x$ac_cv_lib_tls_tls_init" = xyes +then : + + unet_cv_with_tls=libtls + +fi + + +fi + + +else + LIBTLS_CFLAGS=$pkg_cv_LIBTLS_CFLAGS + LIBTLS_LIBS=$pkg_cv_LIBTLS_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + + unet_cv_with_tls=libtls + +fi +fi + +case x"$unet_cv_with_tls" in +xopenssl) + CFLAGS="$CFLAGS $OPENSSL_CFLAGS" + LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" + LIBS="$LIBS $OPENSSL_LIBS" + TLS_C="tls_openssl.c" + ;; +xgnutls) + CFLAGS="$CFLAGS $GNUTLS_CFLAGS" + LDFLAGS="$LDFLAGS $GNUTLS_LDFLAGS" + LIBS="$LIBS $GNUTLS_LIBS" + TLS_C="tls_gnutls.c" + ;; +xlibtls) + CFLAGS="$CFLAGS $LIBTLS_CFLAGS" + LDFLAGS="$LDFLAGS $LIBTLS_LDFLAGS" + LIBS="$LIBS $LIBTLS_LIBS" + TLS_C="tls_libtls.c" + ;; +xyes|xno) + unet_cv_with_tls="none" + TLS_C="tls_none.c" + ;; +esac +if test x"$TLS_C" = x ; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Unknown TLS library $unet_cv_with_tls" >&5 +printf "%s\n" "$as_me: WARNING: Unknown TLS library $unet_cv_with_tls" >&2;} + TLS_C="tls_none.c" +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $unet_cv_with_tls" >&5 +printf "%s\n" "$unet_cv_with_tls" >&6; } + + +if test x"$unet_cv_with_tls" = xopenssl ; then + ac_fn_c_check_func "$LINENO" "SSL_set_ciphersuites" "ac_cv_func_SSL_set_ciphersuites" +if test "x$ac_cv_func_SSL_set_ciphersuites" = xyes +then : + printf "%s\n" "#define HAVE_SSL_SET_CIPHERSUITES 1" >>confdefs.h + +fi + +fi + ac_config_files="$ac_config_files Makefile ircd/Makefile ircd/test/Makefile" cat >confcache <<\_ACEOF @@ -9062,6 +9641,7 @@ ircu is now hopefully configured for your system. CPath: $unet_cv_with_cpath LPath: $unet_cv_with_lpath Maximum connections: $unet_cv_with_maxcon + TLS implementation: $unet_cv_with_tls poll() engine: $unet_cv_enable_poll kqueue() engine: $unet_cv_enable_kqueue diff --git a/configure.ac b/configure.ac index a33b70ec..dd613f9f 100644 --- a/configure.ac +++ b/configure.ac @@ -712,6 +712,8 @@ AC_MSG_RESULT([$unet_cv_with_maxcon]) AC_DEFINE_UNQUOTED(MAXCONNECTIONS, $unet_cv_with_maxcon, [Maximum number of network connections]) +unet_TLS + dnl Finally really generate all output files: AC_CONFIG_FILES([Makefile ircd/Makefile ircd/test/Makefile], [echo timestamp > stamp-h]) @@ -735,6 +737,7 @@ ircu is now hopefully configured for your system. CPath: $unet_cv_with_cpath LPath: $unet_cv_with_lpath Maximum connections: $unet_cv_with_maxcon + TLS implementation: $unet_cv_with_tls poll() engine: $unet_cv_enable_poll kqueue() engine: $unet_cv_enable_kqueue diff --git a/doc/example.conf b/doc/example.conf index 7d881228..0fbe5963 100644 --- a/doc/example.conf +++ b/doc/example.conf @@ -60,6 +60,8 @@ # dns vhost = "ipv6vhost"; # dns server = "ipaddress"; # dns server = "ipaddress2"; +# tls certfile = "ircd.pem"; +# tls keyfile = "ircd.key"; # }; # # If present, must contain a valid address in dotted @@ -84,6 +86,12 @@ # address, and the default DNS servers are read from /etc/resolv.conf. # In most cases, you do not need to specify either the dns vhost or # the dns server. +# +# The TLS certfile and keyfile contain, respectively, the public key +# (and associated signatures for authenticating the public key) and the +# private key for the server. Both must be present, and name valid +# files, for the server to establish or accept new TLS-protected +# connections. General { name = "London.UK.Eu.UnderNet.org"; description = "University of London, England"; @@ -272,6 +280,7 @@ Class { # ip = "user@ip"; # password = "password"; # class = "classname"; +# tls fingerprint = "tls-fingerprint-hex"; # }; # # Technical description (for examples, see below): @@ -358,6 +367,17 @@ Client maxlinks = 5; }; +# You may restrict a Client connection to using a TLS client certificate +# with a particular fingerprint. The fingerprint is an SHA-256 digest, +# so must be 64 hexadecimal characters long. If a password is also +# listed, both certificate and password must satisfy the configuration. +Client { + host = "*@*"; + ip = "*@*"; + class = "Other"; + tls fingerprint = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; +} + # You can put an expression in the maxlinks value, which will make ircd # only accept a client when the total number of connections to the network # from the same IP number doesn't exceed this number. @@ -564,6 +584,9 @@ Kill # maxhops = 2; # hub = "*.eu.undernet.org"; # autoconnect = no; +# tls = no; +# tls fingerprint = "tls-fingerprint-hex"; +# tls ciphers = ""; # }; # # The "port" field defines the default port the server tries to connect @@ -583,6 +606,13 @@ Kill # be introduced by a hub; the element 'hub;' is an alias for # 'hub = "*";'. # +# The "tls" field defines whether TLS is required for connections to or +# from this server. If "tls = yes", then TLS fingerprint and ciphers +# are used. If "tls fingerprint" is present, the other server must use +# a certificate with that fingerprint. If "tls ciphers" is present, it +# is given to the TLS library to restrict or prioritize particular +# algorithms. (See TLS_CIPHERS in readme.features for details.) +# # Our primary uplink. Connect { name = "Amsterdam.NL.Eu.UnderNet.org"; @@ -655,6 +685,7 @@ CRULE # name = "opername"; # password = "encryptedpass"; # class = "classname"; +# tls fingerprint = "tls-fingerprint-hex"; # # You can also set any operator privilege; see the Class block # # documentation for details. A privilege defined for a single # # Operator will override the privilege settings for the Class @@ -667,6 +698,11 @@ CRULE # mechanisms. If you use a password format that is NOT generated by # umkpasswd, ircu will not recognize the oper's password. # +# If the tls fingerprint field is present, the client must be using TLS +# with a certificate that has that fingerprint (in addition to any +# checks for hostname or IP and password by the rest of the Operator +# block). +# # All privileges are shown with their default values; if you wish to # override defaults, you should set only those privileges for the # operator. Listing defaulted privileges just makes things harder to @@ -718,10 +754,15 @@ Operator { # server = yes; # # Setting to yes makes the port "hidden" from stats. # hidden = yes; +# # Setting to yes makes the port a TLS-only port. +# tls = yes; # # Setting to yes makes this for webirc clients only. # # If the head-in-sand (HIS) webirc features are on, you probably # # want WebIRC ports to also be hidden. # WebIRC = yes; +# # Setting tls ciphers affects which TLS cipher suites are allowed on +# # this port. See TLS_CIPHERS in readme.features for more details. +# tls ciphers = ""; # }; # # The port and vhost lines allow you to specify one or both of "ipv4" @@ -763,10 +804,12 @@ Port { port = 6666; }; -# This is a hidden client port, listening on 168.8.21.107. +# This is a hidden client port, listening on 168.8.21.107, that starts +# each connection with TLS negotiation. Port { vhost = "168.8.21.107"; hidden = yes; + tls = yes; port = 7000; }; @@ -977,6 +1020,10 @@ features # "HIS_SERVERINFO" = "The Undernet Underworld"; # "HIS_URLSERVERS" = "http://www.undernet.org/servers.php"; # "URLREG" = "http://cservice.undernet.org/live/"; +# TLS_CACERTFILE" = "ircd-ca.pem"; +# "TLS_CACERTDIR" = "/etc/ssl/certs"; +# "TLS_CIPHERS" = ""; +# "TLS_ALLOW_SELFSIGNED" = "TRUE"; }; # Well, you have now reached the end of this sample configuration diff --git a/doc/readme.features b/doc/readme.features index a9fc01c3..cb39373b 100644 --- a/doc/readme.features +++ b/doc/readme.features @@ -137,6 +137,7 @@ It's used for providing promotional space to providers as per CFV-202 KILL_IPMISMATCH * Type: boolean + * Default: FALSE When a client connects to your server, the IP address of the client is @@ -927,6 +928,112 @@ passwords, respectively) on channels where they are marked as channel managers. This feature must be disabled until all servers on the network are able to interpret and handle these modes correctly. +TLS_CACERTFILE + * Type: string + * Default: "" + +This optionally names a file that contains public keys for certificate +authorities (CAs) that are trusted to sign keys for clients and servers +connected to this server. Certificates in this file take precedence +over those in TLS_CACERTDIR. + +TLS_CACERTDIR + * Type: string + * Default: "" + +This optionally names a directory that contains public keys for +certificate authorities (CAs) that are trusted to sign keys for clients +and servers connected to this server. + +TLS_CIPHERS + * Type: string + * Default: "" + +This specifies the default list of ciphers to use. This list is used +for client connections that use STARTTLS, for outbound connections to +servers with no "tls ciphers" directive in their Connect blocks, and for +inbound connections on TLS-only ports with no "tls ciphers" directive in +their Port blocks. + +This cipher list is interpreted by, and thus depends on, the TLS library +in use: + + - For all libraries, an empty string represents use of the library's + default cipher suites. + - For OpenSSL, it is parsed as "L1 L2" (two lists, separated by spaces) + where L1 is used for TLSv1.2 and below (with SSL_set_cipher_list()) + and L2 is used for TLSv1.3 (with SSL_set_ciphersuites()). + - For GnuTLS, it is parsed as a "priority string" by the function + gnutls_priority_init() and then applied to sessions. + - For OpenBSD's libtls, it is passed to tls_config_set_ciphers(). + +TLS_SSLV2 + * Type: boolean + * Default: FALSE + +This controls whether SSLv2 connections are supported. DO NOT USE SSLv2 +unless you are aware of, and willing to accept, the serious security +weaknesses of the SSLv2 protocol. + +NOTE: This feature only affects ircu2 when using OpenSSL. gnutls and +libtls have no support for SSLv2. + +TLS_SSLV3 + * Type: boolean + * Default: FALSE + +This controls whether SSLv3 connections are supported. DO NOT USE SSLv3 +unless you are aware of, and willing to accept, the serious security +weaknesses of the SSLv3 protocol. + +NOTE: This feature only affects ircu2 when using OpenSSL. libtls has +no support for SSLv2. For gnutls, add "-VERS-SSL3.0" to TLS_CIPHERS. + +TLS_V1P0 + * Type: boolean + * Default: FALSE (except for gnutls, which uses TRUE) + +This controls whether TLS 1.0 connections are supported. This is +strongly discouraged in favor of TLS 1.1 and later because of security +weaknesses in CBC modes of operation under TLS 1.1. + +NOTE: This feature only affects ircu2 when using OpenSSL or libtls. For +gnutls, add "-VERS-TLS1.0" to TLS_CIPHERS. + +TLS_V1P1 + * Type: boolean + * Default: TRUE + +This controls whether TLS 1.1 connections are supported. In most cases, +TLS 1.2 is strictly preferable to TLS 1.1, so a server might want to +disable TLS 1.1. + +NOTE: This feature only affects ircu2 when using OpenSSL or libtls. For +gnutls, add "-VERS-TLS1.1" to TLS_CIPHERS. + +TLS_V1P2 + * Type: boolean + * Default: TRUE + +This controls whether TLS 1.2 connections are supported. + +NOTE: This feature only affects ircu2 when using OpenSSL or libtls. For +gnutls, add "-VERS-TLS1.2" to TLS_CIPHERS. + +TLS_V1P3 + * Type: boolean + * Default: TRUE + +This controls whether TLS 1.3 connections are supported. This offers a +number of minor security improvements over TLS 1.2, but is incompatible +with some proxies, so it may break connections. At the time of writing +this documentation (December 2019), not all deployed TLS libraries +support TLS 1.3; this feature setting is effectively false for such +libraries. + +NOTE: This feature only affects ircu2 when using OpenSSL or libtls. For +gnutls, add "-VERS-TLS1.3" to TLS_CIPHERS. + ZANNELS * Type: boolean * Default: FALSE diff --git a/include/channel.h b/include/channel.h index 50b6444d..ab16b64c 100644 --- a/include/channel.h +++ b/include/channel.h @@ -114,15 +114,16 @@ struct Client; #define MODE_APASS 0x200000 #define MODE_WASDELJOINS 0x400000 /**< Not DELJOINS, but some joins * pending */ -#define MODE_NOPARTMSGS 0x800000 /**< +P No part messages */ +#define MODE_NOPARTMSGS 0x800000 /**< +P No part messages */ #define MODE_MODERATENOREG 0x1000000 /**< +M Moderate unauthed users */ +#define MODE_TLSONLY 0x2000000 /**< +Z TLS users only */ /** mode flags which take another parameter (With PARAmeterS) */ #define MODE_WPARAS (MODE_CHANOP|MODE_VOICE|MODE_BAN|MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS) /** Available Channel modes */ -#define infochanmodes feature_bool(FEAT_OPLEVELS) ? "AbiklmnopstUvrDdRcCPM" : "biklmnopstvrDdRcCPM" +#define infochanmodes feature_bool(FEAT_OPLEVELS) ? "AbiklmnopstUvrDdRcCPMZ" : "biklmnopstvrDdRcCPMZ" /** Available Channel modes that take parameters */ #define infochanmodeswithparams feature_bool(FEAT_OPLEVELS) ? "AbkloUv" : "bklov" diff --git a/include/client.h b/include/client.h index 92e4816c..650cfe38 100644 --- a/include/client.h +++ b/include/client.h @@ -93,7 +93,7 @@ typedef unsigned long flagpage_t; #define FlagClr(set,flag) ((set)->bits[FLAGSET_INDEX(flag)] &= ~FLAGSET_MASK(flag)) /** String containing valid user modes, in no particular order. */ -#define infousermodes "diOoswkgx" +#define infousermodes "diOoswkgxz" /** Operator privileges. */ enum Priv @@ -158,6 +158,8 @@ enum Flag FLAG_BURST_ACK, /**< Server is waiting for eob ack */ FLAG_IPCHECK, /**< Added or updated IPregistry data */ FLAG_IAUTH_STATS, /**< Wanted IAuth statistics */ + FLAG_NEGOTIATING_TLS, /**< TLS negotation ongoing */ + FLAG_LOCOP, /**< Local operator -- SRB */ FLAG_SERVNOTICE, /**< server notices such as kill */ FLAG_OPER, /**< Operator */ @@ -169,6 +171,7 @@ enum Flag FLAG_DEBUG, /**< send global debug/anti-hack info */ FLAG_ACCOUNT, /**< account name has been set */ FLAG_HIDDENHOST, /**< user's host is hidden */ + FLAG_TLS, /**< user is using TLS */ FLAG_LAST_FLAG, /**< number of flags */ FLAG_LOCAL_UMODES = FLAG_LOCOP, /**< First local mode flag */ FLAG_GLOBAL_UMODES = FLAG_OPER /**< First global mode flag */ @@ -236,6 +239,8 @@ struct Connection capset_t con_active; /**< Active capabilities (to us) */ struct AuthRequest* con_auth; /**< Auth request for client */ const struct wline* con_wline; /**< WebIRC authorization for client */ + char* con_rexmit; /**< TLS retransmission data */ + size_t con_rexmit_len; /**, TLS retransmission length */ }; /** Magic constant to identify valid Connection structures. */ @@ -263,6 +268,7 @@ struct Client { char cli_name[HOSTLEN + 1]; /**< Unique name of the client, nick or host */ char cli_username[USERLEN + 1]; /**< Username determined by ident lookup */ char cli_info[REALLEN + 1]; /**< Free form additional client information */ + char cli_tls_fingerprint[65]; /**< TLS SHA-256 fingerprint. */ }; /** Magic constant to identify valid Client structures. */ @@ -324,6 +330,8 @@ struct Client { #define cli_info(cli) ((cli)->cli_info) /** Get client account string. */ #define cli_account(cli) (cli_user(cli) ? cli_user(cli)->account : "0") +/** Get the client's TLS fingerprint. */ +#define cli_tls_fingerprint(cli) ((cli)->cli_tls_fingerprint) /** Get number of incoming bytes queued for client. */ #define cli_count(cli) con_count(cli_connect(cli)) @@ -602,6 +610,10 @@ struct Client { #define IsHiddenHost(x) HasFlag(x, FLAG_HIDDENHOST) /** Return non-zero if the client has an active PING request. */ #define IsPingSent(x) HasFlag(x, FLAG_PINGSENT) +/** Return non-zero if the client is using TLS. */ +#define IsTLS(x) HasFlag(x, FLAG_TLS) +/** Return non-zero if the client is (re-)negotiating TLS. */ +#define IsNegotiatingTLS(x) HasFlag(x, FLAG_NEGOTIATING_TLS) /** Return non-zero if the client has operator or server privileges. */ #define IsPrivileged(x) (IsAnOper(x) || IsServer(x)) @@ -648,6 +660,10 @@ struct Client { #define SetHiddenHost(x) SetFlag(x, FLAG_HIDDENHOST) /** Mark a client as having a pending PING. */ #define SetPingSent(x) SetFlag(x, FLAG_PINGSENT) +/** Mark a client as using TLS. */ +#define SetTLS(x) SetFlag(x, FLAG_TLS) +/** Mark a client as (re-)negotiating TLS. */ +#define SetNegotiatingTLS(x) SetFlag(x, FLAG_NEGOTIATING_TLS) /** Return non-zero if \a sptr sees \a acptr as an operator. */ #define SeeOper(sptr,acptr) (IsAnOper(acptr) && (HasPriv(acptr, PRIV_DISPLAY) \ @@ -683,6 +699,8 @@ struct Client { #define ClearPingSent(x) ClrFlag(x, FLAG_PINGSENT) /** Clear the client's HUB flag. */ #define ClearHub(x) ClrFlag(x, FLAG_HUB) +/** Mark a client's TLS negotation as complete. */ +#define ClearNegotiatingTLS(x) ClrFlag(x, FLAG_NEGOTIATING_TLS) /* free flags */ #define FREEFLAG_SOCKET 0x0001 /**< socket needs to be freed */ diff --git a/include/ircd_events.h b/include/ircd_events.h index f8148a88..ddcbab3a 100644 --- a/include/ircd_events.h +++ b/include/ircd_events.h @@ -104,6 +104,7 @@ struct Socket { enum SocketState s_state; /**< state socket's in */ unsigned int s_events; /**< events socket is interested in */ int s_fd; /**< file descriptor for socket */ + void* s_tls; /**< TLS state for socket */ }; #define SOCK_EVENT_READABLE 0x0001 /**< interested in readable */ @@ -132,6 +133,8 @@ struct Socket { #define s_ed_ptr(sock) ((sock)->s_header.gh_engdata.ed_ptr) /** Retrieve whether the Socket \a sock is active. */ #define s_active(sock) ((sock)->s_header.gh_flags & GEN_ACTIVE) +/** Retrieve TLS context for \a sock. */ +#define s_tls(sock) ((sock)->s_tls) /** Signal event generator. */ struct Signal { diff --git a/include/ircd_features.h b/include/ircd_features.h index 10167947..c9ce9989 100644 --- a/include/ircd_features.h +++ b/include/ircd_features.h @@ -100,6 +100,11 @@ enum Feature { FEAT_IRCD_RES_TIMEOUT, FEAT_AUTH_TIMEOUT, FEAT_ANNOUNCE_INVITES, + FEAT_TLS_CACERTFILE, + FEAT_TLS_CACERTDIR, + FEAT_TLS_CIPHERS, + FEAT_TLS_ALLOW_SELFSIGNED, + FEAT_TLS_BURST_FINGERPRINT, /* features that affect all operators */ FEAT_CONFIG_OPERCMDS, diff --git a/include/ircd_tls.h b/include/ircd_tls.h new file mode 100644 index 00000000..087a6e9d --- /dev/null +++ b/include/ircd_tls.h @@ -0,0 +1,150 @@ +/* + * IRC - Internet Relay Chat, include/ircd_tls.h + * Copyright (C) 2019 Michael Poole + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/** @file + * @brief Functions for handling TLS-protected connections. + */ +#ifndef INCLUDED_ircd_tls_h +#define INCLUDED_ircd_tls_h + +#include "ircd_osdep.h" + +struct Client; +struct ConfItem; +struct Listener; +struct MsgQ; +struct Socket; + +/** Timeout for TLS handshake in seconds */ +#define TLS_HANDSHAKE_TIMEOUT 5 + +/* The following variables and functions are provided by ircu2's core + * code, not by the TLS interface. + */ + +/** ircd_tls_keyfile holds this server's private key. */ +extern char *ircd_tls_keyfile; + +/** ircd_tls_certfile holds this server's public key certificate. */ +extern char *ircd_tls_certfile; + +/* The following variables are provided by the TLS interface. */ + +/** ircd_tls_version identifies the TLS library in current use. */ +extern const char *ircd_tls_version; + +/** ircd_tls_init() initializes the TLS library. + * + * Among any other global initialization that the library needs, this + * function loads #ircd_tls_keyfile and #ircd_tls_certfile. It should + * return zero (ideally without performing other work) if either of + * those strings are null or empty. + * + * This function is idempotent; it is called both at initial startup + * and upon "REHASH s". The TLS interface code must distinguish between + * those cases as needed. + * + * \returns Zero on success, non-zero to indicate failure. + */ +int ircd_tls_init(void); + +/** ircd_tls_accept() creates an inbound TLS session. + * + * If \a listener is NULL, the client connected on a plaintext port and + * used STARTTLS. Otherwise, the client connected on a TLS-only port + * configured with \a listener. The connection uses \a . + * + * @param[in] listener Listening socket that accepted the connection. + * @param[in] fd File descriptor for new connection. + * \returns NULL on failure, otherwise a valid new TLS session. + */ +void *ircd_tls_accept(struct Listener *listener, int fd); + +/** ircd_tls_connect() creates an outbound connection to another server. + * + * \a aconf represents the Connect block for the other server, and \a fd + * is the file descriptor of a (connected but not yet used) connection + * to that server. + * + * @param[in] aconf Connect block for the server we connected to. + * @param[in] fd File descriptor connected to that server. + */ +void *ircd_tls_connect(struct ConfItem *aconf, int fd); + +/** ircd_tls_close() destroys the TLS session \a ctx, optionally passing + * \a message as an explanation. + * + * @param[in] ctx TLS session to destroy. + * @param[in] message If not null and not empty, this string is sent to + * the peer as an explanation for the connection close. (This is + * intended for use by add_connection().) + */ +void ircd_tls_close(void *ctx, const char *message); + +/** ircd_tls_listen() configures any listener-specific TLS parameters. + * \a listener->tls_ciphers is populated on entry. \a listener->tls_ctx + * may be null or may have been previously set by the TLS implementation. + * + * @param[in,out] listener Listener structure to configure. + * \returns Zero on success, non-zero to indicate failure. + */ +int ircd_tls_listen(struct Listener *listener); + +/** ircd_tls_negotiate() attempts to continue an initial TLS handshake + * for \a cptr. If the handshake completes, this function calls + * \a ClearNegotiatingTLS(cptr) and returns 1. If the handshake failed, + * this function returns -1. Otherwise it updates event flags for the + * client's socket and returns 0. + * + * @param[in] cptr Locally connected client to perform handshake for. + * \returns 1 on completed handshake, 0 on continuing handshake, -1 on + * error. + */ +int ircd_tls_negotiate(struct Client *cptr); + +/** ircd_tls_recv() performs a non-blocking receive of TLS application + * data from \a cptr into \a buf. + * + * @param[in] cptr Locally connected client to read from. + * @param[out] buf Buffer to receive application data into. + * @param[in] length Length of \a buf. + * @param[out] count_out Number of bytes actually read into \a buf. + * \returns IO_FAILURE on error, IO_BLOCKED if no data is available, or + * IO_SUCCESS if any data was read into \a buf. + */ +IOResult ircd_tls_recv(struct Client *cptr, char *buf, + unsigned int length, unsigned int *count_out); + +/** ircd_tls_sendv() performs a non-blocking send of TLS application + * data from \a buf to \a cptr. + * + * This function must accomodate changes to \a buf for successive calls + * to \a cptr. The connection's \a con_rexmit and \a con_rexmit_len + * fields are provided to support this requirement. + * + * @param[in] cptr Locally connected client to send to. + * @param[in] buf Client's message queue. + * @param[out] count_in Total number of bytes in \a buf at entry. + * @param[out] count_out Number of bytes consumed from \a buf. + * \returns IO_FAILURE on error, IO_BLOCKED if no data could be sent, or + * IO_SUCCESS if any data was written from \a buf. + */ +IOResult ircd_tls_sendv(struct Client *cptr, struct MsgQ *buf, + unsigned int *count_in, unsigned int *count_out); + +#endif /* INCLUDED_ircd_tls_h */ diff --git a/include/listener.h b/include/listener.h index 2451e40c..14db88a8 100644 --- a/include/listener.h +++ b/include/listener.h @@ -54,6 +54,8 @@ enum ListenerFlag { LISTEN_IPV6, /** Port accepts only webirc connections. */ LISTEN_WEBIRC, + /** Port uses TLS natively. */ + LISTEN_TLS, /** Sentinel for counting listener flags. */ LISTEN_LAST_FLAG }; @@ -70,6 +72,8 @@ struct Listener { unsigned char mask_bits; /**< number of bits in mask address */ int index; /**< index into poll array */ time_t last_accept; /**< last time listener accepted */ + char* tls_ciphers; /**< ciphers to use for TLS */ + void* tls_ctx; /**< TLS context for the listener */ struct irc_sockaddr addr; /**< virtual address and port */ struct irc_in_addr mask; /**< listener hostmask */ struct Socket socket_v4; /**< describe IPv4 socket to event system */ @@ -79,9 +83,11 @@ struct Listener { #define listener_server(LISTENER) FlagHas(&(LISTENER)->flags, LISTEN_SERVER) #define listener_active(LISTENER) FlagHas(&(LISTENER)->flags, LISTEN_ACTIVE) #define listener_webirc(LISTENER) FlagHas(&(LISTENER)->flags, LISTEN_WEBIRC) +#define listener_tls(LISTENER) FlagHas(&(LISTENER)->flags, LISTEN_TLS) extern void add_listener(int port, const char* vaddr_ip, const char* mask, + const char* tls_ciphers, const struct ListenerFlags *flags); extern void close_listener(struct Listener* listener); extern void close_listeners(void); diff --git a/include/msgq.h b/include/msgq.h index 409daabc..bd2c0c46 100644 --- a/include/msgq.h +++ b/include/msgq.h @@ -81,6 +81,7 @@ extern void msgq_append(struct Client *dest, struct MsgBuf *mb, const char *format, ...); extern void msgq_clean(struct MsgBuf *mb); extern void msgq_add(struct MsgQ *mq, struct MsgBuf *mb, int prio); +extern void msgq_excise(struct MsgQ *mq, const char *buf, unsigned int len); extern void msgq_count_memory(struct Client *cptr, size_t *msg_alloc, size_t *msg_used); extern void msgq_histogram(struct Client *cptr, const struct StatDesc *sd, diff --git a/include/numeric.h b/include/numeric.h index 7da37e91..31d1239a 100644 --- a/include/numeric.h +++ b/include/numeric.h @@ -388,6 +388,7 @@ extern const struct Numeric* get_error_numeric(int err); #define ERR_INVALIDUSERNAME 468 /* Undernet extension */ /* ERR_ONLYSERVERSCANCHANGE 468 Dalnet,unreal */ /* ERR_LINKSET 469 unreal */ +#define ERR_TLSONLYCHAN 469 /* Nefarious, Undernet */ /* ERR_LINKCHANNEL 470 unreal */ /* ERR_KICKEDFROMCHAN 470 aircd */ #define ERR_CHANNELISFULL 471 @@ -459,6 +460,7 @@ extern const struct Numeric* get_error_numeric(int err); ERR_WHOLIMEXCEED 523 dalnet */ #define ERR_QUARANTINED 524 /* Undernet extension -Vampire */ #define ERR_INVALIDKEY 525 /* Undernet extension */ +#define ERR_TLSCLIFINGERPRINT 532 /* Nefarious & Undernet extension */ #define ERR_NOTLOWEROPLEVEL 560 /* Undernet extension */ #define ERR_NOTMANAGER 561 /* Undernet extension */ @@ -468,7 +470,8 @@ extern const struct Numeric* get_error_numeric(int err); /* ERR_NOMANAGER_LONG 565 no longer used */ #define ERR_NOMANAGER 566 /* Undernet extension */ #define ERR_UPASS_SAME_APASS 567 /* Undernet extension */ -#define ERR_LASTERROR 568 +#define RPL_WHOISSECURE 671 /* Nefarious, Undernet */ +#define ERR_LASTERROR 692 /* RPL_LOGON 600 dalnet,unreal RPL_LOGOFF 601 dalnet,unreal diff --git a/include/s_conf.h b/include/s_conf.h index 4a2070f6..bae3b1f5 100644 --- a/include/s_conf.h +++ b/include/s_conf.h @@ -32,8 +32,14 @@ struct Message; #define CONF_OPERATOR 0x0020 /**< ConfItem describes an Operator block */ #define CONF_UWORLD 0x8000 /**< ConfItem describes a Uworld server */ +/* These flags apply to Connect blocks: */ #define CONF_AUTOCONNECT 0x0001 /**< Autoconnect to a server */ +#define CONF_CONNECT_TLS 0x0002 /**< Server connection uses TLS */ +/* These flags apply to Port blocks: */ +#define CONF_PORT_TLS 0x0001 /**< Port should use TLS */ + +/* These flags apply to UWorld blocks: */ #define CONF_UWORLD_OPER 0x0001 /**< UWorld server can remotely oper users */ /** Indicates ConfItem types that count associated clients. */ @@ -64,6 +70,8 @@ struct ConfItem char *name; /**< Name of peer */ char *hub_limit; /**< Mask that limits servers allowed behind this one. */ + char *tls_ciphers; /**< TLS cipher preference list. */ + char *tls_fingerprint; /**< Peer must have this TLS cert fingerprint. */ time_t hold; /**< Earliest time to attempt an outbound connect on this ConfItem. */ int dns_pending; /**< A dns request is pending. */ diff --git a/include/s_misc.h b/include/s_misc.h index 10939e40..3ddef25d 100644 --- a/include/s_misc.h +++ b/include/s_misc.h @@ -68,10 +68,12 @@ struct ServerStatistics { unsigned int is_ip_full; /**< client rejected: too many from IP */ unsigned int is_bad_socket; /**< client rejected: socket failure */ unsigned int is_throttled; /**< client rejected: IP connecting too fast */ + unsigned int is_bad_fingerprint; /**< client rejected: bad TLS fingerprint */ unsigned int is_not_hub; /**< server rejected: I am not a hub */ unsigned int is_crule_fail; /**< server rejected: CRULE rejected */ unsigned int is_not_server; /**< server rejected: no matching Connect block */ unsigned int is_bad_server; /**< server rejected: bad password */ + unsigned int is_wrong_server; /**< server rejected: bad TLS fingerprint */ unsigned int is_unco; /**< unknown commands */ unsigned int is_wrdi; /**< command going in wrong direction */ unsigned int is_unpf; /**< unknown prefix */ diff --git a/include/supported.h b/include/supported.h index b32289da..6dd97d70 100644 --- a/include/supported.h +++ b/include/supported.h @@ -66,8 +66,8 @@ feature_int(FEAT_CHANNELLEN), CHANNELLEN, \ (feature_bool(FEAT_LOCAL_CHANNELS) ? "#&" : "#"), "(ov)@+", "@+", \ (feature_bool(FEAT_OPLEVELS) \ - ? "b,AkU,l,imnpstrDdRcCPM" \ - : "b,k,l,imnpstrDdRcCPM"), \ + ? "b,AkU,l,imnpstrDdRcCPMZ" \ + : "b,k,l,imnpstrDdRcCPMZ"), \ "rfc1459", feature_str(FEAT_NETWORK) #endif /* INCLUDED_supported_h */ diff --git a/install-sh b/install-sh index ebc66913..b1d7a6f6 100755 --- a/install-sh +++ b/install-sh @@ -1,250 +1,541 @@ -#! /bin/sh -# +#!/bin/sh # install - install a program, script, or datafile -# This comes from X11R5 (mit/util/scripts/install.sh). + +scriptversion=2024-06-19.01; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -# Copyright 1991 by the Massachusetts Institute of Technology +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. # -# Permission to use, copy, modify, distribute, and sell this software and its -# documentation for any purpose is hereby granted without fee, provided that -# the above copyright notice appear in all copies and that both that -# copyright notice and this permission notice appear in supporting -# documentation, and that the name of M.I.T. not be used in advertising or -# publicity pertaining to distribution of the software without specific, -# written prior permission. M.I.T. makes no representations about the -# suitability of this software for any purpose. It is provided "as is" -# without express or implied warranty. +# +# FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent -# `make' implicit rules from creating a file called install from it +# 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written -# from scratch. It can only install one file at a time, a restriction -# shared with many OS's install programs. +# from scratch. + +tab=' ' +nl=' +' +IFS=" $tab$nl" +# Set DOITPROG to "echo" to test this script. -# set DOITPROG to echo to test this script +doit=${DOITPROG-} +doit_exec=${doit:-exec} -# Don't use :- since 4.3BSD and earlier shells don't like it. -doit="${DOITPROG-}" +# Put in absolute file names if you don't have them in your path; +# or use environment vars. +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} -# put in absolute paths if you don't have them in your path; or use env. vars. +posix_mkdir= -mvprog="${MVPROG-mv}" -cpprog="${CPPROG-cp}" -chmodprog="${CHMODPROG-chmod}" -chownprog="${CHOWNPROG-chown}" -chgrpprog="${CHGRPPROG-chgrp}" -stripprog="${STRIPPROG-strip}" -rmprog="${RMPROG-rm}" -mkdirprog="${MKDIRPROG-mkdir}" +# Desired mode of installed file. +mode=0755 -transformbasename="" -transform_arg="" -instcmd="$mvprog" -chmodcmd="$chmodprog 0755" -chowncmd="" -chgrpcmd="" -stripcmd="" +# Create dirs (including intermediate dirs) using mode 755. +# This is like GNU 'install' as of coreutils 8.32 (2020). +mkdir_umask=22 + +backupsuffix= +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog rmcmd="$rmprog -f" -mvcmd="$mvprog" -src="" -dst="" -dir_arg="" - -while [ x"$1" != x ]; do - case $1 in - -c) instcmd="$cpprog" - shift - continue;; - - -d) dir_arg=true - shift - continue;; - - -m) chmodcmd="$chmodprog $2" - shift - shift - continue;; - - -o) chowncmd="$chownprog $2" - shift - shift - continue;; - - -g) chgrpcmd="$chgrpprog $2" - shift - shift - continue;; - - -s) stripcmd="$stripprog" - shift - continue;; - - -t=*) transformarg=`echo $1 | sed 's/-t=//'` - shift - continue;; - - -b=*) transformbasename=`echo $1 | sed 's/-b=//'` - shift - continue;; - - *) if [ x"$src" = x ] - then - src=$1 - else - # this colon is to work around a 386BSD /bin/sh bug - : - dst=$1 - fi - shift - continue;; - esac -done +stripcmd= -if [ x"$src" = x ] -then - echo "install: no input file specified" - exit 1 -else - true -fi +src= +dst= +dir_arg= +dst_arg= -if [ x"$dir_arg" != x ]; then - dst=$src - src="" - - if [ -d $dst ]; then - instcmd=: - else - instcmd=mkdir - fi -else +copy_on_change=false +is_target_a_directory=possibly -# Waiting for this to be detected by the "$instcmd $src $dsttmp" command -# might cause directories to be created, which would be especially bad -# if $src (and thus $dsttmp) contains '*'. +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... - if [ -f $src -o -d $src ] - then - true - else - echo "install: $src does not exist" - exit 1 - fi - - if [ x"$dst" = x ] - then - echo "install: no destination specified" - exit 1 - else - true - fi +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. -# If destination is a directory, append the input filename; if your system -# does not like double slashes in filenames, you may need to add some logic +Options: + --help display this help and exit. + --version display version info and exit. - if [ -d $dst ] - then - dst="$dst"/`basename $src` - else - true - fi -fi + -c (ignored) + -C install only if different (preserve data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -p pass -p to $cpprog. + -s $stripprog installed files. + -S SUFFIX attempt to back up existing files, with suffix SUFFIX. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. -## this sed command emulates the dirname command -dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG -# Make sure that the destination directory exists. -# this part is taken from Noah Friedman's mkinstalldirs script +By default, rm is invoked with -f; when overridden with RMPROG, +it's up to you to specify -f if you want it. -# Skip lots of stat calls in the usual case. -if [ ! -d "$dstdir" ]; then -defaultIFS=' -' -IFS="${IFS-${defaultIFS}}" +If -S is not specified, no backups are attempted. -oIFS="${IFS}" -# Some sh's can't handle IFS=/ for some reason. -IFS='%' -set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` -IFS="${oIFS}" +Report bugs to . +GNU Automake home page: . +General help using GNU software: ." -pathcomp='' +while test $# -ne 0; do + case $1 in + -c) ;; -while [ $# -ne 0 ] ; do - pathcomp="${pathcomp}${1}" - shift + -C) copy_on_change=true;; - if [ ! -d "${pathcomp}" ] ; - then - $mkdirprog "${pathcomp}" - else - true - fi + -d) dir_arg=true;; - pathcomp="${pathcomp}/" -done -fi + -g) chgrpcmd="$chgrpprog $2" + shift;; -if [ x"$dir_arg" != x ] -then - $doit $instcmd $dst && + --help) echo "$usage"; exit $?;; - if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi -else + -m) mode=$2 + case $mode in + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; -# If we're going to rename the final executable, determine the name now. + -o) chowncmd="$chownprog $2" + shift;; - if [ x"$transformarg" = x ] - then - dstfile=`basename $dst` - else - dstfile=`basename $dst $transformbasename | - sed $transformarg`$transformbasename - fi + -p) cpprog="$cpprog -p";; -# don't allow the sed command to completely eliminate the filename + -s) stripcmd=$stripprog;; - if [ x"$dstfile" = x ] - then - dstfile=`basename $dst` - else - true - fi + -S) backupsuffix="$2" + shift;; -# Make a temp file name in the proper directory. + -t) + is_target_a_directory=always + dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; - dsttmp=$dstdir/#inst.$$# + -T) is_target_a_directory=never;; -# Move or copy the file name to the temp name + --version) echo "$0 (GNU Automake) $scriptversion"; exit $?;; - $doit $instcmd $src $dsttmp && + --) shift + break;; - trap "rm -f ${dsttmp}" 0 && + -*) echo "$0: invalid option: $1" >&2 + exit 1;; -# and set any options; do chmod last to preserve setuid bits + *) break;; + esac + shift +done -# If any of these fail, we abort the whole thing. If we want to -# ignore errors from any of these, just make sure not to ignore -# errors from the above "$doit $instcmd $src $dsttmp" command. +# We allow the use of options -d and -T together, by making -d +# take the precedence; this is for compatibility with GNU install. - if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && +if test -n "$dir_arg"; then + if test -n "$dst_arg"; then + echo "$0: target directory not allowed when installing a directory." >&2 + exit 1 + fi +fi -# Now rename the file to the real destination. +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call 'install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + if test $# -gt 1 || test "$is_target_a_directory" = always; then + if test ! -d "$dst_arg"; then + echo "$0: $dst_arg: Is not a directory." >&2 + exit 1 + fi + fi +fi - $doit $rmcmd -f $dstdir/$dstfile && - $doit $mvcmd $dsttmp $dstdir/$dstfile +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi -fi && +for src +do + # Protect names problematic for 'test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + # Don't chown directories that already exist. + if test $dstdir_status = 0; then + chowncmd="" + fi + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename. + if test -d "$dst"; then + if test "$is_target_a_directory" = never; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dstbase=`basename "$src"` + case $dst in + */) dst=$dst$dstbase;; + *) dst=$dst/$dstbase;; + esac + dstdir_status=0 + else + dstdir=`dirname "$dst"` + test -d "$dstdir" + dstdir_status=$? + fi + fi + + case $dstdir in + */) dstdirslash=$dstdir;; + *) dstdirslash=$dstdir/;; + esac + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + # The $RANDOM variable is not portable (e.g., dash). Use it + # here however when possible just to lower collision chance. + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + + trap ' + ret=$? + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null + exit $ret + ' 0 + + # Because "mkdir -p" follows existing symlinks and we likely work + # directly in world-writable /tmp, make sure that the '$tmpdir' + # directory is successfully created first before we actually test + # 'mkdir -p'. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibility with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null + fi + trap '' 0;; + esac + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + oIFS=$IFS + IFS=/ + set -f + set fnord $dstdir + shift + set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=${dstdirslash}_inst.$$_ + rmtmp=${dstdirslash}_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && + { test -z "$stripcmd" || { + # Create $dsttmp read-write so that cp doesn't create it read-only, + # which would cause strip to fail. + if test -z "$doit"; then + : >"$dsttmp" # No need to fork-exec 'touch'. + else + $doit touch "$dsttmp" + fi + } + } && + $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + set +f && + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # If $backupsuffix is set, and the file being installed + # already exists, attempt a backup. Don't worry if it fails, + # e.g., if mv doesn't support -f. + if test -n "$backupsuffix" && test -f "$dst"; then + $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null + fi + + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done -exit 0 +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/ircd/Makefile.in b/ircd/Makefile.in index 432c66e2..b727ca38 100644 --- a/ircd/Makefile.in +++ b/ircd/Makefile.in @@ -41,6 +41,7 @@ TOUCH = touch GREP = grep YACC = @YACC@ ENGINE_C = @ENGINE_C@ +TLS_C = @TLS_C@ @SET_MAKE@ BINDIR = @bindir@ @@ -72,6 +73,12 @@ ENGINE_SRC = \ engine_kqueue.c \ engine_select.c +TLS_SRC = \ + tls_none.c \ + tls_gnutls.c \ + tls_libtls.c \ + tls_openssl.c + CRYPTO_SRC = \ ircd_md5.c \ ircd_crypt_plain.c \ @@ -216,7 +223,7 @@ IRCD_SRC = \ whowas.c \ y.tab.c -SRC = ${IRCD_SRC} ${ENGINE_C} ${CRYPTO_SRC} +SRC = ${IRCD_SRC} ${ENGINE_C} ${TLS_C} ${CRYPTO_SRC} OBJS = ${SRC:%.c=%.o} @@ -224,7 +231,7 @@ UMKPASSWD_OBJS = ${UMKPASSWD_SRC:%.c=%.o} CONVERT_CONF_OBJS = ${CONVERT_CONF_SRC:%.c=%.o} -DEP_SRC = ${IRCD_SRC} ${ENGINE_SRC} ${CRYPTO_SRC} +DEP_SRC = ${IRCD_SRC} ${ENGINE_SRC} ${TLS_SRC} ${CRYPTO_SRC} all: ( cd ..; make -f Makefile ) @@ -386,9 +393,11 @@ client.o: client.c ../config.h ../include/client.h ../include/ircd_defs.h \ ../include/ircd_handler.h ../include/res.h ../include/capab.h \ ../include/class.h ../include/client.h ../include/ircd.h \ ../include/struct.h ../include/ircd_features.h ../include/ircd_log.h \ - ../include/ircd_reply.h ../include/list.h ../include/msgq.h \ - ../include/numeric.h ../include/s_conf.h ../include/s_debug.h \ - ../include/send.h ../include/struct.h + ../include/ircd_reply.h ../include/ircd_string.h \ + ../include/ircd_chattr.h ../include/ircd_tls.h ../include/ircd_osdep.h \ + ../include/list.h ../include/msgq.h ../include/numeric.h \ + ../include/s_conf.h ../include/s_debug.h ../include/send.h \ + ../include/struct.h crule.o: crule.c ../config.h ../include/crule.h ../include/client.h \ ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \ ../include/ircd_events.h ../include/ircd_handler.h ../include/res.h \ @@ -435,8 +444,9 @@ ircd.o: ircd.c ../config.h ../include/ircd.h ../include/struct.h \ ../include/ircd_alloc.h ../include/ircd_events.h \ ../include/ircd_features.h ../include/ircd_log.h ../include/ircd_reply.h \ ../include/ircd_signal.h ../include/ircd_string.h \ - ../include/ircd_chattr.h ../include/ircd_crypt.h ../include/jupe.h \ - ../include/list.h ../include/match.h ../include/motd.h ../include/msg.h \ + ../include/ircd_chattr.h ../include/ircd_crypt.h ../include/ircd_tls.h \ + ../include/ircd_osdep.h ../include/jupe.h ../include/list.h \ + ../include/match.h ../include/motd.h ../include/msg.h \ ../include/numeric.h ../include/numnicks.h ../include/opercmds.h \ ../include/parse.h ../include/res.h ../include/s_auth.h \ ../include/s_bsd.h ../include/s_conf.h ../include/s_debug.h \ @@ -556,9 +566,10 @@ listener.o: listener.c ../config.h ../include/listener.h \ ../include/ircd_events.h ../include/ircd_features.h \ ../include/ircd_log.h ../include/ircd_osdep.h ../include/ircd_reply.h \ ../include/ircd_snprintf.h ../include/ircd_string.h \ - ../include/ircd_chattr.h ../include/match.h ../include/numeric.h \ - ../include/s_bsd.h ../include/s_conf.h ../include/s_misc.h \ - ../include/s_stats.h ../include/send.h ../include/sys.h + ../include/ircd_chattr.h ../include/ircd_tls.h ../include/ircd_osdep.h \ + ../include/match.h ../include/numeric.h ../include/s_bsd.h \ + ../include/s_conf.h ../include/s_misc.h ../include/s_stats.h \ + ../include/send.h ../include/sys.h m_account.o: m_account.c ../config.h ../include/client.h \ ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \ ../include/ircd_events.h ../include/ircd_handler.h ../include/res.h \ @@ -722,10 +733,10 @@ m_info.o: m_info.c ../config.h ../include/client.h ../include/ircd_defs.h \ ../include/ircd_handler.h ../include/res.h ../include/capab.h \ ../include/ircd.h ../include/struct.h ../include/ircd_log.h \ ../include/ircd_reply.h ../include/ircd_string.h \ - ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \ - ../include/numnicks.h ../include/s_misc.h ../include/s_user.h \ - ../include/s_conf.h ../include/client.h ../include/send.h \ - ../include/version.h + ../include/ircd_chattr.h ../include/ircd_tls.h ../include/ircd_osdep.h \ + ../include/msg.h ../include/numeric.h ../include/numnicks.h \ + ../include/s_misc.h ../include/s_user.h ../include/s_conf.h \ + ../include/client.h ../include/send.h ../include/version.h m_invite.o: m_invite.c ../config.h ../include/channel.h \ ../include/ircd_defs.h ../include/res.h ../include/client.h \ ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \ @@ -863,11 +874,11 @@ m_oper.o: m_oper.c ../config.h ../include/client.h ../include/ircd_defs.h \ ../include/hash.h ../include/ircd.h ../include/struct.h \ ../include/ircd_alloc.h ../include/ircd_features.h ../include/ircd_log.h \ ../include/ircd_reply.h ../include/ircd_string.h \ - ../include/ircd_chattr.h ../include/ircd_crypt.h ../include/msg.h \ - ../include/numeric.h ../include/numnicks.h ../include/querycmds.h \ - ../include/ircd_features.h ../include/s_conf.h ../include/client.h \ - ../include/s_debug.h ../include/s_user.h ../include/s_misc.h \ - ../include/send.h + ../include/ircd_chattr.h ../include/ircd_tls.h ../include/ircd_osdep.h \ + ../include/ircd_crypt.h ../include/msg.h ../include/numeric.h \ + ../include/numnicks.h ../include/querycmds.h ../include/ircd_features.h \ + ../include/s_conf.h ../include/client.h ../include/s_debug.h \ + ../include/s_user.h ../include/s_misc.h ../include/send.h m_opmode.o: m_opmode.c ../config.h ../include/client.h \ ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \ ../include/ircd_events.h ../include/ircd_handler.h ../include/res.h \ @@ -952,8 +963,9 @@ m_rehash.o: m_rehash.c ../config.h ../include/client.h \ ../include/ircd_events.h ../include/ircd_handler.h ../include/res.h \ ../include/capab.h ../include/ircd.h ../include/struct.h \ ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \ - ../include/ircd_chattr.h ../include/motd.h ../include/numeric.h \ - ../include/s_conf.h ../include/client.h ../include/send.h + ../include/ircd_chattr.h ../include/ircd_tls.h ../include/ircd_osdep.h \ + ../include/motd.h ../include/numeric.h ../include/s_conf.h \ + ../include/client.h ../include/send.h m_reset.o: m_reset.c ../config.h ../include/client.h \ ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \ ../include/ircd_events.h ../include/ircd_handler.h ../include/res.h \ @@ -991,12 +1003,12 @@ m_server.o: m_server.c ../config.h ../include/client.h \ ../include/capab.h ../include/hash.h ../include/ircd.h \ ../include/struct.h ../include/ircd_log.h ../include/ircd_features.h \ ../include/ircd_reply.h ../include/ircd_string.h \ - ../include/ircd_chattr.h ../include/jupe.h ../include/list.h \ - ../include/match.h ../include/msg.h ../include/numeric.h \ - ../include/numnicks.h ../include/querycmds.h ../include/ircd_features.h \ - ../include/s_bsd.h ../include/s_conf.h ../include/client.h \ - ../include/s_debug.h ../include/s_misc.h ../include/s_serv.h \ - ../include/send.h ../include/userload.h + ../include/ircd_chattr.h ../include/ircd_tls.h ../include/ircd_osdep.h \ + ../include/jupe.h ../include/list.h ../include/match.h ../include/msg.h \ + ../include/numeric.h ../include/numnicks.h ../include/querycmds.h \ + ../include/ircd_features.h ../include/s_bsd.h ../include/s_conf.h \ + ../include/client.h ../include/s_debug.h ../include/s_misc.h \ + ../include/s_serv.h ../include/send.h ../include/userload.h m_set.o: m_set.c ../config.h ../include/client.h ../include/ircd_defs.h \ ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \ ../include/ircd_handler.h ../include/res.h ../include/capab.h \ @@ -1260,7 +1272,8 @@ s_auth.o: s_auth.c ../config.h ../include/s_auth.h \ ../include/struct.h ../include/ircd_alloc.h ../include/ircd_chattr.h \ ../include/ircd_events.h ../include/ircd_features.h \ ../include/ircd_log.h ../include/ircd_osdep.h ../include/ircd_reply.h \ - ../include/ircd_snprintf.h ../include/ircd_string.h ../include/list.h \ + ../include/ircd_snprintf.h ../include/ircd_string.h \ + ../include/ircd_tls.h ../include/ircd_osdep.h ../include/list.h \ ../include/msg.h ../include/numeric.h ../include/numnicks.h \ ../include/querycmds.h ../include/ircd_features.h ../include/random.h \ ../include/res.h ../include/s_bsd.h ../include/s_conf.h \ @@ -1274,14 +1287,15 @@ s_bsd.o: s_bsd.c ../config.h ../include/s_bsd.h ../include/client.h \ ../include/ircd_alloc.h ../include/ircd_log.h ../include/ircd_features.h \ ../include/ircd_osdep.h ../include/ircd_reply.h \ ../include/ircd_snprintf.h ../include/ircd_string.h \ - ../include/ircd_chattr.h ../include/ircd.h ../include/struct.h \ - ../include/list.h ../include/listener.h ../include/msg.h \ - ../include/msgq.h ../include/numeric.h ../include/numnicks.h \ - ../include/packet.h ../include/parse.h ../include/querycmds.h \ - ../include/ircd_features.h ../include/res.h ../include/s_auth.h \ - ../include/s_conf.h ../include/s_debug.h ../include/s_misc.h \ - ../include/s_user.h ../include/send.h ../include/struct.h \ - ../include/sys.h ../include/uping.h ../include/version.h + ../include/ircd_chattr.h ../include/ircd_tls.h ../include/ircd_osdep.h \ + ../include/ircd.h ../include/struct.h ../include/list.h \ + ../include/listener.h ../include/msg.h ../include/msgq.h \ + ../include/numeric.h ../include/numnicks.h ../include/packet.h \ + ../include/parse.h ../include/querycmds.h ../include/ircd_features.h \ + ../include/res.h ../include/s_auth.h ../include/s_conf.h \ + ../include/s_debug.h ../include/s_misc.h ../include/s_user.h \ + ../include/send.h ../include/struct.h ../include/sys.h \ + ../include/uping.h ../include/version.h s_conf.o: s_conf.c ../config.h ../include/s_conf.h ../include/client.h \ ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \ ../include/ircd_events.h ../include/ircd_handler.h ../include/res.h \ @@ -1444,6 +1458,7 @@ y.tab.o: y.tab.c ../config.h ../include/s_conf.h ../include/client.h \ ../include/ircd_features.h ../include/ircd_lexer.h ../include/ircd_log.h \ ../include/ircd_reply.h ../include/ircd_snprintf.h \ ../include/ircd_string.h ../include/list.h ../include/listener.h \ + ../include/ircd_tls.h ../include/ircd_osdep.h \ ../include/match.h ../include/motd.h ../include/numeric.h \ ../include/numnicks.h ../include/opercmds.h ../include/parse.h \ ../include/res.h ../include/s_auth.h ../include/s_bsd.h \ @@ -1463,6 +1478,28 @@ engine_kqueue.o: engine_kqueue.c ../config.h ../include/ircd_events.h \ engine_select.o: engine_select.c ../config.h ../include/ircd_events.h \ ../include/ircd.h ../include/struct.h ../include/ircd_defs.h \ ../include/ircd_log.h ../include/s_debug.h +tls_none.o: tls_none.c ../config.h ../include/ircd_tls.h \ + ../include/ircd_osdep.h ../include/client.h ../include/ircd_defs.h \ + ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \ + ../include/ircd_handler.h ../include/res.h ../include/capab.h +tls_gnutls.o: tls_gnutls.c ../config.h ../include/client.h \ + ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \ + ../include/ircd_events.h ../include/ircd_handler.h ../include/res.h \ + ../include/capab.h ../include/ircd_features.h ../include/ircd_log.h \ + ../include/ircd_string.h ../include/ircd_chattr.h ../include/ircd_tls.h \ + ../include/ircd_osdep.h ../include/listener.h ../include/s_conf.h \ + ../include/client.h +tls_libtls.o: tls_libtls.c ../config.h ../include/ircd_tls.h \ + ../include/ircd_osdep.h ../include/client.h ../include/ircd_defs.h \ + ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \ + ../include/ircd_handler.h ../include/res.h ../include/capab.h +tls_openssl.o: tls_openssl.c ../config.h ../include/client.h \ + ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \ + ../include/ircd_events.h ../include/ircd_handler.h ../include/res.h \ + ../include/capab.h ../include/ircd_alloc.h ../include/ircd_features.h \ + ../include/ircd_log.h ../include/ircd_string.h ../include/ircd_chattr.h \ + ../include/ircd_tls.h ../include/ircd_osdep.h ../include/listener.h \ + ../include/s_conf.h ../include/client.h ../include/s_debug.h ircd_md5.o: ircd_md5.c ../include/ircd_md5.h ircd_crypt_plain.o: ircd_crypt_plain.c ../config.h \ ../include/ircd_crypt.h ../include/ircd_crypt_plain.h \ diff --git a/ircd/channel.c b/ircd/channel.c index 16eacc36..e198f48a 100644 --- a/ircd/channel.c +++ b/ircd/channel.c @@ -712,6 +712,10 @@ int member_can_send_to_channel(struct Membership* member, int reveal) if (member->channel->mode.mode & (MODE_MODERATENOREG|MODE_REGONLY) && !IsAccount(member->user)) return 0; + /* If only TLS-using users may join and you're not one, you can't speak. */ + if (member->channel->mode.mode & MODE_TLSONLY && !IsTLS(member->user)) + return 0; + /* If you're banned then you can't speak either. */ if (is_banned(member)) return 0; @@ -755,6 +759,10 @@ int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int r if (chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) return 0; + /* TLS only channel and non-TLS client? */ + if ((chptr->mode.mode & MODE_TLSONLY) && !IsTLS(cptr)) + return 0; + /* .. or to a +r or +M channel when you are not logged in. */ if ((chptr->mode.mode & (MODE_REGONLY|MODE_MODERATENOREG)) && !IsAccount(cptr)) return 0; @@ -843,6 +851,8 @@ void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen, *mbuf++ = 'P'; if (chptr->mode.mode & MODE_MODERATENOREG) *mbuf++ = 'M'; + if (chptr->mode.mode & MODE_TLSONLY) + *mbuf++ = 'Z'; if (chptr->mode.limit) { *mbuf++ = 'l'; ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit); @@ -1543,6 +1553,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) MODE_NOCTCP, 'C', MODE_NOPARTMSGS, 'P', MODE_MODERATENOREG, 'M', + MODE_TLSONLY, 'Z', /* MODE_KEY, 'k', */ /* MODE_BAN, 'b', */ MODE_LIMIT, 'l', @@ -1974,7 +1985,7 @@ modebuf_mode(struct ModeBuf *mbuf, unsigned int mode) mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED | MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY | - MODE_NOCOLOR | MODE_NOCTCP | MODE_NOPARTMSGS | MODE_MODERATENOREG | + MODE_NOCOLOR | MODE_NOCTCP | MODE_NOPARTMSGS | MODE_MODERATENOREG | MODE_TLSONLY | MODE_DELJOINS | MODE_WASDELJOINS | MODE_REGISTERED); if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */ @@ -2112,6 +2123,7 @@ modebuf_extract(struct ModeBuf *mbuf, char *buf) MODE_NOCTCP, 'C', MODE_NOPARTMSGS, 'P', MODE_MODERATENOREG, 'M', + MODE_TLSONLY, 'Z', 0x0, 0x0 }; unsigned int add; @@ -3257,6 +3269,7 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, MODE_NOCTCP, 'C', MODE_NOPARTMSGS, 'P', MODE_MODERATENOREG, 'M', + MODE_TLSONLY, 'Z', MODE_ADD, '+', MODE_DEL, '-', 0x0, 0x0 diff --git a/ircd/client.c b/ircd/client.c index e861c876..6fbb2c4f 100644 --- a/ircd/client.c +++ b/ircd/client.c @@ -28,6 +28,8 @@ #include "ircd_features.h" #include "ircd_log.h" #include "ircd_reply.h" +#include "ircd_string.h" +#include "ircd_tls.h" #include "list.h" #include "msgq.h" #include "numeric.h" diff --git a/ircd/ircd.c b/ircd/ircd.c index d643fb09..89363586 100644 --- a/ircd/ircd.c +++ b/ircd/ircd.c @@ -38,6 +38,7 @@ #include "ircd_signal.h" #include "ircd_string.h" #include "ircd_crypt.h" +#include "ircd_tls.h" #include "jupe.h" #include "list.h" #include "match.h" @@ -110,6 +111,8 @@ time_t CurrentTime; /**< Updated every time we leave select( char *configfile = CPATH; /**< Server configuration file */ int debuglevel = -1; /**< Server debug level */ char *debugmode = ""; /**< Server debug level */ +char *ircd_tls_keyfile; /**< Private key file for TLS */ +char *ircd_tls_certfile; /**< Public key file for TLS */ static char *dpath = DPATH; /**< Working directory for daemon */ static char *dbg_client; /**< Client specifier for chkconf */ @@ -497,6 +500,7 @@ static void parse_command_line(int argc, char** argv) { #else printf("select()"); #endif + printf("\nTLS: %s", ircd_tls_version); printf("\nCompiled for a maximum of %d connections.\n", MAXCONNECTIONS); @@ -711,6 +715,11 @@ int main(int argc, char **argv) { return 7; } + if (ircd_tls_init()) { + log_write(LS_SYSTEM, L_CRIT, 0, "TLS initialization failed"); + return 10; + } + if (thisServer.bootopt & BOOT_CHKCONF) { if (dbg_client) conf_debug_iline(dbg_client); diff --git a/ircd/ircd_features.c b/ircd/ircd_features.c index 6410099b..3c7f4f33 100644 --- a/ircd/ircd_features.c +++ b/ircd/ircd_features.c @@ -365,6 +365,11 @@ static struct FeatureDesc { F_I(IRCD_RES_TIMEOUT, 0, 4, 0), F_I(AUTH_TIMEOUT, 0, 9, 0), F_B(ANNOUNCE_INVITES, 0, 0, 0), + F_S(TLS_CACERTFILE, FEAT_NULL | FEAT_CASE | FEAT_OPER, 0, 0), + F_S(TLS_CACERTDIR, FEAT_NULL | FEAT_CASE | FEAT_OPER, 0, 0), + F_S(TLS_CIPHERS, FEAT_NULL | FEAT_CASE | FEAT_OPER, 0, 0), + F_B(TLS_ALLOW_SELFSIGNED, 0, 1, 0), + F_B(TLS_BURST_FINGERPRINT, 0, 1, 0), /* features that affect all operators */ F_B(CONFIG_OPERCMDS, 0, 0, 0), diff --git a/ircd/ircd_lexer.c b/ircd/ircd_lexer.c index 0a9f5247..9007bcb1 100644 --- a/ircd/ircd_lexer.c +++ b/ircd/ircd_lexer.c @@ -69,7 +69,9 @@ static const struct lexer_token tokens[] = { { "b", BYTES }, { "badchan", TPRIV_BADCHAN }, { "bytes", BYTES }, + { "certfile", CERTFILE }, { "chan_limit", TPRIV_CHAN_LIMIT }, + { "ciphers", CIPHERS }, { "class", CLASS }, { "client", CLIENT }, { "connect", CONNECT }, @@ -87,6 +89,7 @@ static const struct lexer_token tokens[] = { { "fast", FAST }, { "features", FEATURES }, { "file", TFILE }, + { "fingerprint", FINGERPRINT }, { "force_local_opmode", TPRIV_FORCE_LOCAL_OPMODE }, { "force_opmode", TPRIV_FORCE_OPMODE }, { "gb", GBYTES }, @@ -107,6 +110,7 @@ static const struct lexer_token tokens[] = { { "jupe", JUPE }, { "kb", KBYTES }, { "kbytes", KBYTES }, + { "keyfile", KEYFILE }, { "kill", KILL }, { "kilobytes", KBYTES }, { "leaf", LEAF }, @@ -162,6 +166,7 @@ static const struct lexer_token tokens[] = { { "tb", TBYTES }, { "tbytes", TBYTES }, { "terabytes", TBYTES }, + { "tls", TLS }, { "unlimit_query", TPRIV_UNLIMIT_QUERY }, { "usermode", USERMODE }, { "username", USERNAME }, diff --git a/ircd/ircd_parser.y b/ircd/ircd_parser.y index 30c927ae..24c9110d 100644 --- a/ircd/ircd_parser.y +++ b/ircd/ircd_parser.y @@ -39,6 +39,7 @@ #include "ircd_reply.h" #include "ircd_snprintf.h" #include "ircd_string.h" +#include "ircd_tls.h" #include "list.h" #include "listener.h" #include "match.h" @@ -77,6 +78,7 @@ /* Now all the globals we need :/... */ int tping, tconn, maxflood, maxlinks, sendq, port, invert, stringno, flags; char *name, *pass, *host, *ip, *username, *origin, *hub_limit; + char *tls_certfile, *tls_ciphers, *tls_fingerprint, *tls_keyfile; struct SLink *hosts; char *stringlist[MAX_STRINGS]; struct ListenerFlags listen_flags; @@ -224,6 +226,11 @@ static void free_slist(struct SLink **link) { %token FROM %token TEOF %token TOKERR +%token TLS +%token CERTFILE +%token CIPHERS +%token FINGERPRINT +%token KEYFILE /* and now a lot of privileges... */ %token TPRIV_CHAN_LIMIT TPRIV_MODE_LCHAN TPRIV_DEOP_LCHAN TPRIV_WALK_LCHAN %token TPRIV_LOCAL_KILL TPRIV_REHASH TPRIV_RESTART TPRIV_DIE @@ -348,10 +355,30 @@ generalblock: GENERAL parse_error("Your General block must contain a name."); if (localConf.numeric == 0) parse_error("Your General block must contain a numeric (between 1 and 4095)."); + MyFree(ircd_tls_keyfile); + MyFree(ircd_tls_certfile); + if (tls_certfile && !tls_keyfile) + { + parse_error("General block has tls certfile but no tls keyfile; disabling TLS"); + MyFree(tls_certfile); + } + else if (tls_keyfile && !tls_certfile) + { + parse_error("General block has tls keyfile but no tls certfile; disabling TLS"); + MyFree(tls_keyfile); + } + else if (tls_certfile && tls_keyfile) + { + ircd_tls_certfile = tls_certfile; + ircd_tls_keyfile = tls_keyfile; + tls_certfile = NULL; + tls_keyfile = NULL; + } }; generalitems: generalitem generalitems | generalitem; generalitem: generalnumeric | generalname | generalvhost | generaldesc - | generaldnsvhost | generaldnsserver; + | generaldnsvhost | generaldnsserver + | generaltlscertfile | generaltlskeyfile; generalnumeric: NUMERIC '=' NUMBER ';' { @@ -428,6 +455,16 @@ generaldnsserver: DNS SERVER '=' QSTRING ';' MyFree(server); }; +generaltlscertfile: TLS CERTFILE '=' QSTRING ';' +{ + tls_certfile = $4; +}; + +generaltlskeyfile: TLS KEYFILE '=' QSTRING ';' +{ + tls_keyfile = $4; +}; + adminblock: ADMIN { if (!permitted(BLOCK_ADMIN)) YYERROR; @@ -551,6 +588,8 @@ connectblock: CONNECT aconf->conn_class = c_class; aconf->address.port = port; aconf->host = host; + aconf->tls_ciphers = tls_ciphers; + aconf->tls_fingerprint = tls_fingerprint; /* If the user specified a hub allowance, but not maximum links, * allow an effectively unlimited number of hops. */ @@ -565,15 +604,19 @@ connectblock: CONNECT MyFree(host); MyFree(origin); MyFree(hub_limit); + MyFree(tls_ciphers); + MyFree(tls_fingerprint); } name = pass = host = origin = hub_limit = NULL; + tls_ciphers = tls_fingerprint = NULL; c_class = NULL; port = flags = maxlinks = 0; }; connectitems: connectitem connectitems | connectitem; connectitem: connectname | connectpass | connectclass | connecthost | connectport | connectvhost | connectleaf | connecthub - | connecthublimit | connectmaxhops | connectauto; + | connecthublimit | connectmaxhops | connectauto + | connecttls | tlsfingerprint | tlsciphers; connectname: NAME '=' QSTRING ';' { MyFree(name); @@ -625,6 +668,14 @@ connectmaxhops: MAXHOPS '=' expr ';' }; connectauto: AUTOCONNECT '=' YES ';' { flags |= CONF_AUTOCONNECT; } | AUTOCONNECT '=' NO ';' { flags &= ~CONF_AUTOCONNECT; }; +connecttls: TLS '=' YES ';' +{ + flags |= CONF_CONNECT_TLS; +} +| TLS '=' NO ';' +{ + flags &= ~CONF_CONNECT_TLS; +}; uworldblock: UWORLD { if (!permitted(BLOCK_UWORLD)) YYERROR; @@ -668,9 +719,15 @@ operblock: OPER { aconf->conn_class = c_class; memcpy(&aconf->privs, &privs, sizeof(aconf->privs)); memcpy(&aconf->privs_dirty, &privs_dirty, sizeof(aconf->privs_dirty)); + if (tls_fingerprint) + { + aconf->tls_fingerprint = tls_fingerprint; + tls_fingerprint = NULL; + } } MyFree(name); MyFree(pass); + MyFree(tls_fingerprint); free_slist(&hosts); name = pass = NULL; c_class = NULL; @@ -678,7 +735,8 @@ operblock: OPER { memset(&privs_dirty, 0, sizeof(privs_dirty)); }; operitems: operitem | operitems operitem; -operitem: opername | operpass | operhost | operclass | priv; +operitem: opername | operpass | operhost | operclass | priv + | tlsfingerprint; opername: NAME '=' QSTRING ';' { MyFree(name); @@ -750,6 +808,17 @@ privtype: TPRIV_CHAN_LIMIT { $$ = PRIV_CHAN_LIMIT; } | yesorno: YES { $$ = 1; } | NO { $$ = 0; }; +tlsfingerprint: TLS FINGERPRINT '=' QSTRING ';' +{ + MyFree(tls_fingerprint); + tls_fingerprint = $4; +}; +tlsciphers: TLS CIPHERS '=' QSTRING ';' +{ + MyFree(tls_ciphers); + tls_ciphers = $4; +}; + /* not a recursive definition because some pedant will just come along * and whine that the parser accepts "ipv4 ipv4 ipv4 ipv4" */ @@ -775,6 +844,8 @@ portblock: PORT { link->next = hosts; hosts = link; } + if (!FlagHas(&listen_flags, LISTEN_TLS)) + MyFree(tls_ciphers); for (link = hosts; link != NULL; link = link->next) { memcpy(&flags_here, &listen_flags, sizeof(flags_here)); switch (link->flags & (USE_IPV4 | USE_IPV6)) { @@ -791,16 +862,18 @@ portblock: PORT { } if (link->flags & 65535) port = link->flags & 65535; - add_listener(port, link->value.cp, pass, &flags_here); + add_listener(port, link->value.cp, pass, tls_ciphers, &flags_here); } free_slist(&hosts); MyFree(pass); + MyFree(tls_ciphers); memset(&listen_flags, 0, sizeof(listen_flags)); pass = NULL; port = 0; }; portitems: portitem portitems | portitem; -portitem: portnumber | portvhost | portvhostnumber | portmask | portserver | portwebirc | porthidden; +portitem: portnumber | portvhost | portvhostnumber | portmask | portserver + | portwebirc | porthidden | porttls | tlsciphers; portnumber: PORT '=' address_family NUMBER ';' { if ($4 < 1 || $4 > 65535) { @@ -869,6 +942,14 @@ portwebirc: WEBIRC '=' YES ';' FlagClr(&listen_flags, LISTEN_WEBIRC); }; +porttls: TLS '=' YES ';' +{ + FlagSet(&listen_flags, LISTEN_TLS); +} | TLS '=' NO ';' +{ + FlagClr(&listen_flags, LISTEN_TLS); +}; + clientblock: CLIENT { if (!permitted(BLOCK_CLIENT)) YYERROR; diff --git a/ircd/list.c b/ircd/list.c index ace92a0c..28e325d8 100644 --- a/ircd/list.c +++ b/ircd/list.c @@ -228,6 +228,7 @@ struct Client* make_client(struct Client *from, int status) cli_status(cptr) = status; cli_hnext(cptr) = cptr; strcpy(cli_username(cptr), ""); + strcpy(cli_tls_fingerprint(cptr), ""); return cptr; } diff --git a/ircd/listener.c b/ircd/listener.c index 22658402..afccf47c 100644 --- a/ircd/listener.c +++ b/ircd/listener.c @@ -33,6 +33,7 @@ #include "ircd_reply.h" #include "ircd_snprintf.h" #include "ircd_string.h" +#include "ircd_tls.h" #include "match.h" #include "numeric.h" #include "s_bsd.h" @@ -155,6 +156,10 @@ void show_ports(struct Client* sptr, const struct StatDesc* sd, continue; flags[len++] = 'H'; } + if (FlagHas(&listener->flags, LISTEN_TLS)) + { + flags[len++] = 'E'; + } if (FlagHas(&listener->flags, LISTEN_IPV4)) { flags[len++] = '4'; @@ -284,9 +289,11 @@ static struct Listener* find_listener(int port, const struct irc_in_addr *addr) * @param[in] port Port number to listen on. * @param[in] vhost_ip Local address to listen on. * @param[in] mask Address mask to accept connections from. + * @param[in] tls_ciphers TLS cipher(s) to use. * @param[in] flags Flags describing listener options. */ void add_listener(int port, const char* vhost_ip, const char* mask, + const char* tls_ciphers, const struct ListenerFlags *flags) { struct Listener* listener; @@ -300,6 +307,9 @@ void add_listener(int port, const char* vhost_ip, const char* mask, */ if (0 == port) return; + /* if TLS requested but no implementation, skip this port */ + if (FlagHas(flags, LISTEN_TLS) && !ircd_tls_version) + return; memset(&vaddr, 0, sizeof(vaddr)); @@ -323,6 +333,10 @@ void add_listener(int port, const char* vhost_ip, const char* mask, } } else listener->mask_bits = 0; + if (!EmptyString(tls_ciphers)) + DupString(listener->tls_ciphers, tls_ciphers); + else + listener->tls_ciphers = NULL; #ifdef IPV6 if (FlagHas(&listener->flags, LISTEN_IPV6) @@ -356,6 +370,11 @@ void add_listener(int port, const char* vhost_ip, const char* mask, listener->fd_v4 = -1; } + if (okay + && FlagHas(flags, LISTEN_TLS) + && ircd_tls_listen(listener)) + okay = 0; + if (!okay) free_listener(listener); else if (new_listener) { diff --git a/ircd/m_burst.c b/ircd/m_burst.c index be9eaa26..b4f4b405 100644 --- a/ircd/m_burst.c +++ b/ircd/m_burst.c @@ -130,6 +130,9 @@ netride_modes(int parc, char **parv, const char *curr_key) case 'r': result |= MODE_REGONLY; break; + case 'Z': + result |= MODE_TLSONLY; + break; } } return result; @@ -308,7 +311,8 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) */ if (!(check_modes & MODE_KEY) && (!(check_modes & MODE_INVITEONLY) || IsAnOper(member->user)) - && (!(check_modes & MODE_REGONLY) || IsAccount(member->user))) + && (!(check_modes & MODE_REGONLY) || IsAccount(member->user)) + && (!(check_modes & MODE_TLSONLY) || IsTLS(member->user))) continue; sendcmdto_serv_butone(&me, CMD_KICK, NULL, "%H %C :Net Rider", chptr, member->user); sendcmdto_channel_butserv_butone(&his, CMD_KICK, chptr, NULL, 0, "%H %C :Net Rider", chptr, member->user); diff --git a/ircd/m_clearmode.c b/ircd/m_clearmode.c index 2476b15b..684cb073 100644 --- a/ircd/m_clearmode.c +++ b/ircd/m_clearmode.c @@ -128,6 +128,7 @@ do_clearmode(struct Client *cptr, struct Client *sptr, struct Channel *chptr, MODE_NOCTCP, 'C', MODE_NOPARTMSGS, 'P', MODE_MODERATENOREG, 'M', + MODE_TLSONLY, 'Z', 0x0, 0x0 }; int *flag_p; diff --git a/ircd/m_info.c b/ircd/m_info.c index 6f85a6b9..8a05ca19 100644 --- a/ircd/m_info.c +++ b/ircd/m_info.c @@ -86,6 +86,7 @@ #include "ircd_log.h" #include "ircd_reply.h" #include "ircd_string.h" +#include "ircd_tls.h" #include "msg.h" #include "numeric.h" #include "numnicks.h" @@ -120,6 +121,8 @@ int m_info(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) creation, generation); send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":On-line since %s", myctime(cli_firsttime(&me))); + if (ircd_tls_version) + send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":TLS library: %s", ircd_tls_version); send_reply(sptr, RPL_ENDOFINFO); return 0; @@ -157,6 +160,8 @@ int ms_info(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) creation, generation); send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":On-line since %s", myctime(cli_firsttime(&me))); + if (ircd_tls_version) + send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":TLS library: %s", ircd_tls_version); send_reply(sptr, RPL_ENDOFINFO); return 0; } @@ -190,6 +195,8 @@ int mo_info(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) creation, generation); send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":On-line since %s", myctime(cli_firsttime(&me))); + if (ircd_tls_version) + send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":TLS library: %s", ircd_tls_version); send_reply(sptr, RPL_ENDOFINFO); } return 0; diff --git a/ircd/m_join.c b/ircd/m_join.c index 47728043..7a925e63 100644 --- a/ircd/m_join.c +++ b/ircd/m_join.c @@ -223,6 +223,8 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) err = ERR_BANNEDFROMCHAN; else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key))) err = ERR_BADCHANNELKEY; + else if ((chptr->mode.mode & MODE_TLSONLY) && !IsTLS(sptr)) + err = ERR_TLSONLYCHAN; /* An oper with WALK_LCHAN privilege can join a local channel * he otherwise could not join by using "OVERRIDE" as the key. @@ -247,6 +249,7 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) case ERR_BANNEDFROMCHAN: err = 'b'; break; case ERR_BADCHANNELKEY: err = 'k'; break; case ERR_NEEDREGGEDNICK: err = 'r'; break; + case ERR_TLSONLYCHAN: err = 'Z'; break; default: err = '?'; break; } /* send accountability notice */ diff --git a/ircd/m_oper.c b/ircd/m_oper.c index a66a42cc..b49ccf15 100644 --- a/ircd/m_oper.c +++ b/ircd/m_oper.c @@ -89,6 +89,7 @@ #include "ircd_log.h" #include "ircd_reply.h" #include "ircd_string.h" +#include "ircd_tls.h" #include "ircd_crypt.h" #include "msg.h" #include "numeric.h" @@ -156,6 +157,15 @@ int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) } assert(0 != (aconf->status & CONF_OPERATOR)); + if (!EmptyString(aconf->tls_fingerprint) + && ircd_strcmp(cli_tls_fingerprint(sptr), aconf->tls_fingerprint)) + { + send_reply(sptr, ERR_TLSCLIFINGERPRINT); + sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s)", + parv[0], cli_user(sptr)->username, cli_sockhost(sptr)); + return 0; + } + if (oper_password_match(password, aconf->passwd)) { struct Flags old_mode = cli_flags(sptr); diff --git a/ircd/m_rehash.c b/ircd/m_rehash.c index 8e8c2db6..2014fde5 100644 --- a/ircd/m_rehash.c +++ b/ircd/m_rehash.c @@ -86,6 +86,7 @@ #include "ircd_log.h" #include "ircd_reply.h" #include "ircd_string.h" +#include "ircd_tls.h" #include "motd.h" #include "numeric.h" #include "s_conf.h" @@ -99,6 +100,7 @@ * parv[1] = 'm' flushes the MOTD cache and returns * parv[1] = 'l' reopens the log files and returns * parv[1] = 'q' to not rehash the resolver (optional) + * parv[1] = 's' to reload TLS certificate and private key files */ int mo_rehash(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { @@ -116,6 +118,10 @@ int mo_rehash(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Reopening log files"); log_reopen(); /* reopen log files */ return 0; + } else if (*parv[1] == 's') { + send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Reloading TLS files"); + ircd_tls_init(); + return 0; } else if (*parv[1] == 'q') flag = 2; } diff --git a/ircd/m_server.c b/ircd/m_server.c index 9c3332ad..4468c480 100644 --- a/ircd/m_server.c +++ b/ircd/m_server.c @@ -34,6 +34,7 @@ #include "ircd_features.h" #include "ircd_reply.h" #include "ircd_string.h" +#include "ircd_tls.h" #include "jupe.h" #include "list.h" #include "match.h" @@ -607,6 +608,15 @@ int mr_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) "Access denied. No conf line for server %s", cli_name(cptr)); } + if (!EmptyString(aconf->tls_fingerprint) + && ircd_strcmp(cli_tls_fingerprint(cptr), aconf->tls_fingerprint)) { + ++ServerStats->is_wrong_server; + sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (fingerprint mismatch) %s", + cli_name(cptr)); + return exit_client_msg(cptr, cptr, &me, + "Access denied. Bad TLS fingerprint for server %s", cli_name(cptr)); + } + if (*aconf->passwd && !!strcmp(aconf->passwd, cli_passwd(cptr))) { ++ServerStats->is_bad_server; sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s", diff --git a/ircd/m_whois.c b/ircd/m_whois.c index 09664614..b56f835f 100644 --- a/ircd/m_whois.c +++ b/ircd/m_whois.c @@ -208,6 +208,9 @@ static void do_whois(struct Client* sptr, struct Client *acptr, int parc) if (user->away) send_reply(sptr, RPL_AWAY, name, user->away); + if (IsTLS(acptr)) + send_reply(sptr, RPL_WHOISSECURE, name); + if (SeeOper(sptr,acptr)) send_reply(sptr, RPL_WHOISOPERATOR, name); diff --git a/ircd/msgq.c b/ircd/msgq.c index ec320500..3df948c7 100644 --- a/ircd/msgq.c +++ b/ircd/msgq.c @@ -549,6 +549,41 @@ msgq_add(struct MsgQ *mq, struct MsgBuf *mb, int prio) mq->count++; /* and the queue count */ } +static int msgqlist_excise(struct MsgQ *mq, struct MsgQList *qlist, + const char *buf, unsigned int len) +{ + struct Msg *msg; + + msg = qlist->head; + if (!msg) + return 0; + + if (buf != msg->msg->msg) + return 0; + + assert(len == msg->msg->length); + msgq_delmsg(mq, qlist, &len); + return 1; +} + +/** Excise a message from the front of a message queue. + * + * This is used for TLS, where TLS libraries may return an EAGAIN-like + * condition for a send but also require the application to provide + * exactly the same contents for the next send. + * + * @warning \a buf must be at the front of one of \a mq's queues. + * @param[in] mq Message queue to operate on. + * @param[in] buf Buffered message to excise. + * @param[in] len Length of buffered message. + */ +void msgq_excise(struct MsgQ *mq, const char *buf, unsigned int len) +{ + if (!msgqlist_excise(mq, &mq->queue, buf, len) + && !msgqlist_excise(mq, &mq->prio, buf, len)) + assert(0 && "msgq_excise() could not find message to excise"); +} + /** Report memory statistics for message buffers. * @param[in] cptr Client requesting information. * @param[out] msg_alloc Receives number of bytes allocated in Msg structs. diff --git a/ircd/s_auth.c b/ircd/s_auth.c index ce038181..3639b095 100644 --- a/ircd/s_auth.c +++ b/ircd/s_auth.c @@ -49,6 +49,7 @@ #include "ircd_reply.h" #include "ircd_snprintf.h" #include "ircd_string.h" +#include "ircd_tls.h" #include "list.h" #include "msg.h" /* for MAXPARA */ #include "numeric.h" @@ -142,10 +143,6 @@ typedef enum { REPORT_INVAL_DNS } ReportType; -/** Sends response \a r (from #ReportType) to client \a c. */ -#define sendheader(c, r) \ - send(cli_fd(c), HeaderMessages[(r)].message, HeaderMessages[(r)].length, 0) - /** Enumeration of IAuth connection flags. */ enum IAuthFlag { @@ -221,6 +218,21 @@ static int preregister_user(struct Client *cptr); typedef int (*iauth_cmd_handler)(struct IAuth *iauth, struct Client *cli, int parc, char **params); +/** Sends response \a r (from #ReportType) to client \a cptr. */ +static void sendheader(struct Client *cptr, ReportType r) +{ + if (IsTLS(cptr)) + { + sendrawto_one(cptr, "%.*s", HeaderMessages[r].length - 2, + HeaderMessages[r].message); + send_queued(cptr); + } + else + { + send(cli_fd(cptr), HeaderMessages[r].message, HeaderMessages[r].length, 0); + } +} + /** Copies a username, cleaning it in the process. * * @param[out] dest Destination buffer for user name. @@ -560,6 +572,15 @@ static int check_auth_finished(struct AuthRequest *auth, int bitclr) send_reply(cptr, ERR_PASSWDMISMATCH); res = exit_client(cptr, cptr, &me, "Bad Password"); } + + /* Check TLS fingerprint. */ + if ((res == 0) && aconf && !EmptyString(aconf->tls_fingerprint) + && ircd_strcmp(cli_tls_fingerprint(cptr), aconf->tls_fingerprint)) + { + ++ServerStats->is_bad_fingerprint; + send_reply(cptr, ERR_TLSCLIFINGERPRINT); + res = exit_client(cptr, cptr, &me, "Bad TLS fingerprint"); + } } if (res == 0) @@ -1163,6 +1184,10 @@ void start_auth(struct Client* client) if (IsUserPort(client)) { /* Try to start iauth lookup. */ start_iauth_query(auth); + + /* Pass on fingerprint to iauth. */ + if (IsTLS(client) && *cli_tls_fingerprint(client)) + sendto_iauth(auth->client, "Z %s", cli_tls_fingerprint(client)); } } diff --git a/ircd/s_bsd.c b/ircd/s_bsd.c index 9bfb8760..eeaef991 100644 --- a/ircd/s_bsd.c +++ b/ircd/s_bsd.c @@ -36,6 +36,7 @@ #include "ircd_reply.h" #include "ircd_snprintf.h" #include "ircd_string.h" +#include "ircd_tls.h" #include "ircd.h" #include "list.h" #include "listener.h" @@ -280,9 +281,14 @@ unsigned int deliver_it(struct Client *cptr, struct MsgQ *buf) { unsigned int bytes_written = 0; unsigned int bytes_count = 0; + IOResult io_result; + assert(0 != cptr); - switch (os_sendv_nonb(cli_fd(cptr), buf, &bytes_count, &bytes_written)) { + io_result = IsTLS(cptr) && s_tls(&cli_socket(cptr)) + ? ircd_tls_sendv(cptr, buf, &bytes_count, &bytes_written) + : os_sendv_nonb(cli_fd(cptr), buf, &bytes_count, &bytes_written); + switch (io_result) { case IO_SUCCESS: ClrFlag(cptr, FLAG_BLOCKED); @@ -338,6 +344,29 @@ static int completed_connection(struct Client* cptr) if (s_state(&(cli_socket(cptr))) == SS_CONNECTING) socket_state(&(cli_socket(cptr)), SS_CONNECTED); + if (aconf->flags & CONF_CONNECT_TLS) { + /* Should we start the TLS handshake? */ + if (!IsTLS(cptr)) { + void *tls; + + tls = ircd_tls_connect(aconf, cli_fd(cptr)); + if (!tls) { + sendto_opmask_butone(0, SNO_OLDSNO, "Unable to start TLS connection to %s", cli_name(cptr)); + return 0; + } + s_tls(&cli_socket(cptr)) = tls; + SetNegotiatingTLS(cptr); + SetTLS(cptr); + } + + /* Are we making progress? */ + if (IsNegotiatingTLS(cptr)) { + ircd_tls_negotiate(cptr); + if (IsNegotiatingTLS(cptr)) + return 1; + } + } + if (!EmptyString(aconf->passwd)) sendrawto_one(cptr, MSG_PASS " :%s", aconf->passwd); @@ -367,6 +396,12 @@ static int completed_connection(struct Client* cptr) MAJOR_PROTOCOL, NumServCap(&me), feature_bool(FEAT_HUB) ? "h" : "", cli_info(&me)); + if (IsTLS(cptr) && !IsNegotiatingTLS(cptr)) { + Debug((DEBUG_DEBUG, "TLS connection completed for %s", cli_name(cptr))); + socket_events(&cli_socket(cptr), SOCK_EVENT_READABLE | SOCK_EVENT_WRITABLE); + send_queued(cptr); + } + return (IsDead(cptr)) ? 0 : 1; } @@ -414,6 +449,10 @@ void close_connection(struct Client *cptr) if (-1 < cli_fd(cptr)) { flush_connections(cptr); LocalClientArray[cli_fd(cptr)] = 0; + if (IsTLS(cptr) && s_tls(&cli_socket(cptr))) { + ircd_tls_close(s_tls(&cli_socket(cptr)), NULL); + s_tls(&cli_socket(cptr)) = NULL; + } close(cli_fd(cptr)); socket_del(&(cli_socket(cptr))); /* queue a socket delete */ cli_fd(cptr) = -1; @@ -471,6 +510,7 @@ void add_connection(struct Listener* listener, int fd) { struct irc_sockaddr addr; struct Client *new_client; time_t next_target = 0; + void *tls; const char* const throttle_message = "ERROR :Your host is trying to (re)connect too fast -- throttled\r\n"; @@ -551,9 +591,19 @@ void add_connection(struct Listener* listener, int fd) { cli_listener(new_client) = listener; ++listener->ref_count; + tls = listener_tls(listener) ? ircd_tls_accept(listener, fd) : NULL; + s_tls(&cli_socket(new_client)) = tls; + if (tls) + { + SetTLS(new_client); + SetNegotiatingTLS(new_client); + socket_events(&cli_socket(new_client), SOCK_EVENT_WRITABLE); + } + Count_newunknown(UserStats); /* if we've made it this far we can put the client on the auth query pile */ - start_auth(new_client); + if (!IsTLS(new_client)) + start_auth(new_client); } /** Determines whether to tell the events engine we're interested in @@ -588,8 +638,11 @@ static int read_packet(struct Client *cptr, int socket_ready) if (socket_ready && !(IsUser(cptr) && - DBufLength(&(cli_recvQ(cptr))) > GetMaxFlood(cptr))) { - switch (os_recv_nonb(cli_fd(cptr), readbuf, sizeof(readbuf), &length)) { + DBufLength(&(cli_recvQ(cptr))) > GetMaxFlood(cptr))) { + IOResult io_result = IsTLS(cptr) && s_tls(&cli_socket(cptr)) + ? ircd_tls_recv(cptr, readbuf, sizeof(readbuf), &length) + : os_recv_nonb(cli_fd(cptr), readbuf, sizeof(readbuf), &length); + switch (io_result) { case IO_SUCCESS: if (length) { @@ -857,6 +910,10 @@ static void client_sock_callback(struct Event* ev) if (!con_freeflag(con) && !cptr) free_connection(con); + if (s_tls(&con_socket(con))) { + ircd_tls_close(s_tls(&con_socket(con)), NULL); + s_tls(&con_socket(con)) = NULL; + } break; case ET_CONNECT: /* socket connection completed */ @@ -897,6 +954,28 @@ static void client_sock_callback(struct Event* ev) break; case ET_WRITE: /* socket is writable */ + if (IsNegotiatingTLS(cptr)) { + int res = ircd_tls_negotiate(cptr); + if (res < 0) { + SetFlag(cptr, FLAG_DEADSOCKET); + ClrFlag(cptr, FLAG_NEGOTIATING_TLS); + /* Clean up TLS context if it still exists */ + if (s_tls(&cli_socket(cptr))) { + ircd_tls_close(s_tls(&cli_socket(cptr)), "TLS negotiation failed"); + s_tls(&cli_socket(cptr)) = NULL; + } + fmt = "TLS negotiation failed: %s"; + fallback = "TLS negotiation failed"; + break; + } + if (res == 0) { + /* Still negotiating */ + break; + } + /* TLS negotiation succeeded */ + IsConnecting(cptr) ? completed_connection(cptr) : start_auth(cptr); + return; + } ClrFlag(cptr, FLAG_BLOCKED); if (cli_listing(cptr) && MsgQLength(&(cli_sendQ(cptr))) < 2048) list_next_channels(cptr); @@ -907,8 +986,30 @@ static void client_sock_callback(struct Event* ev) case ET_READ: /* socket is readable */ if (!IsDead(cptr)) { Debug((DEBUG_DEBUG, "Reading data from %C", cptr)); + if (IsNegotiatingTLS(cptr)) { + int res = ircd_tls_negotiate(cptr); + if (res < 0) { + SetFlag(cptr, FLAG_DEADSOCKET); + ClrFlag(cptr, FLAG_NEGOTIATING_TLS); + /* Clean up TLS context if it still exists */ + if (s_tls(&cli_socket(cptr))) { + ircd_tls_close(s_tls(&cli_socket(cptr)), "TLS negotiation failed"); + s_tls(&cli_socket(cptr)) = NULL; + } + fmt = "TLS negotiation failed: %s"; + fallback = "TLS negotiation failed"; + break; + } + if (res == 0) { + /* Still negotiating */ + break; + } + /* TLS negotiation succeeded */ + if (IsConnecting(cptr)) + completed_connection(cptr); + } if (read_packet(cptr, 1) == 0) /* error while reading packet */ - fallback = "EOF from client"; + fallback = "EOF from client"; } break; @@ -923,6 +1024,12 @@ static void client_sock_callback(struct Event* ev) const char* msg = (cli_error(cptr)) ? strerror(cli_error(cptr)) : fallback; if (!msg) msg = "Unknown error"; + + if (s_tls(&con_socket(con))) { + ircd_tls_close(s_tls(&con_socket(con)), NULL); + s_tls(&con_socket(con)) = NULL; + } + exit_client_msg(cptr, cptr, &me, fmt, msg); } } diff --git a/ircd/s_conf.c b/ircd/s_conf.c index 389d549a..e4177d7b 100644 --- a/ircd/s_conf.c +++ b/ircd/s_conf.c @@ -158,6 +158,8 @@ void free_conf(struct ConfItem *aconf) MyFree(aconf->passwd); MyFree(aconf->name); MyFree(aconf->hub_limit); + MyFree(aconf->tls_ciphers); + MyFree(aconf->tls_fingerprint); MyFree(aconf); --GlobalConfCount; } diff --git a/ircd/s_err.c b/ircd/s_err.c index 3390ce12..ec0e8f56 100644 --- a/ircd/s_err.c +++ b/ircd/s_err.c @@ -970,7 +970,7 @@ static Numeric replyTable[] = { /* 468 */ { ERR_INVALIDUSERNAME, 0, "468" }, /* 469 */ - { 0 }, + { ERR_TLSONLYCHAN, "%s :Cannot join channel (+Z)", "469" }, /* 470 */ { 0 }, /* 471 */ @@ -1096,7 +1096,7 @@ static Numeric replyTable[] = { /* 531 */ { 0 }, /* 532 */ - { 0 }, + { ERR_TLSCLIFINGERPRINT, ":TLS certificate fingerprint did not match", "532" }, /* 533 */ { 0 }, /* 534 */ @@ -1230,7 +1230,191 @@ static Numeric replyTable[] = { /* 598 */ { 0 }, /* 599 */ - { 0 } + { 0 }, +/* 600 */ + { 0 }, +/* 601 */ + { 0 }, +/* 602 */ + { 0 }, +/* 603 */ + { 0 }, +/* 604 */ + { 0 }, +/* 605 */ + { 0 }, +/* 606 */ + { 0 }, +/* 607 */ + { 0 }, +/* 608 */ + { 0 }, +/* 609 */ + { 0 }, +/* 610 */ + { 0 }, +/* 611 */ + { 0 }, +/* 612 */ + { 0 }, +/* 613 */ + { 0 }, +/* 614 */ + { 0 }, +/* 615 */ + { 0 }, +/* 616 */ + { 0 }, +/* 617 */ + { 0 }, +/* 618 */ + { 0 }, +/* 619 */ + { 0 }, +/* 620 */ + { 0 }, +/* 621 */ + { 0 }, +/* 622 */ + { 0 }, +/* 623 */ + { 0 }, +/* 624 */ + { 0 }, +/* 625 */ + { 0 }, +/* 626 */ + { 0 }, +/* 627 */ + { 0 }, +/* 628 */ + { 0 }, +/* 629 */ + { 0 }, +/* 630 */ + { 0 }, +/* 631 */ + { 0 }, +/* 632 */ + { 0 }, +/* 633 */ + { 0 }, +/* 634 */ + { 0 }, +/* 635 */ + { 0 }, +/* 636 */ + { 0 }, +/* 637 */ + { 0 }, +/* 638 */ + { 0 }, +/* 639 */ + { 0 }, +/* 640 */ + { 0 }, +/* 641 */ + { 0 }, +/* 642 */ + { 0 }, +/* 643 */ + { 0 }, +/* 644 */ + { 0 }, +/* 645 */ + { 0 }, +/* 646 */ + { 0 }, +/* 647 */ + { 0 }, +/* 648 */ + { 0 }, +/* 649 */ + { 0 }, +/* 650 */ + { 0 }, +/* 651 */ + { 0 }, +/* 652 */ + { 0 }, +/* 653 */ + { 0 }, +/* 654 */ + { 0 }, +/* 655 */ + { 0 }, +/* 656 */ + { 0 }, +/* 657 */ + { 0 }, +/* 658 */ + { 0 }, +/* 659 */ + { 0 }, +/* 660 */ + { 0 }, +/* 661 */ + { 0 }, +/* 662 */ + { 0 }, +/* 663 */ + { 0 }, +/* 664 */ + { 0 }, +/* 665 */ + { 0 }, +/* 666 */ + { 0 }, +/* 667 */ + { 0 }, +/* 668 */ + { 0 }, +/* 669 */ + { 0 }, +/* 670 */ + { 0 }, +/* 671 */ + { RPL_WHOISSECURE, "%s :is using a secure connection", "671" }, +/* 672 */ + { 0 }, +/* 673 */ + { 0 }, +/* 674 */ + { 0 }, +/* 675 */ + { 0 }, +/* 676 */ + { 0 }, +/* 677 */ + { 0 }, +/* 678 */ + { 0 }, +/* 679 */ + { 0 }, +/* 680 */ + { 0 }, +/* 681 */ + { 0 }, +/* 682 */ + { 0 }, +/* 683 */ + { 0 }, +/* 684 */ + { 0 }, +/* 685 */ + { 0 }, +/* 686 */ + { 0 }, +/* 687 */ + { 0 }, +/* 688 */ + { 0 }, +/* 689 */ + { 0 }, +/* 690 */ + { 0 }, +/* 691 */ + { 0 }, }; /** Return a pointer to the Numeric for a particular code. diff --git a/ircd/s_misc.c b/ircd/s_misc.c index a6a0cff3..1992e77b 100644 --- a/ircd/s_misc.c +++ b/ircd/s_misc.c @@ -597,7 +597,7 @@ void tstats(struct Client *cptr, const struct StatDesc *sd, char *param) + sp->is_bad_password + sp->is_no_client + sp->is_class_full + sp->is_ip_full + sp->is_bad_socket + sp->is_throttled + sp->is_not_hub + sp->is_crule_fail + sp->is_not_server - + sp->is_bad_server; + + sp->is_bad_server + sp->is_bad_fingerprint + sp->is_wrong_server; maxconn = MAXCONNECTIONS; send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":accepts %u refused %u", sp->is_ac, is_ref); @@ -617,6 +617,9 @@ void tstats(struct Client *cptr, const struct StatDesc *sd, char *param) ":not hub %u crule faile %u no server block %u bad password %u", sp->is_not_hub, sp->is_crule_fail, sp->is_not_server, sp->is_bad_server); + send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, + ":bad client fingerprint %u bad server fingerprint %u", + sp->is_bad_fingerprint, sp->is_wrong_server); send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":unknown commands %u prefixes %u", sp->is_unco, sp->is_unpf); send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, diff --git a/ircd/s_user.c b/ircd/s_user.c index 13c61cb1..621d6394 100644 --- a/ircd/s_user.c +++ b/ircd/s_user.c @@ -499,7 +499,8 @@ static const struct UserMode { { FLAG_CHSERV, 'k' }, { FLAG_DEBUG, 'g' }, { FLAG_ACCOUNT, 'r' }, - { FLAG_HIDDENHOST, 'x' } + { FLAG_HIDDENHOST, 'x' }, + { FLAG_TLS, 'z' } }; /** Length of #userModeList. */ @@ -966,6 +967,7 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, int prop = 0; int do_host_hiding = 0; char* account = NULL; + char* tls_fingerprint = NULL; what = MODE_ADD; @@ -1085,6 +1087,14 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, } /* There is no -r */ break; + case 'z': + if (what == MODE_ADD) { + SetTLS(sptr); + if (feature_bool(FEAT_TLS_BURST_FINGERPRINT)) + tls_fingerprint = *(++p); + } + /* There is no -z */ + break; default: send_reply(sptr, ERR_UMODEUNKNOWNFLAG, *m); break; @@ -1103,6 +1113,10 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, ClearLocOp(sptr); if (!FlagHas(&setflags, FLAG_ACCOUNT) && IsAccount(sptr)) ClrFlag(sptr, FLAG_ACCOUNT); + if (!FlagHas(&setflags, FLAG_TLS) && IsTLS(sptr)) + ClrFlag(sptr, FLAG_TLS); + else if (FlagHas(&setflags, FLAG_TLS) && !IsTLS(sptr)) + SetFlag(sptr, FLAG_TLS); /* * new umode; servers can set it, local users cannot; * prevents users from /kick'ing or /mode -o'ing @@ -1173,6 +1187,12 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding && allow_modes != ALLOWMODES_DEFAULT) hide_hostmask(sptr, FLAG_HIDDENHOST); + if (feature_bool(FEAT_TLS_BURST_FINGERPRINT) && tls_fingerprint && tls_fingerprint[0] != '_') { + ircd_strncpy(cli_tls_fingerprint(sptr), tls_fingerprint, 64); + Debug((DEBUG_DEBUG, "Received TLS fingerprint in user mode; " + "fingerprint \"%s\"", cli_tls_fingerprint(sptr))); + } + if (IsRegistered(sptr)) { if (!FlagHas(&setflags, FLAG_OPER) && IsOper(sptr)) { /* user now oper */ @@ -1236,6 +1256,8 @@ char *umode_str(struct Client *cptr) while ((*m++ = *t++)) ; /* Empty loop */ + m--; /* back up over previous nul-termination */ + if (cli_user(cptr)->acc_id) { char nbuf[30]; Debug((DEBUG_DEBUG, "Sending account id in user mode for " @@ -1253,9 +1275,25 @@ char *umode_str(struct Client *cptr) ircd_snprintf(0, t = nbuf, sizeof(nbuf), ":%qu", cli_user(cptr)->acc_id); } - m--; /* back up over previous nul-termination */ while ((*m++ = *t++)) ; /* Empty loop */ + m--; /* back up over previous nul-termination */ + } + } + + /** If the client is on a secure connection (umode +z) we append the fingerprint. + * If the fingerprint is empty (client has not provided a certificate), + * we return _ in the place of the fingerprint. + */ + if (IsTLS(cptr) && feature_bool(FEAT_TLS_BURST_FINGERPRINT)) + { + char* t = cli_tls_fingerprint(cptr); + + *m++ = ' '; + if (t && *t) { + while ((*m++ = *t++)); + } else { + *m++ = '_'; } } diff --git a/ircd/send.c b/ircd/send.c index 9dbd2921..f23e18b0 100644 --- a/ircd/send.c +++ b/ircd/send.c @@ -182,6 +182,10 @@ void send_queued(struct Client *to) if (IsBlocked(to) || !can_send(to)) return; /* Don't bother */ + /* If we're still negotiating TLS, don't try to send data yet */ + if (IsTLS(to) && IsNegotiatingTLS(to)) + return; + while (MsgQLength(&(cli_sendQ(to))) > 0) { unsigned int len; diff --git a/ircd/tls_gnutls.c b/ircd/tls_gnutls.c new file mode 100644 index 00000000..d68586d4 --- /dev/null +++ b/ircd/tls_gnutls.c @@ -0,0 +1,445 @@ +/* + * IRC - Internet Relay Chat, ircd/tls_gnutls.c + * Copyright (C) 2019 Michael Poole + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/** @file + * @brief ircd TLS functions using gnutls. + * + * This relies on gnutls_session_t being (a typedef to) a pointer type. + */ + +#include "ircd_tls.h" +#include "ircd.h" +#include "ircd_log.h" +#include "ircd_string.h" +#include "s_auth.h" +#include "send.h" +#include "s_conf.h" +#include "s_debug.h" +#include "listener.h" +#include "ircd_features.h" + +#include +#include +#include +#include +#include +#include + +#if defined(GNUTLS_AUTO_REAUTH) /* 3.6.4 */ +# define TLS_SESSION_FLAGS GNUTLS_NONBLOCK | GNUTLS_NO_SIGNAL \ + | GNUTLS_POST_HANDSHAKE_AUTH | GNUTLS_AUTH_REAUTH \ + | GNUTLS_ENABLE_EARLY_START +#elif defined(GNUTLS_ENABLE_EARLY_START) /* earlier in 3.6.4 */ +# define TLS_SESSION_FLAGS GNUTLS_NONBLOCK | GNUTLS_NO_SIGNAL \ + | GNUTLS_ENABLE_EARLY_START +#else +# define TLS_SESSION_FLAGS GNUTLS_NONBLOCK | GNUTLS_NO_SIGNAL +#endif + +const char *ircd_tls_version = "gnutls " GNUTLS_VERSION; + +static gnutls_priority_t tls_priority; +static gnutls_certificate_credentials_t tls_cert; + +int ircd_tls_init(void) +{ + static int once; + const char *str, *s_2; + int res; + + /* Early out? */ + if (EmptyString(ircd_tls_keyfile) || EmptyString(ircd_tls_certfile)) + return 0; + + if (!once) + { + once = 1; + + /* Global initialization is automatic for 3.3.0 and later. */ +#if GNUTLS_VERSION_NUMBER < 0x030300 + if (gnutls_global_init() != GNUTLS_E_SUCCESS) + return 1; +#endif + } + + str = feature_str(FEAT_TLS_CIPHERS); + if (str) + { + gnutls_priority_t new_priority; + res = gnutls_priority_init2(&new_priority, str, &str, + GNUTLS_PRIORITY_INIT_DEF_APPEND); + if (res == GNUTLS_E_SUCCESS) + { + if (tls_priority) + gnutls_priority_deinit(tls_priority); + tls_priority = new_priority; + } + else if (res == GNUTLS_E_INVALID_REQUEST) + log_write(LS_SYSTEM, L_ERROR, 0, "Invalid TLS_CIPHERS near '%s'", str); + else + log_write(LS_SYSTEM, L_ERROR, 0, "Unable to use TLS_CIPHERS: %s", + gnutls_strerror(res)); + /* But continue on failures. */ + } + else + { + if (tls_priority) + gnutls_priority_deinit(tls_priority); + tls_priority = NULL; + } + + if (1) + { + gnutls_certificate_credentials_t new_cert; + + gnutls_certificate_allocate_credentials(&new_cert); + res = gnutls_certificate_set_x509_key_file2(new_cert, + ircd_tls_certfile, ircd_tls_keyfile, GNUTLS_X509_FMT_PEM, "", + GNUTLS_PKCS_PLAIN | GNUTLS_PKCS_NULL_PASSWORD); + if (res < 0) /* may return a positive index */ + { + log_write(LS_SYSTEM, L_ERROR, 0, "Unable to load TLS keyfile and/or" + " certificate: %s", gnutls_strerror(res)); + gnutls_certificate_free_credentials(new_cert); + return 2; + } + + str = feature_str(FEAT_TLS_CACERTFILE); + s_2 = feature_str(FEAT_TLS_CACERTDIR); + if (!EmptyString(str) || !EmptyString(s_2)) + { + if (!EmptyString(s_2)) + { + res = gnutls_certificate_set_x509_trust_dir(new_cert, s_2, + GNUTLS_X509_FMT_PEM); + if (res < 0) + { + log_write(LS_SYSTEM, L_ERROR, 0, "Unable to read CA certs from" + " %s: %s", s_2, gnutls_strerror(res)); + } + } + + if (!EmptyString(str)) + { + res = gnutls_certificate_set_x509_trust_file(new_cert, str, + GNUTLS_X509_FMT_PEM); + if (res < 0) + { + log_write(LS_SYSTEM, L_ERROR, 0, "Unable to read CA certs from" + " %s: %s", str, gnutls_strerror(res)); + } + } + } + else + (void)gnutls_certificate_set_x509_system_trust(new_cert); + + if (tls_cert) + gnutls_certificate_free_credentials(tls_cert); + tls_cert = new_cert; + } + + return 0; +} + +static void *tls_create(int flag, int fd, const char *name, const char *tls_ciphers) +{ + gnutls_session_t tls; + int res; + + res = gnutls_init(&tls, flag | TLS_SESSION_FLAGS); + if (res != GNUTLS_E_SUCCESS) + return NULL; + + res = gnutls_credentials_set(tls, GNUTLS_CRD_CERTIFICATE, tls_cert); + if (res != GNUTLS_E_SUCCESS) + { + gnutls_deinit(tls); + return NULL; + } + + /* Set verification callback if we allow self-signed certificates */ + if (feature_bool(FEAT_TLS_ALLOW_SELFSIGNED)) { + Debug((DEBUG_DEBUG, "GnuTLS: Allowing self-signed certificates for %s", name ? name : "server")); + /* Disable strict CA verification to allow self-signed certificates */ + gnutls_certificate_set_verify_flags(tls_cert, GNUTLS_VERIFY_DISABLE_CA_SIGN); + } + + /* gnutls does not appear to allow an application to select which + * SSL/TLS protocol versions to support, except indirectly through + * priority strings. + */ + + if (tls_ciphers) + { + const char *sep; + res = gnutls_set_default_priority_append(tls, tls_ciphers, &sep, 0); + if (!name || res == GNUTLS_E_SUCCESS) + { + /* do not report error */ + } + else if (res == GNUTLS_E_INVALID_REQUEST) + log_write(LS_SYSTEM, L_ERROR, 0, "Invalid tls ciphers for %s near '%s'", + name, sep); + else + log_write(LS_SYSTEM, L_ERROR, 0, "Unable to set TLS ciphers for %s: %s", + name, gnutls_strerror(res)); + } + else if (tls_priority) + { + res = gnutls_priority_set(tls, tls_priority); + if (name && (res != GNUTLS_E_SUCCESS)) + log_write(LS_SYSTEM, L_ERROR, 0, "Unable to use default TLS ciphers" + " for %s: %s", name, gnutls_strerror(res)); + } + else + { + gnutls_set_default_priority(tls); + } + + if (flag & GNUTLS_SERVER) + gnutls_certificate_server_set_request(tls, GNUTLS_CERT_REQUEST); + + gnutls_handshake_set_timeout(tls, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); + + gnutls_transport_set_int(tls, fd); + + return tls; +} + +void *ircd_tls_accept(struct Listener *listener, int fd) +{ + return tls_create(GNUTLS_SERVER, fd, NULL, listener->tls_ciphers); +} + +void *ircd_tls_connect(struct ConfItem *aconf, int fd) +{ + return tls_create(GNUTLS_CLIENT, fd, aconf->name, aconf->tls_ciphers); +} + +void ircd_tls_close(void *ctx, const char *message) +{ + gnutls_bye(ctx, GNUTLS_SHUT_RDWR); + gnutls_deinit(ctx); +} + +int ircd_tls_listen(struct Listener *listener) +{ + /* noop for gnutls */ + return 0; +} + +int ircd_tls_negotiate(struct Client *cptr) +{ + gnutls_session_t tls; + gnutls_x509_crt_t crt; + const gnutls_datum_t *datum; + size_t len; + int res; + unsigned char buf[32]; + + tls = s_tls(&cli_socket(cptr)); + + if (!tls) + return 1; + + /* Check for handshake timeout - use the constant from header */ + if (CurrentTime - cli_firsttime(cptr) > TLS_HANDSHAKE_TIMEOUT) { + Debug((DEBUG_DEBUG, "GnuTLS handshake timeout for %s", cli_name(cptr))); + return -1; + } + + res = gnutls_handshake(tls); + switch (res) + { + case GNUTLS_E_INTERRUPTED: + case GNUTLS_E_AGAIN: + case GNUTLS_E_WARNING_ALERT_RECEIVED: + case GNUTLS_E_GOT_APPLICATION_DATA: + return 0; + + case GNUTLS_E_SUCCESS: + ClearNegotiatingTLS(cptr); + + datum = gnutls_certificate_get_peers(tls, NULL); + if (!datum) + { + log_write(LS_SYSTEM, L_ERROR, 0, "gnutls_certificate_get_peers failed for %s", + cli_name(cptr)); + return 1; + } + + res = gnutls_x509_crt_init(&crt); + if (res) + { + log_write(LS_SYSTEM, L_ERROR, 0, "gnutls_x509_crt_init failed for %s: %d", + cli_name(cptr), res); + return 1; + } + + /* Complete the fingerprint extraction - convert buf to hex */ + res = gnutls_x509_crt_import(crt, datum, GNUTLS_X509_FMT_DER); + if (res) + { + log_write(LS_SYSTEM, L_ERROR, 0, "gnutls_x509_crt_import failed for %s: %d", + cli_name(cptr), res); + gnutls_x509_crt_deinit(crt); + return 1; + } + + len = sizeof(buf); + res = gnutls_x509_crt_get_fingerprint(crt, GNUTLS_DIG_SHA256, buf, &len); + gnutls_x509_crt_deinit(crt); + if (res) + { + log_write(LS_SYSTEM, L_ERROR, 0, "gnutls_x509_crt_get_fingerprint failed for %s: %d", + cli_name(cptr), res); + return 1; + } + + /* Convert buf to hex like OpenSSL version */ + if (len == 32) { + char *p = cli_tls_fingerprint(cptr); + for (unsigned int i = 0; i < len; i++) { + sprintf(p + (i * 2), "%02x", buf[i]); + } + p[len * 2] = '\0'; + Debug((DEBUG_DEBUG, "Fingerprint for %s: %s", cli_name(cptr), cli_tls_fingerprint(cptr))); + } + else { + memset(cli_tls_fingerprint(cptr), 0, 65); + Debug((DEBUG_DEBUG, "Invalid fingerprint length: %zu", len)); + } + + return 1; + + default: + Debug((DEBUG_DEBUG, " ... gnutls_handshake() failed -> %s (%d)", + gnutls_strerror(res), res)); + if (gnutls_error_is_fatal(res)) { + const char* const error_tls = "ERROR :TLS connection error\r\n"; + Debug((DEBUG_DEBUG, "GnuTLS handshake failed for %s: %s", cli_name(cptr), gnutls_strerror(res))); + write(cli_fd(cptr), error_tls, strlen(error_tls)); + return -1; + } + return 0; + } +} + +IOResult ircd_tls_recv(struct Client *cptr, char *buf, + unsigned int length, unsigned int *count_out) +{ + gnutls_session_t tls; + int res; + + *count_out = 0; + tls = s_tls(&cli_socket(cptr)); + if (!tls) + return IO_FAILURE; + + res = gnutls_record_recv(tls, buf, length); + if (res > 0) + { + *count_out = res; + return IO_SUCCESS; + } + if (res == GNUTLS_E_REHANDSHAKE) + { + res = gnutls_handshake(tls); + if (res >= 0) + return IO_SUCCESS; + } + if (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN) + return IO_BLOCKED; + return gnutls_error_is_fatal(res) ? IO_FAILURE : IO_BLOCKED; +} + +IOResult ircd_tls_sendv(struct Client *cptr, struct MsgQ *buf, + unsigned int *count_in, unsigned int *count_out) +{ + struct iovec iov[512]; + gnutls_session_t tls; + struct Connection *con; + IOResult result = IO_BLOCKED; + ssize_t res; + int ii, count; + + con = cli_connect(cptr); + tls = s_tls(&con_socket(con)); + if (!tls) + return IO_FAILURE; + + /* TODO: Try to use gnutls_record_cork()/_uncork()/_check_corked(). + * The exact semantics of check_corked()'s return value are not clear: + * What does "the size of the corked data" signify relative to what + * has been accepted or must be provided to a future call to + * gnutls_record_send()? + */ + *count_out = 0; + if (con->con_rexmit) + { + res = gnutls_record_send(tls, con->con_rexmit, con->con_rexmit_len); + if (res <= 0) { + if (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN) + return IO_BLOCKED; + return gnutls_error_is_fatal(res) ? IO_FAILURE : IO_BLOCKED; + } + + // Only excise the message if the full message was sent + if (res == (int)con->con_rexmit_len) { + msgq_excise(buf, con->con_rexmit, con->con_rexmit_len); + con->con_rexmit_len = 0; + con->con_rexmit = NULL; + result = IO_SUCCESS; + } else { + // Partial send, update pointer and length for next retry + con->con_rexmit = (char *)con->con_rexmit + res; + con->con_rexmit_len -= res; + return IO_BLOCKED; + } + } + + // Process remaining messages in the queue + count = msgq_mapiov(buf, iov, sizeof(iov) / sizeof(iov[0]), count_in); + for (ii = 0; ii < count; ++ii) + { + res = gnutls_record_send(tls, iov[ii].iov_base, iov[ii].iov_len); + if (res > 0) + { + *count_out += res; + result = IO_SUCCESS; + if (res < (int)iov[ii].iov_len) { + // Partial send, store for retransmission + cli_connect(cptr)->con_rexmit = (char *)iov[ii].iov_base + res; + cli_connect(cptr)->con_rexmit_len = iov[ii].iov_len - res; + return IO_BLOCKED; + } + // else, full message sent, continue to next + continue; + } + + /* We only reach this if the gnutls_record_send failed. */ + if (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN) { + cli_connect(cptr)->con_rexmit = iov[ii].iov_base; + cli_connect(cptr)->con_rexmit_len = iov[ii].iov_len; + } + result = gnutls_error_is_fatal(res) ? IO_FAILURE : IO_BLOCKED; + break; + } + + return result; +} diff --git a/ircd/tls_libtls.c b/ircd/tls_libtls.c new file mode 100644 index 00000000..79074a03 --- /dev/null +++ b/ircd/tls_libtls.c @@ -0,0 +1,418 @@ +/* + * IRC - Internet Relay Chat, ircd/tls_gnutls.c + * Copyright (C) 2019 Michael Poole + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/** @file + * @brief ircd TLS functions using OpenBSD's libtls. + */ + +#include "config.h" +#include "client.h" +#include "ircd_features.h" +#include "ircd.h" +#include "ircd_log.h" +#include "ircd_string.h" +#include "ircd_tls.h" +#include "listener.h" +#include "s_auth.h" +#include "send.h" +#include "s_conf.h" +#include "s_debug.h" + +#include +#include +#include +#include +#include +#include + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) +const char *ircd_tls_version = "libtls " TOSTRING(TLS_API); + +int ircd_tls_init(void) +{ + static int libtls_init; + + if (EmptyString(ircd_tls_keyfile) || EmptyString(ircd_tls_certfile)) + return 0; + + if (!libtls_init) + { + libtls_init = 1; + if (tls_init() < 0) + { + log_write(LS_SYSTEM, L_ERROR, 0, "tls_init() failed"); + return 1; + } + } + + return 0; +} + +static struct tls_config *make_tls_config(const char *ciphers) +{ + struct tls_config *new_cfg; + uint32_t protos; + const char *str; + + new_cfg = tls_config_new(); + if (!new_cfg) + { + log_write(LS_SYSTEM, L_ERROR, 0, "tls_config_new() failed"); + return NULL; + } + + if (tls_config_set_keypair_file(new_cfg, ircd_tls_certfile, ircd_tls_keyfile) < 0) + { + log_write(LS_SYSTEM, L_ERROR, 0, "unable to load certificate and key: %s", + tls_config_error(new_cfg)); + goto fail; + } + + str = feature_str(FEAT_TLS_CACERTDIR); + if (!EmptyString(str)) + { + if (tls_config_set_ca_path(new_cfg, str) < 0) + { + log_write(LS_SYSTEM, L_ERROR, 0, "unable to set CA path to %s: %s", + str, tls_config_error(new_cfg)); + goto fail; + } + } + + str = feature_str(FEAT_TLS_CACERTFILE); + if (!EmptyString(str)) + { + if (tls_config_set_ca_file(new_cfg, str) < 0) + { + log_write(LS_SYSTEM, L_ERROR, 0, "unable to set CA file to %s: %s", + str, tls_config_error(new_cfg)); + goto fail; + } + } + + /* Configure verification based on self-signed certificate feature */ + if (feature_bool(FEAT_TLS_ALLOW_SELFSIGNED)) { + tls_config_verify_client_optional(new_cfg); + tls_config_insecure_noverifycert(new_cfg); + } + + protos = 0; + /* Set minimum TLS version to 1.2 (like OpenSSL) and support 1.3 */ + protos |= TLS_PROTOCOL_TLSv1_2; +#ifdef TLS_PROTOCOL_TLSv1_3 + protos |= TLS_PROTOCOL_TLSv1_3; +#endif + if (tls_config_set_protocols(new_cfg, protos) < 0) + { + log_write(LS_SYSTEM, L_ERROR, 0, "unable to select TLS versions: %s", + tls_config_error(new_cfg)); + goto fail; + } + + str = ciphers; + if (EmptyString(str)) + str = feature_str(FEAT_TLS_CIPHERS); + if (!EmptyString(str)) + { + if (tls_config_set_ciphers(new_cfg, str) < 0) + { + log_write(LS_SYSTEM, L_ERROR, 0, "unable to select TLS ciphers: %s", + tls_config_error(new_cfg)); + goto fail; + } + } + + return new_cfg; + +fail: + tls_config_free(new_cfg); + return NULL; +} + +void *ircd_tls_accept(struct Listener *listener, int fd) +{ + struct tls *tls; + + if (!listener) { + log_write(LS_SYSTEM, L_ERROR, 0, "TLS accept called with NULL listener"); + return NULL; + } + + if (!listener->tls_ctx) { + log_write(LS_SYSTEM, L_ERROR, 0, "TLS accept called with NULL tls_ctx"); + return NULL; + } + + if (tls_accept_socket((struct tls *)listener->tls_ctx, &tls, fd) < 0) + { + log_write(LS_SYSTEM, L_ERROR, 0, "TLS accept failed: %s", + tls_error((struct tls *)listener->tls_ctx)); + return NULL; + } + + return tls; +} + +void *ircd_tls_connect(struct ConfItem *aconf, int fd) +{ + struct tls_config *cfg; + struct tls *tls; + + cfg = make_tls_config(aconf->tls_ciphers); + if (!cfg) + { + return NULL; + } + + tls = tls_client(); + if (!tls) + { + log_write(LS_SYSTEM, L_ERROR, 0, "tls_client() failed"); + return NULL; + } + + if (tls_configure(tls, cfg) < 0) + { + log_write(LS_SYSTEM, L_ERROR, 0, "tls_configure failed for client: %s", + tls_error(tls)); + fail: + tls_free(tls); + return NULL; + } + + if (tls_connect_socket(tls, fd, aconf->name) < 0) + { + log_write(LS_SYSTEM, L_ERROR, 0, "tls_connect_socket failed for %s: %s", + aconf->name, tls_error(tls)); + goto fail; + } + + return tls; +} + +void ircd_tls_close(void *ctx, const char *message) +{ + /* TODO: handle TLS_WANT_POLL{IN,OUT} from tls_close() */ + tls_close(ctx); + tls_free(ctx); +} + +static IOResult tls_handle_error(struct Client *cptr, struct tls *tls, int err) +{ + switch (err) { + case TLS_WANT_POLLIN: + case TLS_WANT_POLLOUT: + return IO_BLOCKED; + + default: + /* Fatal error */ + Debug((DEBUG_DEBUG, "tls fatal error for %s: %s", cli_name(cptr), tls_error(tls))); + break; + } + tls_free(tls); + s_tls(&cli_socket(cptr)) = NULL; + return IO_FAILURE; +} + +int ircd_tls_listen(struct Listener *listener) +{ + struct tls_config *cfg; + struct tls *server_ctx; + + cfg = make_tls_config(listener->tls_ciphers); + if (!cfg) + return 1; + + if (listener->tls_ctx) + server_ctx = (struct tls *)listener->tls_ctx; + else + { + server_ctx = tls_server(); + if (!server_ctx) + { + log_write(LS_SYSTEM, L_ERROR, 0, "tls_server failed"); + tls_config_free(cfg); + return 2; + } + listener->tls_ctx = (void *)server_ctx; + } + + if (tls_configure(server_ctx, cfg) < 0) + { + const char *error = tls_error(server_ctx); + fprintf(stderr, "TLS configure failed: %s\n", error ? error : "unknown error"); + log_write(LS_SYSTEM, L_ERROR, 0, "unable to configure TLS server context: %s", + error ? error : "unknown error"); + tls_free(server_ctx); + listener->tls_ctx = NULL; + tls_config_free(cfg); + return 3; /* Return error when configuration fails */ + } + + tls_config_free(cfg); + return 0; +} + +int ircd_tls_negotiate(struct Client *cptr) +{ + const char *hash; + struct tls *tls; + int res; + const char* const error_tls = "ERROR :TLS connection error\r\n"; + + tls = s_tls(&cli_socket(cptr)); + if (!tls) + return 1; + + /* Check for handshake timeout */ + if (CurrentTime - cli_firsttime(cptr) > TLS_HANDSHAKE_TIMEOUT) { + Debug((DEBUG_DEBUG, "libtls handshake timeout for %s", cli_name(cptr))); + return -1; + } + + Debug((DEBUG_DEBUG, "libtls handshake for %s", cli_name(cptr))); + + res = tls_handshake(tls); + if (res == 0) + { + ClearNegotiatingTLS(cptr); + + hash = tls_peer_cert_hash(tls); + if (hash && !ircd_strncmp(hash, "SHA256:", 7)) + { + /* Convert the hash to our fingerprint format */ + if (strlen(hash + 7) <= 64) { + ircd_strncpy(cli_tls_fingerprint(cptr), hash + 7, 64); + Debug((DEBUG_DEBUG, "Fingerprint for %s: %s", cli_name(cptr), cli_tls_fingerprint(cptr))); + } else { + memset(cli_tls_fingerprint(cptr), 0, 65); + Debug((DEBUG_DEBUG, "Invalid fingerprint length: %zu", strlen(hash + 7))); + } + } else { + memset(cli_tls_fingerprint(cptr), 0, 65); + Debug((DEBUG_DEBUG, "Failed to get fingerprint for %s", cli_name(cptr))); + } + + return 1; + } + + if (res == TLS_WANT_POLLIN || res == TLS_WANT_POLLOUT) { + return 0; /* Handshake in progress */ + } + + IOResult tls_result = tls_handle_error(cptr, tls, res); + if (tls_result == IO_FAILURE) { + Debug((DEBUG_DEBUG, "TLS handshake failed for %s", cli_name(cptr))); + write(cli_fd(cptr), error_tls, strlen(error_tls)); + return -1; + } + /* tls_result == IO_BLOCKED - handshake still in progress */ + return 0; +} + +IOResult ircd_tls_recv(struct Client *cptr, char *buf, + unsigned int length, unsigned int *count_out) +{ + struct tls *tls; + int res; + + tls = s_tls(&cli_socket(cptr)); + if (!tls) + return IO_FAILURE; + + res = tls_read(tls, buf, length); + if (res > 0) + { + *count_out = res; + return IO_SUCCESS; + } + + return tls_handle_error(cptr, tls, res); +} + +IOResult ircd_tls_sendv(struct Client *cptr, struct MsgQ *buf, + unsigned int *count_in, unsigned int *count_out) +{ + struct iovec iov[512]; + struct tls *tls; + struct Connection *con; + IOResult result = IO_BLOCKED; + int ii, count, res; + + con = cli_connect(cptr); + tls = s_tls(&con_socket(con)); + if (!tls) + return IO_FAILURE; + + /* tls_write() does not document any restriction on retries. */ + *count_out = 0; + if (con->con_rexmit) + { + res = tls_write(tls, con->con_rexmit, con->con_rexmit_len); + if (res <= 0) { + if (res == TLS_WANT_POLLIN || res == TLS_WANT_POLLOUT) + return IO_BLOCKED; + return tls_handle_error(cptr, tls, res); + } + + // Only excise the message if the full message was sent + if (res == (int)con->con_rexmit_len) { + msgq_excise(buf, con->con_rexmit, con->con_rexmit_len); + con->con_rexmit_len = 0; + con->con_rexmit = NULL; + result = IO_SUCCESS; + } else { + // Partial send, update pointer and length for next retry + con->con_rexmit = (char *)con->con_rexmit + res; + con->con_rexmit_len -= res; + return IO_BLOCKED; + } + } + + // Process remaining messages in the queue + count = msgq_mapiov(buf, iov, sizeof(iov) / sizeof(iov[0]), count_in); + for (ii = 0; ii < count; ++ii) + { + res = tls_write(tls, iov[ii].iov_base, iov[ii].iov_len); + if (res > 0) + { + *count_out += res; + result = IO_SUCCESS; + if (res < (int)iov[ii].iov_len) { + // Partial send, store for retransmission + cli_connect(cptr)->con_rexmit = (char *)iov[ii].iov_base + res; + cli_connect(cptr)->con_rexmit_len = iov[ii].iov_len - res; + return IO_BLOCKED; + } + // else, full message sent, continue to next + continue; + } + + /* We only reach this if the tls_write failed. */ + if (res == TLS_WANT_POLLIN || res == TLS_WANT_POLLOUT) { + cli_connect(cptr)->con_rexmit = iov[ii].iov_base; + cli_connect(cptr)->con_rexmit_len = iov[ii].iov_len; + return IO_BLOCKED; + } + result = tls_handle_error(cptr, tls, res); + break; + } + + return result; +} diff --git a/ircd/tls_none.c b/ircd/tls_none.c new file mode 100644 index 00000000..977d79ab --- /dev/null +++ b/ircd/tls_none.c @@ -0,0 +1,75 @@ +/* + * IRC - Internet Relay Chat, ircd/tls_none.c + * Copyright (C) 2019 Michael Poole + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/** @file + * @brief Stub (noop) implementation of ircd TLS functions. + */ + +#include "config.h" +#include "ircd_tls.h" +#include "client.h" +#include "s_auth.h" +#include +#include + +const char *ircd_tls_version = NULL; + +int ircd_tls_init(void) +{ + return 0; +} + +void *ircd_tls_accept(struct Listener *listener, int fd) +{ + return NULL; +} + +void *ircd_tls_connect(struct ConfItem *aconf, int fd) +{ + return NULL; +} + +void ircd_tls_close(void *ctx, const char *message) +{ + return; +} + +int ircd_tls_listen(struct Listener *listener) +{ + return 0; +} + +int ircd_tls_negotiate(struct Client *cptr) +{ + ClearNegotiatingTLS(cptr); + if (!IsConnecting(cptr)) + start_auth(cptr); + return 1; +} + +IOResult ircd_tls_recv(struct Client *cptr, char *buf, + unsigned int length, unsigned int *count_out) +{ + return os_recv_nonb(cli_fd(cptr), buf, length, count_out); +} + +IOResult ircd_tls_sendv(struct Client *cptr, struct MsgQ *buf, + unsigned int *count_in, unsigned int *count_out) +{ + return os_sendv_nonb(cli_fd(cptr), buf, count_in, count_out); +} diff --git a/ircd/tls_openssl.c b/ircd/tls_openssl.c new file mode 100644 index 00000000..b56b6083 --- /dev/null +++ b/ircd/tls_openssl.c @@ -0,0 +1,559 @@ +/* + * IRC - Internet Relay Chat, ircd/tls_openssl.c + * Copyright (C) 2019 Michael Poole + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/** @file + * @brief ircd TLS functions using OpenSSL. + */ + +#include "config.h" +#include "client.h" +#include "ircd_alloc.h" +#include "ircd_features.h" +#include "ircd_log.h" +#include "ircd_string.h" +#include "ircd_tls.h" +#include "ircd.h" +#include "listener.h" +#include "s_conf.h" +#include "s_debug.h" +#include "s_auth.h" +#include "send.h" +#include "s_bsd.h" + +#include +#include +#include +#include /* IOV_MAX */ +#include /* write() on failure of ssl_accept() */ + +const char *ircd_tls_version = OPENSSL_VERSION_TEXT; + +static SSL_CTX *server_ctx; /* For incoming connections */ +static SSL_CTX *client_ctx; /* For outgoing connections */ +static const EVP_MD *fp_digest; + +static void ssl_log_error(const char *msg) +{ + unsigned long err; + char buf[BUFSIZE]; + + err = ERR_get_error(); + if (err) + { + ERR_error_string_n(err, buf, sizeof(buf)); + log_write(LS_SYSTEM, L_ERROR, 0, "OpenSSL %s: %s", msg, buf); + + while ((err = ERR_get_error()) != 0) + { + ERR_error_string_n(err, buf, sizeof(buf)); + log_write(LS_SYSTEM, L_ERROR, 0, " ... %s", buf); + } + } + else + { + log_write(LS_SYSTEM, L_ERROR, 0, "Unknown OpenSSL failure: %s", msg); + } +} + +static void ssl_set_ciphers(SSL_CTX *ctx, SSL *tls, const char *text) +{ + const char *sep; + + if (!text) + return; + + sep = strchr(text, ' '); + if (sep != NULL) + { + char *tmp; +#if HAVE_SSL_SET_CIPHERSUITES + if (ctx) + SSL_CTX_set_ciphersuites(ctx, sep + 1); + if (tls) + SSL_set_ciphersuites(tls, sep + 1); +#endif + + tmp = MyMalloc(sep + 1 - text); + ircd_strncpy(tmp, text, sep - text); + if (ctx) + SSL_CTX_set_cipher_list(ctx, tmp); + if (tls) + SSL_set_cipher_list(tls, tmp); + MyFree(tmp); + } + else if (*text != '\0') + { + if (ctx) + SSL_CTX_set_cipher_list(ctx, text); + if (tls) + SSL_set_cipher_list(tls, text); + } + else + { + if (ctx) + SSL_CTX_set_cipher_list(ctx, SSL_DEFAULT_CIPHER_LIST); + if (tls) + SSL_set_cipher_list(tls, SSL_DEFAULT_CIPHER_LIST); +#if HAVE_SSL_SET_CIPHERSUITES + if (ctx) + SSL_CTX_set_ciphersuites(ctx, TLS_DEFAULT_CIPHERSUITES); + if (tls) + SSL_set_ciphersuites(tls, TLS_DEFAULT_CIPHERSUITES); +#endif + } +} + +static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) +{ + if (!preverify_ok && feature_bool(FEAT_TLS_ALLOW_SELFSIGNED)) + { + int err = X509_STORE_CTX_get_error(ctx); + if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || + err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) + return 1; + } + return preverify_ok; +} + +int ircd_tls_init(void) +{ + static int openssl_init; + SSL_CTX *new_server_ctx = NULL; + SSL_CTX *new_client_ctx = NULL; + const char *str, *s_2; + int res; + + /* Early out if no private key or certificate file was given. */ + if (EmptyString(ircd_tls_keyfile) || EmptyString(ircd_tls_certfile)) + goto done; + + if (!openssl_init) + { + openssl_init = 1; + SSL_library_init(); + SSL_load_error_strings(); + + if (!RAND_poll()) + { + ssl_log_error("RAND_poll failed"); + return 1; + } + + fp_digest = EVP_sha256(); + } + + /* Create server context */ + new_server_ctx = SSL_CTX_new(TLS_server_method()); + if (!new_server_ctx) + { + ssl_log_error("SSL_CTX_new failed for server"); + return 2; + } + + /* Create client context */ + new_client_ctx = SSL_CTX_new(TLS_client_method()); + if (!new_client_ctx) + { + ssl_log_error("SSL_CTX_new failed for client"); + SSL_CTX_free(new_server_ctx); + return 2; + } + + /* Configure certificates and keys for both contexts */ + if (!(SSL_CTX_use_certificate_chain_file(new_server_ctx, ircd_tls_certfile) == 1 && + SSL_CTX_use_certificate_chain_file(new_client_ctx, ircd_tls_certfile) == 1)) + { + ssl_log_error("unable to load certificate file"); + goto fail; + } + + if (!(SSL_CTX_use_PrivateKey_file(new_server_ctx, ircd_tls_keyfile, SSL_FILETYPE_PEM) == 1 && + SSL_CTX_use_PrivateKey_file(new_client_ctx, ircd_tls_keyfile, SSL_FILETYPE_PEM) == 1)) + { + ssl_log_error("unable to load private key"); + goto fail; + } + + if (!(SSL_CTX_check_private_key(new_server_ctx) == 1 && + SSL_CTX_check_private_key(new_client_ctx) == 1)) + { + ssl_log_error("certificate and private key do not match"); + goto fail; + } + + /* Configure CA certificates */ + str = feature_str(FEAT_TLS_CACERTFILE); + s_2 = feature_str(FEAT_TLS_CACERTDIR); + if (!EmptyString(str) || !EmptyString(s_2)) + { + if (!EmptyString(s_2)) + { + if (!(SSL_CTX_load_verify_locations(new_server_ctx, NULL, s_2) == 1 && + SSL_CTX_load_verify_locations(new_client_ctx, NULL, s_2) == 1)) + { + ssl_log_error("unable to load CA certificates from directory"); + goto fail; + } + } + + if (!EmptyString(str)) + { + if (!(SSL_CTX_load_verify_locations(new_server_ctx, str, NULL) == 1 && + SSL_CTX_load_verify_locations(new_client_ctx, str, NULL) == 1)) + { + ssl_log_error("unable to load CA certificates from file"); + goto fail; + } + } + } + else + { + if (!(SSL_CTX_set_default_verify_paths(new_server_ctx) == 1 && + SSL_CTX_set_default_verify_paths(new_client_ctx) == 1)) + { + ssl_log_error("unable to load default CA certificates"); + goto fail; + } + } + + /* Set protocol versions. */ + SSL_CTX_set_min_proto_version(new_server_ctx, TLS1_2_VERSION); + SSL_CTX_set_min_proto_version(new_client_ctx, TLS1_2_VERSION); + + /* Configure verification */ + SSL_CTX_set_verify(new_server_ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verify_callback); + SSL_CTX_set_verify(new_client_ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verify_callback); + + SSL_CTX_set_mode(new_server_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_set_mode(new_client_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + + /* Configure ciphers */ + str = feature_str(FEAT_TLS_CIPHERS); + ssl_set_ciphers(new_server_ctx, NULL, str); + ssl_set_ciphers(new_client_ctx, NULL, str); + +done: + if (server_ctx) + SSL_CTX_free(server_ctx); + if (client_ctx) + SSL_CTX_free(client_ctx); + server_ctx = new_server_ctx; + client_ctx = new_client_ctx; + return 0; + +fail: + if (new_server_ctx) + SSL_CTX_free(new_server_ctx); + if (new_client_ctx) + SSL_CTX_free(new_client_ctx); + return 6; +} + +void ircd_tls_close(void *ctx, const char *message) +{ + SSL *ssl = ctx; + assert(ssl != NULL); + + if (!ssl) + return; + + /* Only attempt graceful shutdown if the SSL handshake completed */ + if (SSL_is_init_finished(ssl)) { + SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); + if (SSL_shutdown(ssl) == 0) + SSL_shutdown(ssl); + } + + SSL_free(ssl); +} + +static void ssl_set_fd(SSL *tls, int fd) +{ + SSL_set_fd(tls, fd); + + BIO_set_nbio(SSL_get_rbio(tls), 1); + + BIO_set_nbio(SSL_get_wbio(tls), 1); +} + +void *ircd_tls_accept(struct Listener *listener, int fd) +{ + SSL *tls; + + tls = SSL_new(server_ctx); + if (!tls) + { + ssl_log_error("unable to create SSL session"); + return NULL; + } + + if (listener && listener->tls_ciphers) + ssl_set_ciphers(NULL, tls, listener->tls_ciphers); + + ssl_set_fd(tls, fd); + + SSL_set_accept_state(tls); + + return tls; +} + +void *ircd_tls_connect(struct ConfItem *aconf, int fd) +{ + SSL *tls; + + tls = SSL_new(client_ctx); + if (!tls) + { + ssl_log_error("unable to create SSL session"); + return NULL; + } + + if (aconf->tls_ciphers) + ssl_set_ciphers(NULL, tls, aconf->tls_ciphers); + + ssl_set_fd(tls, fd); + + SSL_set_connect_state(tls); + + return tls; +} + +int ircd_tls_listen(struct Listener *listener) +{ + /* noop for OpenSSL */ + return 0; +} + +static void clear_tls_rexmit(struct Connection *con) +{ + if (con && con->con_rexmit) { + con->con_rexmit = NULL; + con->con_rexmit_len = 0; + } +} + +static IOResult ssl_handle_error(struct Client *cptr, SSL *tls, int res, int orig_errno) +{ + int err = SSL_get_error(tls, res); + + Debug((DEBUG_DEBUG, "ssl_handle_error: SSL_get_error=%d, res=%d, orig_errno=%d for %C", + err, res, orig_errno, cptr)); + + switch (err) + { + case SSL_ERROR_WANT_READ: + return IO_BLOCKED; + + case SSL_ERROR_WANT_WRITE: + return IO_BLOCKED; + + case SSL_ERROR_SYSCALL: + if (orig_errno == EINTR || orig_errno == EAGAIN || orig_errno == EWOULDBLOCK) + return IO_BLOCKED; + break; + case SSL_ERROR_ZERO_RETURN: + Debug((DEBUG_DEBUG, "SSL_ERROR_ZERO_RETURN: peer closed connection for %C", cptr)); + if (SSL_shutdown(tls) == 0) + SSL_shutdown(tls); + break; + + default: + /* Fatal SSL error */ + Debug((DEBUG_ERROR, "SSL fatal error %d for %C", err, cptr)); + unsigned long e; + while ((e = ERR_get_error()) != 0) { + Debug((DEBUG_ERROR, "SSL ERROR: %s", ERR_error_string(e, NULL))); + } + break; + } + + /* Fatal error - clean up SSL context */ + if (tls && s_tls(&cli_socket(cptr)) == tls) { + Debug((DEBUG_ERROR, "SSL fall-through fatal error %d for %C", err, cptr)); + s_tls(&cli_socket(cptr)) = NULL; + /* Do not call SSL_shutdown() after fatal errors */ + SSL_free(tls); + } + + return IO_FAILURE; +} + +int ircd_tls_negotiate(struct Client *cptr) +{ + SSL *tls; + X509 *cert; + unsigned int len; + int res; + unsigned char buf[EVP_MAX_MD_SIZE]; + const char* const error_ssl = "ERROR :SSL connection error\r\n"; + + tls = s_tls(&cli_socket(cptr)); + if (!tls) + return 1; + + /* Check for handshake timeout */ + if (CurrentTime - cli_firsttime(cptr) > TLS_HANDSHAKE_TIMEOUT) { + Debug((DEBUG_DEBUG, "SSL handshake timeout for fd=%d", cli_fd(cptr))); + return -1; + } + + /* For client connections, use SSL_connect */ + if (SSL_get_SSL_CTX(tls) == client_ctx) + res = SSL_connect(tls); + /* For server connections, use SSL_accept */ + else + res = SSL_accept(tls); + + if (res == 1) + { + Debug((DEBUG_DEBUG, "SSL handshake success for fd=%d", cli_fd(cptr))); + cert = SSL_get_peer_certificate(tls); + if (cert) + { + Debug((DEBUG_DEBUG, "SSL_get_peer_certificate success for fd=%d", cli_fd(cptr))); + len = sizeof(buf); + res = X509_digest(cert, fp_digest, buf, &len); + X509_free(cert); + if (res) + { + log_write(LS_SYSTEM, L_ERROR, 0, "X509_digest failed for %C: %d", + cptr, res); + } + if (len == 32) { + /* Convert fingerprint to lowercase hex */ + char *p = cli_tls_fingerprint(cptr); + for (unsigned int i = 0; i < len; i++) { + sprintf(p + (i * 2), "%02x", buf[i]); + } + p[len * 2] = '\0'; + Debug((DEBUG_DEBUG, "Fingerprint for %C: %s", cptr, cli_tls_fingerprint(cptr))); + } + else { + memset(cli_tls_fingerprint(cptr), 0, 65); + Debug((DEBUG_DEBUG, "Invalid length")); + } + } + ClearNegotiatingTLS(cptr); + } + else + { + int orig_errno = errno; + /* Handshake in progress. */ + IOResult ssl_result = ssl_handle_error(cptr, tls, res, orig_errno); + if (ssl_result == IO_FAILURE) { + Debug((DEBUG_DEBUG, "SSL handshake failed for fd=%d", cli_fd(cptr))); + write(cli_fd(cptr), error_ssl, strlen(error_ssl)); + return -1; + } + /* ssl_result == IO_BLOCKED - handshake still in progress */ + return 0; + } + + return res; +} + +IOResult ircd_tls_recv(struct Client *cptr, char *buf, + unsigned int length, unsigned int *count_out) +{ + SSL *tls; + int res, orig_errno; + + tls = s_tls(&cli_socket(cptr)); + if (!tls) + return IO_FAILURE; + + res = SSL_read(tls, buf, length); + if (res > 0) + { + *count_out = res; + return IO_SUCCESS; + } + + orig_errno = errno; + *count_out = 0; + + return ssl_handle_error(cptr, tls, res, orig_errno); +} + +IOResult ircd_tls_sendv(struct Client *cptr, struct MsgQ *buf, + unsigned int *count_in, + unsigned int *count_out) +{ + struct iovec iov[512]; + SSL *tls; + struct Connection *con; + IOResult result = IO_BLOCKED; + int ii, count, res, orig_errno; + + con = cli_connect(cptr); + tls = s_tls(&con_socket(con)); + if (!tls) + return IO_FAILURE; + *count_out = 0; + if (con->con_rexmit) + { + ERR_clear_error(); + res = SSL_write(tls, con->con_rexmit, con->con_rexmit_len); + if (res <= 0) { + orig_errno = errno; + return ssl_handle_error(cptr, tls, res, orig_errno); + } + + // Only excise the message if the full message was sent + if (res == (int)con->con_rexmit_len) { + msgq_excise(buf, con->con_rexmit, con->con_rexmit_len); + con->con_rexmit_len = 0; + con->con_rexmit = NULL; + result = IO_SUCCESS; + } else { + // Partial send, update pointer and length for next retry + con->con_rexmit = (char *)con->con_rexmit + res; + con->con_rexmit_len -= res; + return IO_BLOCKED; + } + } + + // Process remaining messages in the queue + count = msgq_mapiov(buf, iov, sizeof(iov) / sizeof(iov[0]), count_in); + for (ii = 0; ii < count; ++ii) + { + ERR_clear_error(); + res = SSL_write(tls, iov[ii].iov_base, iov[ii].iov_len); + if (res > 0) + { + *count_out += res; + result = IO_SUCCESS; + if (res < (int)iov[ii].iov_len) { + // Partial send, store for retransmission + cli_connect(cptr)->con_rexmit = (char *)iov[ii].iov_base + res; + cli_connect(cptr)->con_rexmit_len = iov[ii].iov_len - res; + return IO_BLOCKED; + } + // else, full message sent, continue to next + continue; + } + + /* We only reach this if the SSL_write failed. */ + orig_errno = errno; + cli_connect(cptr)->con_rexmit = iov[ii].iov_base; + cli_connect(cptr)->con_rexmit_len = iov[ii].iov_len; + return ssl_handle_error(cptr, tls, res, orig_errno); + } + + return result; +} diff --git a/ircd/whocmds.c b/ircd/whocmds.c index 0b166ba0..9a02a231 100644 --- a/ircd/whocmds.c +++ b/ircd/whocmds.c @@ -208,6 +208,8 @@ void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan, } if (HasHiddenHost(acptr)) *(p1++) = 'x'; + if (IsTLS(acptr)) + *(p1++) = 'z'; } if (!fields || (fields & WHO_FIELD_DIS))