summaryrefslogtreecommitdiff
path: root/src/libradius
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@corsac.net>2012-06-28 21:16:07 +0200
committerYves-Alexis Perez <corsac@corsac.net>2012-06-28 21:16:07 +0200
commitb34738ed08c2227300d554b139e2495ca5da97d6 (patch)
tree62f33b52820f2e49f0e53c0f8c636312037c8054 /src/libradius
parent0a9d51a49042a68daa15b0c74a2b7f152f52606b (diff)
downloadvyos-strongswan-b34738ed08c2227300d554b139e2495ca5da97d6.tar.gz
vyos-strongswan-b34738ed08c2227300d554b139e2495ca5da97d6.zip
Imported Upstream version 4.6.4
Diffstat (limited to 'src/libradius')
-rw-r--r--src/libradius/Makefile.am11
-rw-r--r--src/libradius/Makefile.in598
-rw-r--r--src/libradius/radius_client.c157
-rw-r--r--src/libradius/radius_client.h68
-rw-r--r--src/libradius/radius_config.c221
-rw-r--r--src/libradius/radius_config.h100
-rw-r--r--src/libradius/radius_message.c515
-rw-r--r--src/libradius/radius_message.h302
-rw-r--r--src/libradius/radius_mppe.h40
-rw-r--r--src/libradius/radius_socket.c373
-rw-r--r--src/libradius/radius_socket.h77
11 files changed, 2462 insertions, 0 deletions
diff --git a/src/libradius/Makefile.am b/src/libradius/Makefile.am
new file mode 100644
index 000000000..5672f7b84
--- /dev/null
+++ b/src/libradius/Makefile.am
@@ -0,0 +1,11 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan
+
+ipseclib_LTLIBRARIES = libradius.la
+libradius_la_SOURCES = \
+ radius_message.h radius_message.c \
+ radius_socket.h radius_socket.c \
+ radius_client.h radius_client.c \
+ radius_config.h radius_config.c \
+ radius_mppe.h
+
diff --git a/src/libradius/Makefile.in b/src/libradius/Makefile.in
new file mode 100644
index 000000000..bcc38792a
--- /dev/null
+++ b/src/libradius/Makefile.in
@@ -0,0 +1,598 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/libradius
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \
+ $(top_srcdir)/m4/config/ltoptions.m4 \
+ $(top_srcdir)/m4/config/ltsugar.m4 \
+ $(top_srcdir)/m4/config/ltversion.m4 \
+ $(top_srcdir)/m4/config/lt~obsolete.m4 \
+ $(top_srcdir)/m4/macros/with.m4 \
+ $(top_srcdir)/m4/macros/enable-disable.m4 \
+ $(top_srcdir)/m4/macros/add-plugin.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(ipseclibdir)"
+LTLIBRARIES = $(ipseclib_LTLIBRARIES)
+libradius_la_LIBADD =
+am_libradius_la_OBJECTS = radius_message.lo radius_socket.lo \
+ radius_client.lo radius_config.lo
+libradius_la_OBJECTS = $(am_libradius_la_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libradius_la_SOURCES)
+DIST_SOURCES = $(libradius_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BTLIB = @BTLIB@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLIB = @DLLIB@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MYSQLCFLAG = @MYSQLCFLAG@
+MYSQLCONFIG = @MYSQLCONFIG@
+MYSQLLIB = @MYSQLLIB@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREADLIB = @PTHREADLIB@
+RANLIB = @RANLIB@
+RTLIB = @RTLIB@
+RUBY = @RUBY@
+RUBYINCLUDE = @RUBYINCLUDE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKLIB = @SOCKLIB@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+attest_plugins = @attest_plugins@
+axis2c_CFLAGS = @axis2c_CFLAGS@
+axis2c_LIBS = @axis2c_LIBS@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+c_plugins = @c_plugins@
+clearsilver_LIBS = @clearsilver_LIBS@
+datadir = @datadir@
+datarootdir = @datarootdir@
+dbusservicedir = @dbusservicedir@
+default_pkcs11 = @default_pkcs11@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gtk_CFLAGS = @gtk_CFLAGS@
+gtk_LIBS = @gtk_LIBS@
+h_plugins = @h_plugins@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+imcvdir = @imcvdir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+ipsecgroup = @ipsecgroup@
+ipseclibdir = @ipseclibdir@
+ipsecuser = @ipsecuser@
+libcharon_plugins = @libcharon_plugins@
+libdir = @libdir@
+libexecdir = @libexecdir@
+linux_headers = @linux_headers@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+maemo_CFLAGS = @maemo_CFLAGS@
+maemo_LIBS = @maemo_LIBS@
+manager_plugins = @manager_plugins@
+mandir = @mandir@
+medsrv_plugins = @medsrv_plugins@
+mkdir_p = @mkdir_p@
+nm_CFLAGS = @nm_CFLAGS@
+nm_LIBS = @nm_LIBS@
+nm_ca_dir = @nm_ca_dir@
+oldincludedir = @oldincludedir@
+openac_plugins = @openac_plugins@
+p_plugins = @p_plugins@
+pcsclite_CFLAGS = @pcsclite_CFLAGS@
+pcsclite_LIBS = @pcsclite_LIBS@
+pdfdir = @pdfdir@
+piddir = @piddir@
+pki_plugins = @pki_plugins@
+plugindir = @plugindir@
+pluto_plugins = @pluto_plugins@
+pool_plugins = @pool_plugins@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+random_device = @random_device@
+resolv_conf = @resolv_conf@
+routing_table = @routing_table@
+routing_table_prio = @routing_table_prio@
+s_plugins = @s_plugins@
+sbindir = @sbindir@
+scepclient_plugins = @scepclient_plugins@
+scripts_plugins = @scripts_plugins@
+sharedstatedir = @sharedstatedir@
+soup_CFLAGS = @soup_CFLAGS@
+soup_LIBS = @soup_LIBS@
+srcdir = @srcdir@
+starter_plugins = @starter_plugins@
+strongswan_conf = @strongswan_conf@
+sysconfdir = @sysconfdir@
+systemdsystemunitdir = @systemdsystemunitdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+urandom_device = @urandom_device@
+xml_CFLAGS = @xml_CFLAGS@
+xml_LIBS = @xml_LIBS@
+INCLUDES = -I$(top_srcdir)/src/libstrongswan
+ipseclib_LTLIBRARIES = libradius.la
+libradius_la_SOURCES = \
+ radius_message.h radius_message.c \
+ radius_socket.h radius_socket.c \
+ radius_client.h radius_client.c \
+ radius_config.h radius_config.c \
+ radius_mppe.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libradius/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/libradius/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-ipseclibLTLIBRARIES: $(ipseclib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(ipseclibdir)" || $(MKDIR_P) "$(DESTDIR)$(ipseclibdir)"
+ @list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(ipseclibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(ipseclibdir)"; \
+ }
+
+uninstall-ipseclibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(ipseclibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(ipseclibdir)/$$f"; \
+ done
+
+clean-ipseclibLTLIBRARIES:
+ -test -z "$(ipseclib_LTLIBRARIES)" || rm -f $(ipseclib_LTLIBRARIES)
+ @list='$(ipseclib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libradius.la: $(libradius_la_OBJECTS) $(libradius_la_DEPENDENCIES)
+ $(LINK) -rpath $(ipseclibdir) $(libradius_la_OBJECTS) $(libradius_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radius_client.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radius_config.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radius_message.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radius_socket.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(ipseclibdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-ipseclibLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-ipseclibLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-ipseclibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-ipseclibLTLIBRARIES clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am \
+ install-ipseclibLTLIBRARIES install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-ipseclibLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/libradius/radius_client.c b/src/libradius/radius_client.c
new file mode 100644
index 000000000..acdac78c9
--- /dev/null
+++ b/src/libradius/radius_client.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2009 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include "radius_client.h"
+#include "radius_config.h"
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <debug.h>
+#include <utils/host.h>
+#include <utils/linked_list.h>
+#include <threading/condvar.h>
+#include <threading/mutex.h>
+
+typedef struct private_radius_client_t private_radius_client_t;
+
+/**
+ * Private data of an radius_client_t object.
+ */
+struct private_radius_client_t {
+
+ /**
+ * Public radius_client_t interface.
+ */
+ radius_client_t public;
+
+ /**
+ * Selected RADIUS server configuration
+ */
+ radius_config_t *config;
+
+ /**
+ * RADIUS servers State attribute
+ */
+ chunk_t state;
+
+ /**
+ * EAP MSK, from MPPE keys
+ */
+ chunk_t msk;
+};
+
+/**
+ * Save the state attribute to include in further request
+ */
+static void save_state(private_radius_client_t *this, radius_message_t *msg)
+{
+ enumerator_t *enumerator;
+ int type;
+ chunk_t data;
+
+ enumerator = msg->create_enumerator(msg);
+ while (enumerator->enumerate(enumerator, &type, &data))
+ {
+ if (type == RAT_STATE)
+ {
+ free(this->state.ptr);
+ this->state = chunk_clone(data);
+ enumerator->destroy(enumerator);
+ return;
+ }
+ }
+ enumerator->destroy(enumerator);
+ /* no state attribute found, remove state */
+ chunk_free(&this->state);
+}
+
+METHOD(radius_client_t, request, radius_message_t*,
+ private_radius_client_t *this, radius_message_t *req)
+{
+ char virtual[] = {0x00,0x00,0x00,0x05};
+ radius_socket_t *socket;
+ radius_message_t *res;
+ chunk_t data;
+
+ /* we add the "Virtual" NAS-Port-Type, as we SHOULD include one */
+ req->add(req, RAT_NAS_PORT_TYPE, chunk_create(virtual, sizeof(virtual)));
+ /* add our NAS-Identifier */
+ req->add(req, RAT_NAS_IDENTIFIER,
+ this->config->get_nas_identifier(this->config));
+ /* add State attribute, if server sent one */
+ if (this->state.ptr)
+ {
+ req->add(req, RAT_STATE, this->state);
+ }
+ socket = this->config->get_socket(this->config);
+ DBG1(DBG_CFG, "sending RADIUS %N to server '%s'", radius_message_code_names,
+ req->get_code(req), this->config->get_name(this->config));
+
+ res = socket->request(socket, req);
+ if (res)
+ {
+ DBG1(DBG_CFG, "received RADIUS %N from server '%s'",
+ radius_message_code_names, res->get_code(res),
+ this->config->get_name(this->config));
+ data = res->get_encoding(res);
+ DBG3(DBG_CFG, "%B", &data);
+
+ save_state(this, res);
+ if (res->get_code(res) == RMC_ACCESS_ACCEPT)
+ {
+ chunk_clear(&this->msk);
+ this->msk = socket->decrypt_msk(socket, req, res);
+ }
+ this->config->put_socket(this->config, socket, TRUE);
+ return res;
+ }
+ this->config->put_socket(this->config, socket, FALSE);
+ return NULL;
+}
+
+METHOD(radius_client_t, get_msk, chunk_t,
+ private_radius_client_t *this)
+{
+ return this->msk;
+}
+
+METHOD(radius_client_t, destroy, void,
+ private_radius_client_t *this)
+{
+ this->config->destroy(this->config);
+ chunk_clear(&this->msk);
+ free(this->state.ptr);
+ free(this);
+}
+
+/**
+ * See header
+ */
+radius_client_t *radius_client_create(radius_config_t *config)
+{
+ private_radius_client_t *this;
+
+ INIT(this,
+ .public = {
+ .request = _request,
+ .get_msk = _get_msk,
+ .destroy = _destroy,
+ },
+ .config = config,
+ );
+
+ return &this->public;
+}
diff --git a/src/libradius/radius_client.h b/src/libradius/radius_client.h
new file mode 100644
index 000000000..cf5f79b6c
--- /dev/null
+++ b/src/libradius/radius_client.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup radius_client radius_client
+ * @{ @ingroup libradius
+ */
+
+#ifndef RADIUS_CLIENT_H_
+#define RADIUS_CLIENT_H_
+
+#include "radius_message.h"
+#include "radius_config.h"
+
+typedef struct radius_client_t radius_client_t;
+
+/**
+ * RADIUS client functionality.
+ *
+ * To communicate with a RADIUS server, create a client and send messages over
+ * it. The client allocates a socket from the best RADIUS server abailable.
+ */
+struct radius_client_t {
+
+ /**
+ * Send a RADIUS request and wait for the response.
+ *
+ * The client fills in NAS-Identifier nad NAS-Port-Type
+ *
+ * @param msg RADIUS request message to send
+ * @return response, NULL if timed out/verification failed
+ */
+ radius_message_t* (*request)(radius_client_t *this, radius_message_t *msg);
+
+ /**
+ * Get the EAP MSK after successful RADIUS authentication.
+ *
+ * @return MSK, allocated
+ */
+ chunk_t (*get_msk)(radius_client_t *this);
+
+ /**
+ * Destroy the client, release the socket.
+ */
+ void (*destroy)(radius_client_t *this);
+};
+
+/**
+ * Create a RADIUS client.
+ *
+ * @param config reference to a server configuration, gets owned
+ * @return radius_client_t object
+ */
+radius_client_t *radius_client_create(radius_config_t *config);
+
+#endif /** RADIUS_CLIENT_H_ @}*/
diff --git a/src/libradius/radius_config.c b/src/libradius/radius_config.c
new file mode 100644
index 000000000..6e3394bb0
--- /dev/null
+++ b/src/libradius/radius_config.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include "radius_config.h"
+
+#include <threading/mutex.h>
+#include <threading/condvar.h>
+#include <utils/linked_list.h>
+
+typedef struct private_radius_config_t private_radius_config_t;
+
+/**
+ * Private data of an radius_config_t object.
+ */
+struct private_radius_config_t {
+
+ /**
+ * Public radius_config_t interface.
+ */
+ radius_config_t public;
+
+ /**
+ * list of radius sockets, as radius_socket_t
+ */
+ linked_list_t *sockets;
+
+ /**
+ * Total number of sockets, in list + currently in use
+ */
+ int socket_count;
+
+ /**
+ * mutex to lock sockets list
+ */
+ mutex_t *mutex;
+
+ /**
+ * condvar to wait for sockets
+ */
+ condvar_t *condvar;
+
+ /**
+ * Server name
+ */
+ char *name;
+
+ /**
+ * NAS-Identifier
+ */
+ chunk_t nas_identifier;
+
+ /**
+ * Preference boost for this server
+ */
+ int preference;
+
+ /**
+ * Is the server currently reachable
+ */
+ bool reachable;
+
+ /**
+ * Retry counter for unreachable servers
+ */
+ int retry;
+
+ /**
+ * reference count
+ */
+ refcount_t ref;
+};
+
+METHOD(radius_config_t, get_socket, radius_socket_t*,
+ private_radius_config_t *this)
+{
+ radius_socket_t *skt;
+
+ this->mutex->lock(this->mutex);
+ while (this->sockets->remove_first(this->sockets, (void**)&skt) != SUCCESS)
+ {
+ this->condvar->wait(this->condvar, this->mutex);
+ }
+ this->mutex->unlock(this->mutex);
+ return skt;
+}
+
+METHOD(radius_config_t, put_socket, void,
+ private_radius_config_t *this, radius_socket_t *skt, bool result)
+{
+ this->mutex->lock(this->mutex);
+ this->sockets->insert_last(this->sockets, skt);
+ this->mutex->unlock(this->mutex);
+ this->condvar->signal(this->condvar);
+ this->reachable = result;
+}
+
+METHOD(radius_config_t, get_nas_identifier, chunk_t,
+ private_radius_config_t *this)
+{
+ return this->nas_identifier;
+}
+
+METHOD(radius_config_t, get_preference, int,
+ private_radius_config_t *this)
+{
+ int pref;
+
+ if (this->socket_count == 0)
+ { /* don't have sockets, huh? */
+ return -1;
+ }
+ /* calculate preference between 0-100 + boost */
+ pref = this->preference;
+ pref += this->sockets->get_count(this->sockets) * 100 / this->socket_count;
+ if (this->reachable)
+ { /* reachable server get a boost: pref = 110-210 + boost */
+ return pref + 110;
+ }
+ /* Not reachable. Increase preference randomly to let it retry from
+ * time to time, especially if other servers have high load. */
+ this->retry++;
+ if (this->retry % 128 == 0)
+ { /* every 64th request gets 210, same as unloaded reachable */
+ return pref + 110;
+ }
+ if (this->retry % 32 == 0)
+ { /* every 32th request gets 190, wins against average loaded */
+ return pref + 90;
+ }
+ if (this->retry % 8 == 0)
+ { /* every 8th request gets 110, same as server under load */
+ return pref + 10;
+ }
+ /* other get ~100, less than fully loaded */
+ return pref;
+}
+
+METHOD(radius_config_t, get_name, char*,
+ private_radius_config_t *this)
+{
+ return this->name;
+}
+
+METHOD(radius_config_t, get_ref, radius_config_t*,
+ private_radius_config_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public;
+}
+
+
+METHOD(radius_config_t, destroy, void,
+ private_radius_config_t *this)
+{
+ if (ref_put(&this->ref))
+ {
+ this->mutex->destroy(this->mutex);
+ this->condvar->destroy(this->condvar);
+ this->sockets->destroy_offset(this->sockets,
+ offsetof(radius_socket_t, destroy));
+ free(this);
+ }
+}
+
+/**
+ * See header
+ */
+radius_config_t *radius_config_create(char *name, char *address,
+ u_int16_t auth_port, u_int16_t acct_port,
+ char *nas_identifier, char *secret,
+ int sockets, int preference)
+{
+ private_radius_config_t *this;
+ radius_socket_t *socket;
+
+ INIT(this,
+ .public = {
+ .get_socket = _get_socket,
+ .put_socket = _put_socket,
+ .get_nas_identifier = _get_nas_identifier,
+ .get_preference = _get_preference,
+ .get_name = _get_name,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .reachable = TRUE,
+ .nas_identifier = chunk_create(nas_identifier, strlen(nas_identifier)),
+ .socket_count = sockets,
+ .sockets = linked_list_create(),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
+ .name = name,
+ .preference = preference,
+ .ref = 1,
+ );
+
+ while (sockets--)
+ {
+ socket = radius_socket_create(address, auth_port, acct_port,
+ chunk_create(secret, strlen(secret)));
+ if (!socket)
+ {
+ destroy(this);
+ return NULL;
+ }
+ this->sockets->insert_last(this->sockets, socket);
+ }
+ return &this->public;
+}
diff --git a/src/libradius/radius_config.h b/src/libradius/radius_config.h
new file mode 100644
index 000000000..40ed6197a
--- /dev/null
+++ b/src/libradius/radius_config.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup radius_config radius_config
+ * @{ @ingroup libradius
+ */
+
+#ifndef RADIUS_CONFIG_H_
+#define RADIUS_CONFIG_H_
+
+typedef struct radius_config_t radius_config_t;
+
+#include "radius_socket.h"
+
+/**
+ * RADIUS server configuration.
+ */
+struct radius_config_t {
+
+ /**
+ * Get a RADIUS socket from the pool to communicate with this config.
+ *
+ * @return RADIUS socket
+ */
+ radius_socket_t* (*get_socket)(radius_config_t *this);
+
+ /**
+ * Release a socket to the pool after use.
+ *
+ * @param skt RADIUS socket to release
+ * @param result result of the socket use, TRUE for success
+ */
+ void (*put_socket)(radius_config_t *this, radius_socket_t *skt, bool result);
+
+ /**
+ * Get the NAS-Identifier to use with this server.
+ *
+ * @return NAS-Identifier, internal data
+ */
+ chunk_t (*get_nas_identifier)(radius_config_t *this);
+
+ /**
+ * Get the preference of this server.
+ *
+ * Based on the available sockets and the server reachability a preference
+ * value is calculated: better servers return a higher value.
+ */
+ int (*get_preference)(radius_config_t *this);
+
+ /**
+ * Get the name of the RADIUS server.
+ *
+ * @return server name
+ */
+ char* (*get_name)(radius_config_t *this);
+
+ /**
+ * Increase reference count of this server configuration.
+ *
+ * @return this
+ */
+ radius_config_t* (*get_ref)(radius_config_t *this);
+
+ /**
+ * Destroy a radius_config_t.
+ */
+ void (*destroy)(radius_config_t *this);
+};
+
+/**
+ * Create a radius_config_t instance.
+ *
+ * @param name server name
+ * @param address server address
+ * @param auth_port server port for authentication
+ * @param acct_port server port for accounting
+ * @param nas_identifier NAS-Identifier to use with this server
+ * @param secret secret to use with this server
+ * @param sockets number of sockets to create in pool
+ * @param preference preference boost for this server
+ */
+radius_config_t *radius_config_create(char *name, char *address,
+ u_int16_t auth_port, u_int16_t acct_port,
+ char *nas_identifier, char *secret,
+ int sockets, int preference);
+
+#endif /** RADIUS_CONFIG_H_ @}*/
diff --git a/src/libradius/radius_message.c b/src/libradius/radius_message.c
new file mode 100644
index 000000000..17fa7357b
--- /dev/null
+++ b/src/libradius/radius_message.c
@@ -0,0 +1,515 @@
+/*
+ * Copyright (C) 2009 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include "radius_message.h"
+
+#include <debug.h>
+#include <crypto/hashers/hasher.h>
+
+typedef struct private_radius_message_t private_radius_message_t;
+typedef struct rmsg_t rmsg_t;
+typedef struct rattr_t rattr_t;
+
+/**
+ * RADIUS message header
+ */
+struct rmsg_t {
+ /** message code, radius_message_code_t */
+ u_int8_t code;
+ /** message identifier */
+ u_int8_t identifier;
+ /** length of Code, Identifier, Length, Authenticator and Attributes */
+ u_int16_t length;
+ /** message authenticator, MD5 hash */
+ u_int8_t authenticator[HASH_SIZE_MD5];
+ /** variable list of packed attributes */
+ u_int8_t attributes[];
+} __attribute__((packed));
+
+/**
+ * RADIUS message attribute.
+ */
+struct rattr_t {
+ /** attribute type, radius_attribute_type_t */
+ u_int8_t type;
+ /** length of the attriubte, including the Type, Length and Value fields */
+ u_int8_t length;
+ /** variable length attribute value */
+ u_int8_t value[];
+} __attribute__((packed));
+
+/**
+ * Private data of an radius_message_t object.
+ */
+struct private_radius_message_t {
+
+ /**
+ * Public radius_message_t interface.
+ */
+ radius_message_t public;
+
+ /**
+ * message data, allocated
+ */
+ rmsg_t *msg;
+};
+
+/**
+ * Described in header.
+ */
+void libradius_init(void)
+{
+ /* empty */
+}
+
+ENUM_BEGIN(radius_message_code_names, RMC_ACCESS_REQUEST, RMC_ACCOUNTING_RESPONSE,
+ "Access-Request",
+ "Access-Accept",
+ "Access-Reject",
+ "Accounting-Request",
+ "Accounting-Response");
+ENUM_NEXT(radius_message_code_names, RMC_ACCESS_CHALLENGE, RMC_ACCESS_CHALLENGE, RMC_ACCOUNTING_RESPONSE,
+ "Access-Challenge");
+ENUM_NEXT(radius_message_code_names, RMC_DISCONNECT_REQUEST, RMC_COA_NAK, RMC_ACCESS_CHALLENGE,
+ "Disconnect-Request",
+ "Disconnect-ACK",
+ "Disconnect-NAK",
+ "CoA-Request",
+ "CoA-ACK",
+ "CoA-NAK");
+ENUM_END(radius_message_code_names, RMC_COA_NAK);
+
+ENUM(radius_attribute_type_names, RAT_USER_NAME, RAT_MIP6_HOME_LINK_PREFIX,
+ "User-Name",
+ "User-Password",
+ "CHAP-Password",
+ "NAS-IP-Address",
+ "NAS-Port",
+ "Service-Type",
+ "Framed-Protocol",
+ "Framed-IP-Address",
+ "Framed-IP-Netmask",
+ "Framed-Routing",
+ "Filter-Id",
+ "Framed-MTU",
+ "Framed-Compression",
+ "Login-IP-Host",
+ "Login-Service",
+ "Login-TCP-Port",
+ "Unassigned",
+ "Reply-Message",
+ "Callback-Number",
+ "Callback-Id",
+ "Unassigned",
+ "Framed-Route",
+ "Framed-IPX-Network",
+ "State",
+ "Class",
+ "Vendor-Specific",
+ "Session-Timeout",
+ "Idle-Timeout",
+ "Termination-Action",
+ "Called-Station-Id",
+ "Calling-Station-Id",
+ "NAS-Identifier",
+ "Proxy-State",
+ "Login-LAT-Service",
+ "Login-LAT-Node",
+ "Login-LAT-Group",
+ "Framed-AppleTalk-Link",
+ "Framed-AppleTalk-Network",
+ "Framed-AppleTalk-Zone",
+ "Acct-Status-Type",
+ "Acct-Delay-Time",
+ "Acct-Input-Octets",
+ "Acct-Output-Octets",
+ "Acct-Session-Id",
+ "Acct-Authentic",
+ "Acct-Session-Time",
+ "Acct-Input-Packets",
+ "Acct-Output-Packets",
+ "Acct-Terminate-Cause",
+ "Acct-Multi-Session-Id",
+ "Acct-Link-Count",
+ "Acct-Input-Gigawords",
+ "Acct-Output-Gigawords",
+ "Unassigned",
+ "Event-Timestamp",
+ "Egress-VLANID",
+ "Ingress-Filters",
+ "Egress-VLAN-Name",
+ "User-Priority-Table",
+ "CHAP-Challenge",
+ "NAS-Port-Type",
+ "Port-Limit",
+ "Login-LAT-Port",
+ "Tunnel-Type",
+ "Tunnel-Medium-Type",
+ "Tunnel-Client-Endpoint",
+ "Tunnel-Server-Endpoint",
+ "Acct-Tunnel-Connection",
+ "Tunnel-Password",
+ "ARAP-Password",
+ "ARAP-Features",
+ "ARAP-Zone-Access",
+ "ARAP-Security",
+ "ARAP-Security-Data",
+ "Password-Retry",
+ "Prompt",
+ "Connect-Info",
+ "Configuration-Token",
+ "EAP-Message",
+ "Message-Authenticator",
+ "Tunnel-Private-Group-ID",
+ "Tunnel-Assignment-ID",
+ "Tunnel-Preference",
+ "ARAP-Challenge-Response",
+ "Acct-Interim-Interval",
+ "Acct-Tunnel-Packets-Lost",
+ "NAS-Port-Id",
+ "Framed-Pool",
+ "CUI",
+ "Tunnel-Client-Auth-ID",
+ "Tunnel-Server-Auth-ID",
+ "NAS-Filter-Rule",
+ "Unassigned",
+ "Originating-Line-Info",
+ "NAS-IPv6-Address",
+ "Framed-Interface-Id",
+ "Framed-IPv6-Prefix",
+ "Login-IPv6-Host",
+ "Framed-IPv6-Route",
+ "Framed-IPv6-Pool",
+ "Error-Cause",
+ "EAP-Key-Name",
+ "Digest-Response",
+ "Digest-Realm",
+ "Digest-Nonce",
+ "Digest-Response-Auth",
+ "Digest-Nextnonce",
+ "Digest-Method",
+ "Digest-URI",
+ "Digest-Qop",
+ "Digest-Algorithm",
+ "Digest-Entity-Body-Hash",
+ "Digest-CNonce",
+ "Digest-Nonce-Count",
+ "Digest-Username",
+ "Digest-Opaque",
+ "Digest-Auth-Param",
+ "Digest-AKA-Auts",
+ "Digest-Domain",
+ "Digest-Stale",
+ "Digest-HA1",
+ "SIP-AOR",
+ "Delegated-IPv6-Prefix",
+ "MIP6-Feature-Vector",
+ "MIP6-Home-Link-Prefix");
+
+/**
+ * Attribute enumerator implementation
+ */
+typedef struct {
+ /** implements enumerator interface */
+ enumerator_t public;
+ /** currently pointing attribute */
+ rattr_t *next;
+ /** bytes left */
+ int left;
+} attribute_enumerator_t;
+
+METHOD(enumerator_t, attribute_enumerate, bool,
+ attribute_enumerator_t *this, int *type, chunk_t *data)
+{
+ if (this->left == 0)
+ {
+ return FALSE;
+ }
+ if (this->left < sizeof(rattr_t) ||
+ this->left < this->next->length)
+ {
+ DBG1(DBG_IKE, "RADIUS message truncated");
+ return FALSE;
+ }
+ *type = this->next->type;
+ data->ptr = this->next->value;
+ data->len = this->next->length - sizeof(rattr_t);
+ this->left -= this->next->length;
+ this->next = ((void*)this->next) + this->next->length;
+ return TRUE;
+}
+
+METHOD(radius_message_t, create_enumerator, enumerator_t*,
+ private_radius_message_t *this)
+{
+ attribute_enumerator_t *e;
+
+ if (ntohs(this->msg->length) < sizeof(rmsg_t) + sizeof(rattr_t))
+ {
+ return enumerator_create_empty();
+ }
+ INIT(e,
+ .public = {
+ .enumerate = (void*)_attribute_enumerate,
+ .destroy = (void*)free,
+ },
+ .next = (rattr_t*)this->msg->attributes,
+ .left = ntohs(this->msg->length) - sizeof(rmsg_t),
+ );
+ return &e->public;
+}
+
+METHOD(radius_message_t, add, void,
+ private_radius_message_t *this, radius_attribute_type_t type, chunk_t data)
+{
+ rattr_t *attribute;
+
+ data.len = min(data.len, MAX_RADIUS_ATTRIBUTE_SIZE);
+ this->msg = realloc(this->msg,
+ ntohs(this->msg->length) + sizeof(rattr_t) + data.len);
+ attribute = ((void*)this->msg) + ntohs(this->msg->length);
+ attribute->type = type;
+ attribute->length = data.len + sizeof(rattr_t);
+ memcpy(attribute->value, data.ptr, data.len);
+ this->msg->length = htons(ntohs(this->msg->length) + attribute->length);
+}
+
+METHOD(radius_message_t, sign, void,
+ private_radius_message_t *this, u_int8_t *req_auth, chunk_t secret,
+ hasher_t *hasher, signer_t *signer, rng_t *rng, bool msg_auth)
+{
+ if (rng)
+ {
+ /* build Request-Authenticator */
+ rng->get_bytes(rng, HASH_SIZE_MD5, this->msg->authenticator);
+ }
+ else
+ {
+ /* prepare build of Response-Authenticator */
+ if (req_auth)
+ {
+ memcpy(this->msg->authenticator, req_auth, HASH_SIZE_MD5);
+ }
+ else
+ {
+ memset(this->msg->authenticator, 0, sizeof(this->msg->authenticator));
+ }
+ }
+
+ if (msg_auth)
+ {
+ char buf[HASH_SIZE_MD5];
+
+ /* build Message-Authenticator attribute, using 16 null bytes */
+ memset(buf, 0, sizeof(buf));
+ add(this, RAT_MESSAGE_AUTHENTICATOR, chunk_create(buf, sizeof(buf)));
+ signer->get_signature(signer,
+ chunk_create((u_char*)this->msg, ntohs(this->msg->length)),
+ ((u_char*)this->msg) + ntohs(this->msg->length) - HASH_SIZE_MD5);
+ }
+
+ if (!rng)
+ {
+ chunk_t msg;
+
+ /* build Response-Authenticator */
+ msg = chunk_create((u_char*)this->msg, ntohs(this->msg->length));
+ hasher->get_hash(hasher, msg, NULL);
+ hasher->get_hash(hasher, secret, this->msg->authenticator);
+ }
+}
+
+METHOD(radius_message_t, verify, bool,
+ private_radius_message_t *this, u_int8_t *req_auth, chunk_t secret,
+ hasher_t *hasher, signer_t *signer)
+{
+ char buf[HASH_SIZE_MD5], res_auth[HASH_SIZE_MD5];
+ enumerator_t *enumerator;
+ int type;
+ chunk_t data, msg;
+ bool has_eap = FALSE, has_auth = FALSE;
+
+ msg = chunk_create((u_char*)this->msg, ntohs(this->msg->length));
+
+ if (this->msg->code != RMC_ACCESS_REQUEST)
+ {
+ /* replace Response by Request Authenticator for verification */
+ memcpy(res_auth, this->msg->authenticator, HASH_SIZE_MD5);
+ if (req_auth)
+ {
+ memcpy(this->msg->authenticator, req_auth, HASH_SIZE_MD5);
+ }
+ else
+ {
+ memset(this->msg->authenticator, 0, HASH_SIZE_MD5);
+ }
+
+ /* verify Response-Authenticator */
+ hasher->get_hash(hasher, msg, NULL);
+ hasher->get_hash(hasher, secret, buf);
+ if (!memeq(buf, res_auth, HASH_SIZE_MD5))
+ {
+ DBG1(DBG_CFG, "RADIUS Response-Authenticator verification failed");
+ return FALSE;
+ }
+ }
+
+ /* verify Message-Authenticator attribute */
+ enumerator = create_enumerator(this);
+ while (enumerator->enumerate(enumerator, &type, &data))
+ {
+ if (type == RAT_MESSAGE_AUTHENTICATOR)
+ {
+ if (data.len != HASH_SIZE_MD5)
+ {
+ DBG1(DBG_CFG, "RADIUS Message-Authenticator invalid length");
+ enumerator->destroy(enumerator);
+ return FALSE;
+ }
+ memcpy(buf, data.ptr, data.len);
+ memset(data.ptr, 0, data.len);
+ if (signer->verify_signature(signer, msg,
+ chunk_create(buf, sizeof(buf))))
+ {
+ /* restore Message-Authenticator */
+ memcpy(data.ptr, buf, data.len);
+ has_auth = TRUE;
+ break;
+ }
+ else
+ {
+ DBG1(DBG_CFG, "RADIUS Message-Authenticator verification failed");
+ enumerator->destroy(enumerator);
+ return FALSE;
+ }
+ }
+ else if (type == RAT_EAP_MESSAGE)
+ {
+ has_eap = TRUE;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (this->msg->code != RMC_ACCESS_REQUEST)
+ {
+ /* restore Response-Authenticator */
+ memcpy(this->msg->authenticator, res_auth, HASH_SIZE_MD5);
+ }
+
+ if (has_eap && !has_auth)
+ { /* Message-Authenticator is required if we have an EAP-Message */
+ DBG1(DBG_CFG, "RADIUS Message-Authenticator attribute missing");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(radius_message_t, get_code, radius_message_code_t,
+ private_radius_message_t *this)
+{
+ return this->msg->code;
+}
+
+METHOD(radius_message_t, get_identifier, u_int8_t,
+ private_radius_message_t *this)
+{
+ return this->msg->identifier;
+}
+
+METHOD(radius_message_t, set_identifier, void,
+ private_radius_message_t *this, u_int8_t identifier)
+{
+ this->msg->identifier = identifier;
+}
+
+METHOD(radius_message_t, get_authenticator, u_int8_t*,
+ private_radius_message_t *this)
+{
+ return this->msg->authenticator;
+}
+
+
+METHOD(radius_message_t, get_encoding, chunk_t,
+ private_radius_message_t *this)
+{
+ return chunk_create((u_char*)this->msg, ntohs(this->msg->length));
+}
+
+METHOD(radius_message_t, destroy, void,
+ private_radius_message_t *this)
+{
+ free(this->msg);
+ free(this);
+}
+
+/**
+ * Generic constructor
+ */
+static private_radius_message_t *radius_message_create_empty()
+{
+ private_radius_message_t *this;
+
+ INIT(this,
+ .public = {
+ .create_enumerator = _create_enumerator,
+ .add = _add,
+ .get_code = _get_code,
+ .get_identifier = _get_identifier,
+ .set_identifier = _set_identifier,
+ .get_authenticator = _get_authenticator,
+ .get_encoding = _get_encoding,
+ .sign = _sign,
+ .verify = _verify,
+ .destroy = _destroy,
+ },
+ );
+
+ return this;
+}
+
+/**
+ * See header
+ */
+radius_message_t *radius_message_create(radius_message_code_t code)
+{
+ private_radius_message_t *this = radius_message_create_empty();
+
+ INIT(this->msg,
+ .code = code,
+ .identifier = 0,
+ .length = htons(sizeof(rmsg_t)),
+ );
+
+ return &this->public;
+}
+
+/**
+ * See header
+ */
+radius_message_t *radius_message_parse(chunk_t data)
+{
+ private_radius_message_t *this = radius_message_create_empty();
+
+ this->msg = malloc(data.len);
+ memcpy(this->msg, data.ptr, data.len);
+ if (data.len < sizeof(rmsg_t) ||
+ ntohs(this->msg->length) != data.len)
+ {
+ DBG1(DBG_IKE, "RADIUS message has invalid length");
+ destroy(this);
+ return NULL;
+ }
+ return &this->public;
+}
diff --git a/src/libradius/radius_message.h b/src/libradius/radius_message.h
new file mode 100644
index 000000000..6d0df53c3
--- /dev/null
+++ b/src/libradius/radius_message.h
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2009 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup libradius libradius
+ *
+ * @addtogroup libradius
+ * RADIUS protocol support library.
+ *
+ * @defgroup radius_message radius_message
+ * @{ @ingroup libradius
+ */
+
+#ifndef RADIUS_MESSAGE_H_
+#define RADIUS_MESSAGE_H_
+
+#include <library.h>
+
+#define MAX_RADIUS_ATTRIBUTE_SIZE 253
+
+#define RADIUS_TUNNEL_TYPE_ESP 9
+
+typedef struct radius_message_t radius_message_t;
+typedef enum radius_message_code_t radius_message_code_t;
+typedef enum radius_attribute_type_t radius_attribute_type_t;
+
+/**
+ * RADIUS Message Codes.
+ */
+enum radius_message_code_t {
+ RMC_ACCESS_REQUEST = 1,
+ RMC_ACCESS_ACCEPT = 2,
+ RMC_ACCESS_REJECT = 3,
+ RMC_ACCOUNTING_REQUEST = 4,
+ RMC_ACCOUNTING_RESPONSE = 5,
+ RMC_ACCESS_CHALLENGE = 11,
+ RMC_DISCONNECT_REQUEST = 40,
+ RMC_DISCONNECT_ACK = 41,
+ RMC_DISCONNECT_NAK = 42,
+ RMC_COA_REQUEST = 43,
+ RMC_COA_ACK = 44,
+ RMC_COA_NAK = 45,
+};
+
+/**
+ * Enum names for radius_attribute_type_t.
+ */
+extern enum_name_t *radius_message_code_names;
+
+/**
+ * RADIUS Attribute Types.
+ */
+enum radius_attribute_type_t {
+ RAT_USER_NAME = 1,
+ RAT_USER_PASSWORD = 2,
+ RAT_CHAP_PASSWORD = 3,
+ RAT_NAS_IP_ADDRESS = 4,
+ RAT_NAS_PORT = 5,
+ RAT_SERVICE_TYPE = 6,
+ RAT_FRAMED_PROTOCOL = 7,
+ RAT_FRAMED_IP_ADDRESS = 8,
+ RAT_FRAMED_IP_NETMASK = 9,
+ RAT_FRAMED_ROUTING = 10,
+ RAT_FILTER_ID = 11,
+ RAT_FRAMED_MTU = 12,
+ RAT_FRAMED_COMPRESSION = 13,
+ RAT_LOGIN_IP_HOST = 14,
+ RAT_LOGIN_SERVICE = 15,
+ RAT_LOGIN_TCP_PORT = 16,
+ RAT_REPLY_MESSAGE = 18,
+ RAT_CALLBACK_NUMBER = 19,
+ RAT_CALLBACK_ID = 20,
+ RAT_FRAMED_ROUTE = 22,
+ RAT_FRAMED_IPX_NETWORK = 23,
+ RAT_STATE = 24,
+ RAT_CLASS = 25,
+ RAT_VENDOR_SPECIFIC = 26,
+ RAT_SESSION_TIMEOUT = 27,
+ RAT_IDLE_TIMEOUT = 28,
+ RAT_TERMINATION_ACTION = 29,
+ RAT_CALLED_STATION_ID = 30,
+ RAT_CALLING_STATION_ID = 31,
+ RAT_NAS_IDENTIFIER = 32,
+ RAT_PROXY_STATE = 33,
+ RAT_LOGIN_LAT_SERVICE = 34,
+ RAT_LOGIN_LAT_NODE = 35,
+ RAT_LOGIN_LAT_GROUP = 36,
+ RAT_FRAMED_APPLETALK_LINK = 37,
+ RAT_FRAMED_APPLETALK_NETWORK = 38,
+ RAT_FRAMED_APPLETALK_ZONE = 39,
+ RAT_ACCT_STATUS_TYPE = 40,
+ RAT_ACCT_DELAY_TIME = 41,
+ RAT_ACCT_INPUT_OCTETS = 42,
+ RAT_ACCT_OUTPUT_OCTETS = 43,
+ RAT_ACCT_SESSION_ID = 44,
+ RAT_ACCT_AUTHENTIC = 45,
+ RAT_ACCT_SESSION_TIME = 46,
+ RAT_ACCT_INPUT_PACKETS = 47,
+ RAT_ACCT_OUTPUT_PACKETS = 48,
+ RAT_ACCT_TERMINATE_CAUSE = 49,
+ RAT_ACCT_MULTI_SESSION_ID = 50,
+ RAT_ACCT_LINK_COUNT = 51,
+ RAT_ACCT_INPUT_GIGAWORDS = 52,
+ RAT_ACCT_OUTPUT_GIGAWORDS = 53,
+ RAT_EVENT_TIMESTAMP = 55,
+ RAT_EGRESS_VLANID = 56,
+ RAT_INGRESS_FILTERS = 57,
+ RAT_EGRESS_VLAN_NAME = 58,
+ RAT_USER_PRIORITY_TABLE = 59,
+ RAT_CHAP_CHALLENGE = 60,
+ RAT_NAS_PORT_TYPE = 61,
+ RAT_PORT_LIMIT = 62,
+ RAT_LOGIN_LAT_PORT = 63,
+ RAT_TUNNEL_TYPE = 64,
+ RAT_TUNNEL_MEDIUM_TYPE = 65,
+ RAT_TUNNEL_CLIENT_ENDPOINT = 66,
+ RAT_TUNNEL_SERVER_ENDPOINT = 67,
+ RAT_ACCT_TUNNEL_CONNECTION = 68,
+ RAT_TUNNEL_PASSWORD = 69,
+ RAT_ARAP_PASSWORD = 70,
+ RAT_ARAP_FEATURES = 71,
+ RAT_ARAP_ZONE_ACCESS = 72,
+ RAT_ARAP_SECURITY = 73,
+ RAT_ARAP_SECURITY_DATA = 74,
+ RAT_PASSWORD_RETRY = 75,
+ RAT_PROMPT = 76,
+ RAT_CONNECT_INFO = 77,
+ RAT_CONFIGURATION_TOKEN = 78,
+ RAT_EAP_MESSAGE = 79,
+ RAT_MESSAGE_AUTHENTICATOR = 80,
+ RAT_TUNNEL_PRIVATE_GROUP_ID = 81,
+ RAT_TUNNEL_ASSIGNMENT_ID = 82,
+ RAT_TUNNEL_PREFERENCE = 83,
+ RAT_ARAP_CHALLENGE_RESPONSE = 84,
+ RAT_ACCT_INTERIM_INTERVAL = 85,
+ RAT_ACCT_TUNNEL_PACKETS_LOST = 86,
+ RAT_NAS_PORT_ID = 87,
+ RAT_FRAMED_POOL = 88,
+ RAT_CUI = 89,
+ RAT_TUNNEL_CLIENT_AUTH_ID = 90,
+ RAT_TUNNEL_SERVER_AUTH_ID = 91,
+ RAT_NAS_FILTER_RULE = 92,
+ RAT_UNASSIGNED = 93,
+ RAT_ORIGINATING_LINE_INFO = 94,
+ RAT_NAS_IPV6_ADDRESS = 95,
+ RAT_FRAMED_INTERFACE_ID = 96,
+ RAT_FRAMED_IPV6_PREFIX = 97,
+ RAT_LOGIN_IPV6_HOST = 98,
+ RAT_FRAMED_IPV6_ROUTE = 99,
+ RAT_FRAMED_IPV6_POOL = 100,
+ RAT_ERROR_CAUSE = 101,
+ RAT_EAP_KEY_NAME = 102,
+ RAT_DIGEST_RESPONSE = 103,
+ RAT_DIGEST_REALM = 104,
+ RAT_DIGEST_NONCE = 105,
+ RAT_DIGEST_RESPONSE_AUTH = 106,
+ RAT_DIGEST_NEXTNONCE = 107,
+ RAT_DIGEST_METHOD = 108,
+ RAT_DIGEST_URI = 109,
+ RAT_DIGEST_QOP = 110,
+ RAT_DIGEST_ALGORITHM = 111,
+ RAT_DIGEST_ENTITY_BODY_HASH = 112,
+ RAT_DIGEST_CNONCE = 113,
+ RAT_DIGEST_NONCE_COUNT = 114,
+ RAT_DIGEST_USERNAME = 115,
+ RAT_DIGEST_OPAQUE = 116,
+ RAT_DIGEST_AUTH_PARAM = 117,
+ RAT_DIGEST_AKA_AUTS = 118,
+ RAT_DIGEST_DOMAIN = 119,
+ RAT_DIGEST_STALE = 120,
+ RAT_DIGEST_HA1 = 121,
+ RAT_SIP_AOR = 122,
+ RAT_DELEGATED_IPV6_PREFIX = 123,
+ RAT_MIP6_FEATURE_VECTOR = 124,
+ RAT_MIP6_HOME_LINK_PREFIX = 125,
+};
+
+/**
+ * Enum names for radius_attribute_type_t.
+ */
+extern enum_name_t *radius_attribute_type_names;
+
+/**
+ * A RADIUS message, contains attributes.
+ */
+struct radius_message_t {
+
+ /**
+ * Create an enumerator over contained RADIUS attributes.
+ *
+ * @return enumerator over (int type, chunk_t data)
+ */
+ enumerator_t* (*create_enumerator)(radius_message_t *this);
+
+ /**
+ * Add a RADIUS attribute to the message.
+ *
+ * @param type type of attribute to add
+ * @param attribute data, gets cloned
+ */
+ void (*add)(radius_message_t *this, radius_attribute_type_t type,
+ chunk_t data);
+
+ /**
+ * Get the message type (code).
+ *
+ * @return message code
+ */
+ radius_message_code_t (*get_code)(radius_message_t *this);
+
+ /**
+ * Get the message identifier.
+ *
+ * @return message identifier
+ */
+ u_int8_t (*get_identifier)(radius_message_t *this);
+
+ /**
+ * Set the message identifier.
+ *
+ * @param identifier message identifier
+ */
+ void (*set_identifier)(radius_message_t *this, u_int8_t identifier);
+
+ /**
+ * Get the 16 byte authenticator.
+ *
+ * @return pointer to the Authenticator field
+ */
+ u_int8_t* (*get_authenticator)(radius_message_t *this);
+
+ /**
+ * Get the RADIUS message in its encoded form.
+ *
+ * @return chunk pointing to internal RADIUS message.
+ */
+ chunk_t (*get_encoding)(radius_message_t *this);
+
+ /**
+ * Calculate and add the Message-Authenticator attribute to the message.
+ *
+ * @param req_auth 16 byte Authenticator of request, or NULL
+ * @param secret shared RADIUS secret
+ * @param signer HMAC-MD5 signer with secret set
+ * @param hasher MD5 hasher
+ * @param rng RNG to create Request-Authenticator, NULL to omit
+ * @param msg_auth calculate and add Message-Authenticator
+ */
+ void (*sign)(radius_message_t *this, u_int8_t *req_auth, chunk_t secret,
+ hasher_t *hasher, signer_t *signer, rng_t *rng, bool msg_auth);
+
+ /**
+ * Verify the integrity of a received RADIUS message.
+ *
+ * @param req_auth 16 byte Authenticator of request, or NULL
+ * @param secret shared RADIUS secret
+ * @param signer HMAC-MD5 signer with secret set
+ * @param hasher MD5 hasher
+ */
+ bool (*verify)(radius_message_t *this, u_int8_t *req_auth, chunk_t secret,
+ hasher_t *hasher, signer_t *signer);
+
+ /**
+ * Destroy the message.
+ */
+ void (*destroy)(radius_message_t *this);
+};
+
+/**
+ * Dummy libradius initialization function needed for integrity test
+ */
+void libradius_init(void);
+
+/**
+ * Create an empty RADIUS message.
+ *
+ * @param code request type
+ * @return radius_message_t object
+ */
+radius_message_t *radius_message_create(radius_message_code_t code);
+
+/**
+ * Parse and verify a recevied RADIUS message.
+ *
+ * @param data received message data
+ * @return radius_message_t object, NULL if length invalid
+ */
+radius_message_t *radius_message_parse(chunk_t data);
+
+#endif /** RADIUS_MESSAGE_H_ @}*/
diff --git a/src/libradius/radius_mppe.h b/src/libradius/radius_mppe.h
new file mode 100644
index 000000000..1b7a732ec
--- /dev/null
+++ b/src/libradius/radius_mppe.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup radius_mppe radius_mppe
+ * @{ @ingroup libradius
+ */
+
+#ifndef RADIUS_MPPE_H_
+#define RADIUS_MPPE_H_
+
+/**
+ * Microsoft specific vendor attributes
+ */
+#define MS_MPPE_SEND_KEY 16
+#define MS_MPPE_RECV_KEY 17
+
+typedef struct mppe_key_t mppe_key_t;
+
+struct mppe_key_t {
+ u_int32_t id;
+ u_int8_t type;
+ u_int8_t length;
+ u_int16_t salt;
+ u_int8_t key[];
+} __attribute__((packed));
+
+#endif /** RADIUS_MPPE_H_ @}*/
diff --git a/src/libradius/radius_socket.c b/src/libradius/radius_socket.c
new file mode 100644
index 000000000..048c8814e
--- /dev/null
+++ b/src/libradius/radius_socket.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include "radius_socket.h"
+#include "radius_mppe.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <pen/pen.h>
+#include <debug.h>
+
+typedef struct private_radius_socket_t private_radius_socket_t;
+
+/**
+ * Private data of an radius_socket_t object.
+ */
+struct private_radius_socket_t {
+
+ /**
+ * Public radius_socket_t interface.
+ */
+ radius_socket_t public;
+
+ /**
+ * Server port for authentication
+ */
+ u_int16_t auth_port;
+
+ /**
+ * socket file descriptor for authentication
+ */
+ int auth_fd;
+
+ /**
+ * Server port for accounting
+ */
+ u_int16_t acct_port;
+
+ /**
+ * socket file descriptor for accounting
+ */
+ int acct_fd;
+
+ /**
+ * Server address
+ */
+ char *address;
+
+ /**
+ * current RADIUS identifier
+ */
+ u_int8_t identifier;
+
+ /**
+ * hasher to use for response verification
+ */
+ hasher_t *hasher;
+
+ /**
+ * HMAC-MD5 signer to build Message-Authenticator attribute
+ */
+ signer_t *signer;
+
+ /**
+ * random number generator for RADIUS request authenticator
+ */
+ rng_t *rng;
+
+ /**
+ * RADIUS secret
+ */
+ chunk_t secret;
+};
+
+/**
+ * Check or establish RADIUS connection
+ */
+static bool check_connection(private_radius_socket_t *this,
+ int *fd, u_int16_t port)
+{
+ if (*fd == -1)
+ {
+ host_t *server;
+
+ server = host_create_from_dns(this->address, AF_UNSPEC, port);
+ if (!server)
+ {
+ DBG1(DBG_CFG, "resolving RADIUS server address '%s' failed",
+ this->address);
+ return FALSE;
+ }
+ *fd = socket(server->get_family(server), SOCK_DGRAM, IPPROTO_UDP);
+ if (*fd == -1)
+ {
+ DBG1(DBG_CFG, "opening RADIUS socket for %#H failed: %s",
+ server, strerror(errno));
+ server->destroy(server);
+ return FALSE;
+ }
+ if (connect(*fd, server->get_sockaddr(server),
+ *server->get_sockaddr_len(server)) < 0)
+ {
+ DBG1(DBG_CFG, "connecting RADIUS socket to %#H failed: %s",
+ server, strerror(errno));
+ server->destroy(server);
+ close(*fd);
+ *fd = -1;
+ return FALSE;
+ }
+ server->destroy(server);
+ }
+ return TRUE;
+}
+
+METHOD(radius_socket_t, request, radius_message_t*,
+ private_radius_socket_t *this, radius_message_t *request)
+{
+ chunk_t data;
+ int i, *fd;
+ u_int16_t port;
+ rng_t *rng = NULL;
+
+ if (request->get_code(request) == RMC_ACCOUNTING_REQUEST)
+ {
+ fd = &this->acct_fd;
+ port = this->acct_port;
+ }
+ else
+ {
+ fd = &this->auth_fd;
+ port = this->auth_port;
+ rng = this->rng;
+ }
+
+ /* set Message Identifier */
+ request->set_identifier(request, this->identifier++);
+ /* sign the request */
+ request->sign(request, NULL, this->secret, this->hasher, this->signer,
+ rng, rng != NULL);
+
+ if (!check_connection(this, fd, port))
+ {
+ return NULL;
+ }
+
+ data = request->get_encoding(request);
+ DBG3(DBG_CFG, "%B", &data);
+
+ /* timeout after 2, 3, 4, 5 seconds */
+ for (i = 2; i <= 5; i++)
+ {
+ radius_message_t *response;
+ bool retransmit = FALSE;
+ struct timeval tv;
+ char buf[4096];
+ fd_set fds;
+ int res;
+
+ if (send(*fd, data.ptr, data.len, 0) != data.len)
+ {
+ DBG1(DBG_CFG, "sending RADIUS message failed: %s", strerror(errno));
+ return NULL;
+ }
+ tv.tv_sec = i;
+ tv.tv_usec = 0;
+
+ while (TRUE)
+ {
+ FD_ZERO(&fds);
+ FD_SET(*fd, &fds);
+ res = select((*fd) + 1, &fds, NULL, NULL, &tv);
+ /* TODO: updated tv to time not waited. Linux does this for us. */
+ if (res < 0)
+ { /* failed */
+ DBG1(DBG_CFG, "waiting for RADIUS message failed: %s",
+ strerror(errno));
+ break;
+ }
+ if (res == 0)
+ { /* timeout */
+ DBG1(DBG_CFG, "retransmitting RADIUS message");
+ retransmit = TRUE;
+ break;
+ }
+ res = recv(*fd, buf, sizeof(buf), MSG_DONTWAIT);
+ if (res <= 0)
+ {
+ DBG1(DBG_CFG, "receiving RADIUS message failed: %s",
+ strerror(errno));
+ break;
+ }
+ response = radius_message_parse(chunk_create(buf, res));
+ if (response)
+ {
+ if (response->verify(response,
+ request->get_authenticator(request), this->secret,
+ this->hasher, this->signer))
+ {
+ return response;
+ }
+ response->destroy(response);
+ }
+ DBG1(DBG_CFG, "received invalid RADIUS message, ignored");
+ }
+ if (!retransmit)
+ {
+ break;
+ }
+ }
+ DBG1(DBG_CFG, "RADIUS server is not responding");
+ return NULL;
+}
+
+/**
+ * Decrypt a MS-MPPE-Send/Recv-Key
+ */
+static chunk_t decrypt_mppe_key(private_radius_socket_t *this, u_int16_t salt,
+ chunk_t C, radius_message_t *request)
+{
+ chunk_t A, R, P, seed;
+ u_char *c, *p;
+
+ /**
+ * From RFC2548 (encryption):
+ * b(1) = MD5(S + R + A) c(1) = p(1) xor b(1) C = c(1)
+ * b(2) = MD5(S + c(1)) c(2) = p(2) xor b(2) C = C + c(2)
+ * . . .
+ * b(i) = MD5(S + c(i-1)) c(i) = p(i) xor b(i) C = C + c(i)
+ */
+
+ if (C.len % HASH_SIZE_MD5 || C.len < HASH_SIZE_MD5)
+ {
+ return chunk_empty;
+ }
+
+ A = chunk_create((u_char*)&salt, sizeof(salt));
+ R = chunk_create(request->get_authenticator(request), HASH_SIZE_MD5);
+ P = chunk_alloca(C.len);
+ p = P.ptr;
+ c = C.ptr;
+
+ seed = chunk_cata("cc", R, A);
+
+ while (c < C.ptr + C.len)
+ {
+ /* b(i) = MD5(S + c(i-1)) */
+ this->hasher->get_hash(this->hasher, this->secret, NULL);
+ this->hasher->get_hash(this->hasher, seed, p);
+
+ /* p(i) = b(i) xor c(1) */
+ memxor(p, c, HASH_SIZE_MD5);
+
+ /* prepare next round */
+ seed = chunk_create(c, HASH_SIZE_MD5);
+ c += HASH_SIZE_MD5;
+ p += HASH_SIZE_MD5;
+ }
+
+ /* remove truncation, first byte is key length */
+ if (*P.ptr >= P.len)
+ { /* decryption failed? */
+ return chunk_empty;
+ }
+ return chunk_clone(chunk_create(P.ptr + 1, *P.ptr));
+}
+
+METHOD(radius_socket_t, decrypt_msk, chunk_t,
+ private_radius_socket_t *this, radius_message_t *request,
+ radius_message_t *response)
+{
+ mppe_key_t *mppe_key;
+ enumerator_t *enumerator;
+ chunk_t data, send = chunk_empty, recv = chunk_empty;
+ int type;
+
+ enumerator = response->create_enumerator(response);
+ while (enumerator->enumerate(enumerator, &type, &data))
+ {
+ if (type == RAT_VENDOR_SPECIFIC && data.len > sizeof(mppe_key_t))
+ {
+ mppe_key = (mppe_key_t*)data.ptr;
+ if (ntohl(mppe_key->id) == PEN_MICROSOFT &&
+ mppe_key->length == data.len - sizeof(mppe_key->id))
+ {
+ data = chunk_create(mppe_key->key, data.len - sizeof(mppe_key_t));
+ if (mppe_key->type == MS_MPPE_SEND_KEY)
+ {
+ send = decrypt_mppe_key(this, mppe_key->salt, data, request);
+ }
+ if (mppe_key->type == MS_MPPE_RECV_KEY)
+ {
+ recv = decrypt_mppe_key(this, mppe_key->salt, data, request);
+ }
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (send.ptr && recv.ptr)
+ {
+ return chunk_cat("mm", recv, send);
+ }
+ chunk_clear(&send);
+ chunk_clear(&recv);
+ return chunk_empty;
+}
+
+METHOD(radius_socket_t, destroy, void,
+ private_radius_socket_t *this)
+{
+ DESTROY_IF(this->hasher);
+ DESTROY_IF(this->signer);
+ DESTROY_IF(this->rng);
+ if (this->auth_fd != -1)
+ {
+ close(this->auth_fd);
+ };
+ if (this->acct_fd != -1)
+ {
+ close(this->acct_fd);
+ }
+ free(this);
+}
+
+/**
+ * See header
+ */
+radius_socket_t *radius_socket_create(char *address, u_int16_t auth_port,
+ u_int16_t acct_port, chunk_t secret)
+{
+ private_radius_socket_t *this;
+
+ INIT(this,
+ .public = {
+ .request = _request,
+ .decrypt_msk = _decrypt_msk,
+ .destroy = _destroy,
+ },
+ .address = address,
+ .auth_port = auth_port,
+ .auth_fd = -1,
+ .acct_port = acct_port,
+ .acct_fd = -1,
+ .hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5),
+ .signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128),
+ .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK),
+ );
+
+ if (!this->hasher || !this->signer || !this->rng)
+ {
+ DBG1(DBG_CFG, "RADIUS initialization failed, HMAC/MD5/RNG required");
+ destroy(this);
+ return NULL;
+ }
+ this->secret = secret;
+ this->signer->set_key(this->signer, secret);
+ /* we use a random identifier, helps if we restart often */
+ this->identifier = random();
+
+ return &this->public;
+}
diff --git a/src/libradius/radius_socket.h b/src/libradius/radius_socket.h
new file mode 100644
index 000000000..07d642c08
--- /dev/null
+++ b/src/libradius/radius_socket.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup radius_socket radius_socket
+ * @{ @ingroup libradius
+ */
+
+#ifndef RADIUS_SOCKET_H_
+#define RADIUS_SOCKET_H_
+
+typedef struct radius_socket_t radius_socket_t;
+
+#include "radius_message.h"
+
+#include <utils/host.h>
+
+/**
+ * RADIUS socket to a server.
+ */
+struct radius_socket_t {
+
+ /**
+ * Send a RADIUS request, wait for response.
+ *
+ * The socket fills in RADIUS Message identifier, builds a
+ * Request-Authenticator and calculates the Message-Authenticator
+ * attribute.
+ * The received response gets verified using the Response-Identifier
+ * and the Message-Authenticator attribute.
+ *
+ * @param request request message
+ * @return response message, NULL if timed out
+ */
+ radius_message_t* (*request)(radius_socket_t *this,
+ radius_message_t *request);
+
+ /**
+ * Decrypt the MSK encoded in a messages MS-MPPE-Send/Recv-Key.
+ *
+ * @param request associated RADIUS request message
+ * @param response RADIUS response message containing attributes
+ * @return allocated MSK, empty chunk if none found
+ */
+ chunk_t (*decrypt_msk)(radius_socket_t *this, radius_message_t *request,
+ radius_message_t *response);
+
+ /**
+ * Destroy a radius_socket_t.
+ */
+ void (*destroy)(radius_socket_t *this);
+};
+
+/**
+ * Create a radius_socket instance.
+ *
+ * @param address server name
+ * @param auth_port server port for authentication
+ * @param acct_port server port for accounting
+ * @param secret RADIUS secret
+ */
+radius_socket_t *radius_socket_create(char *address, u_int16_t auth_port,
+ u_int16_t acct_port, chunk_t secret);
+
+#endif /** RADIUS_SOCKET_H_ @}*/