summaryrefslogtreecommitdiff
path: root/radius
diff options
context:
space:
mode:
Diffstat (limited to 'radius')
-rw-r--r--radius/Makefile.am42
-rw-r--r--radius/Makefile.in682
-rw-r--r--radius/attrs.c1411
-rw-r--r--radius/client.h1302
-rw-r--r--radius/common.pl220
-rwxr-xr-xradius/convert.pl197
-rw-r--r--radius/crypto.c233
-rw-r--r--radius/custom.c163
-rw-r--r--radius/dict.c172
-rw-r--r--radius/dictionaries.c1713
-rw-r--r--radius/id.c181
-rw-r--r--radius/parse.c149
-rw-r--r--radius/print.c227
-rw-r--r--radius/radpkt.c920
-rw-r--r--radius/share/dictionary.abfab.ietf4
-rw-r--r--radius/share/dictionary.juniper23
-rw-r--r--radius/share/dictionary.microsoft17
-rw-r--r--radius/share/dictionary.txt136
-rw-r--r--radius/share/dictionary.ukerna20
-rw-r--r--radius/static.c37
-rw-r--r--radius/valuepair.c191
21 files changed, 8040 insertions, 0 deletions
diff --git a/radius/Makefile.am b/radius/Makefile.am
new file mode 100644
index 0000000..462a1e0
--- /dev/null
+++ b/radius/Makefile.am
@@ -0,0 +1,42 @@
+AUTOMAKE_OPTIONS = foreign
+ACLOCAL_AMFLAGS = -I m4
+
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)
+AM_CFLAGS = -Wall -g
+
+noinst_LTLIBRARIES = libradsec-radius.la
+
+libradsec_radius_la_SOURCES = \
+ attrs.c \
+ crypto.c \
+ custom.c \
+ dict.c \
+ id.c \
+ parse.c \
+ print.c \
+ radpkt.c \
+ static.c \
+ valuepair.c
+
+libradsec_radius_la_SOURCES += client.h
+
+libradsec_radius_la_CFLAGS = $(AM_CFLAGS) -DHAVE_CONFIG_H
+
+DICTIONARIES = \
+ share/dictionary.txt \
+ share/dictionary.juniper \
+ share/dictionary.microsoft \
+ share/dictionary.ukerna \
+ share/dictionary.abfab.ietf
+
+EXTRA_DIST = dictionaries.c $(DICTIONARIES) common.pl convert.pl
+
+$(top_srcdir)/include/radsec/radius.h dictionaries.c: ${DICTIONARIES} convert.pl common.pl
+ $(srcdir)/convert.pl ${DICTIONARIES}
+
+static.$(OBJEXT): static.c dictionaries.c
+
+clean-local:
+ rm -f dictionaries.c
+
+$(libradsec_radius_la_SOURCES): $(top_srcdir)/include/radsec/radius.h
diff --git a/radius/Makefile.in b/radius/Makefile.in
new file mode 100644
index 0000000..ed3c1b6
--- /dev/null
+++ b/radius/Makefile.in
@@ -0,0 +1,682 @@
+# Makefile.in generated by automake 1.14 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 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@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+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 = radius
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libradsec_radius_la_LIBADD =
+am_libradsec_radius_la_OBJECTS = libradsec_radius_la-attrs.lo \
+ libradsec_radius_la-crypto.lo libradsec_radius_la-custom.lo \
+ libradsec_radius_la-dict.lo libradsec_radius_la-id.lo \
+ libradsec_radius_la-parse.lo libradsec_radius_la-print.lo \
+ libradsec_radius_la-radpkt.lo libradsec_radius_la-static.lo \
+ libradsec_radius_la-valuepair.lo
+libradsec_radius_la_OBJECTS = $(am_libradsec_radius_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libradsec_radius_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(libradsec_radius_la_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libradsec_radius_la_SOURCES)
+DIST_SOURCES = $(libradsec_radius_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+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@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+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@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = foreign
+ACLOCAL_AMFLAGS = -I m4
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)
+AM_CFLAGS = -Wall -g
+noinst_LTLIBRARIES = libradsec-radius.la
+libradsec_radius_la_SOURCES = attrs.c crypto.c custom.c dict.c id.c \
+ parse.c print.c radpkt.c static.c valuepair.c client.h
+libradsec_radius_la_CFLAGS = $(AM_CFLAGS) -DHAVE_CONFIG_H
+DICTIONARIES = \
+ share/dictionary.txt \
+ share/dictionary.juniper \
+ share/dictionary.microsoft \
+ share/dictionary.ukerna \
+ share/dictionary.abfab.ietf
+
+EXTRA_DIST = dictionaries.c $(DICTIONARIES) common.pl convert.pl
+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) --foreign radius/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign radius/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):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libradsec-radius.la: $(libradsec_radius_la_OBJECTS) $(libradsec_radius_la_DEPENDENCIES) $(EXTRA_libradsec_radius_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libradsec_radius_la_LINK) $(libradsec_radius_la_OBJECTS) $(libradsec_radius_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libradsec_radius_la-attrs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libradsec_radius_la-crypto.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libradsec_radius_la-custom.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libradsec_radius_la-dict.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libradsec_radius_la-id.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libradsec_radius_la-parse.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libradsec_radius_la-print.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libradsec_radius_la-radpkt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libradsec_radius_la-static.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libradsec_radius_la-valuepair.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libradsec_radius_la-attrs.lo: attrs.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -MT libradsec_radius_la-attrs.lo -MD -MP -MF $(DEPDIR)/libradsec_radius_la-attrs.Tpo -c -o libradsec_radius_la-attrs.lo `test -f 'attrs.c' || echo '$(srcdir)/'`attrs.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libradsec_radius_la-attrs.Tpo $(DEPDIR)/libradsec_radius_la-attrs.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrs.c' object='libradsec_radius_la-attrs.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -c -o libradsec_radius_la-attrs.lo `test -f 'attrs.c' || echo '$(srcdir)/'`attrs.c
+
+libradsec_radius_la-crypto.lo: crypto.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -MT libradsec_radius_la-crypto.lo -MD -MP -MF $(DEPDIR)/libradsec_radius_la-crypto.Tpo -c -o libradsec_radius_la-crypto.lo `test -f 'crypto.c' || echo '$(srcdir)/'`crypto.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libradsec_radius_la-crypto.Tpo $(DEPDIR)/libradsec_radius_la-crypto.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='crypto.c' object='libradsec_radius_la-crypto.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -c -o libradsec_radius_la-crypto.lo `test -f 'crypto.c' || echo '$(srcdir)/'`crypto.c
+
+libradsec_radius_la-custom.lo: custom.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -MT libradsec_radius_la-custom.lo -MD -MP -MF $(DEPDIR)/libradsec_radius_la-custom.Tpo -c -o libradsec_radius_la-custom.lo `test -f 'custom.c' || echo '$(srcdir)/'`custom.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libradsec_radius_la-custom.Tpo $(DEPDIR)/libradsec_radius_la-custom.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='custom.c' object='libradsec_radius_la-custom.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -c -o libradsec_radius_la-custom.lo `test -f 'custom.c' || echo '$(srcdir)/'`custom.c
+
+libradsec_radius_la-dict.lo: dict.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -MT libradsec_radius_la-dict.lo -MD -MP -MF $(DEPDIR)/libradsec_radius_la-dict.Tpo -c -o libradsec_radius_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libradsec_radius_la-dict.Tpo $(DEPDIR)/libradsec_radius_la-dict.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dict.c' object='libradsec_radius_la-dict.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -c -o libradsec_radius_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c
+
+libradsec_radius_la-id.lo: id.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -MT libradsec_radius_la-id.lo -MD -MP -MF $(DEPDIR)/libradsec_radius_la-id.Tpo -c -o libradsec_radius_la-id.lo `test -f 'id.c' || echo '$(srcdir)/'`id.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libradsec_radius_la-id.Tpo $(DEPDIR)/libradsec_radius_la-id.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='id.c' object='libradsec_radius_la-id.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -c -o libradsec_radius_la-id.lo `test -f 'id.c' || echo '$(srcdir)/'`id.c
+
+libradsec_radius_la-parse.lo: parse.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -MT libradsec_radius_la-parse.lo -MD -MP -MF $(DEPDIR)/libradsec_radius_la-parse.Tpo -c -o libradsec_radius_la-parse.lo `test -f 'parse.c' || echo '$(srcdir)/'`parse.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libradsec_radius_la-parse.Tpo $(DEPDIR)/libradsec_radius_la-parse.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='parse.c' object='libradsec_radius_la-parse.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -c -o libradsec_radius_la-parse.lo `test -f 'parse.c' || echo '$(srcdir)/'`parse.c
+
+libradsec_radius_la-print.lo: print.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -MT libradsec_radius_la-print.lo -MD -MP -MF $(DEPDIR)/libradsec_radius_la-print.Tpo -c -o libradsec_radius_la-print.lo `test -f 'print.c' || echo '$(srcdir)/'`print.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libradsec_radius_la-print.Tpo $(DEPDIR)/libradsec_radius_la-print.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='print.c' object='libradsec_radius_la-print.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -c -o libradsec_radius_la-print.lo `test -f 'print.c' || echo '$(srcdir)/'`print.c
+
+libradsec_radius_la-radpkt.lo: radpkt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -MT libradsec_radius_la-radpkt.lo -MD -MP -MF $(DEPDIR)/libradsec_radius_la-radpkt.Tpo -c -o libradsec_radius_la-radpkt.lo `test -f 'radpkt.c' || echo '$(srcdir)/'`radpkt.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libradsec_radius_la-radpkt.Tpo $(DEPDIR)/libradsec_radius_la-radpkt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='radpkt.c' object='libradsec_radius_la-radpkt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -c -o libradsec_radius_la-radpkt.lo `test -f 'radpkt.c' || echo '$(srcdir)/'`radpkt.c
+
+libradsec_radius_la-static.lo: static.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -MT libradsec_radius_la-static.lo -MD -MP -MF $(DEPDIR)/libradsec_radius_la-static.Tpo -c -o libradsec_radius_la-static.lo `test -f 'static.c' || echo '$(srcdir)/'`static.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libradsec_radius_la-static.Tpo $(DEPDIR)/libradsec_radius_la-static.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='static.c' object='libradsec_radius_la-static.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -c -o libradsec_radius_la-static.lo `test -f 'static.c' || echo '$(srcdir)/'`static.c
+
+libradsec_radius_la-valuepair.lo: valuepair.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -MT libradsec_radius_la-valuepair.lo -MD -MP -MF $(DEPDIR)/libradsec_radius_la-valuepair.Tpo -c -o libradsec_radius_la-valuepair.lo `test -f 'valuepair.c' || echo '$(srcdir)/'`valuepair.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libradsec_radius_la-valuepair.Tpo $(DEPDIR)/libradsec_radius_la-valuepair.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='valuepair.c' object='libradsec_radius_la-valuepair.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradsec_radius_la_CFLAGS) $(CFLAGS) -c -o libradsec_radius_la-valuepair.lo `test -f 'valuepair.c' || echo '$(srcdir)/'`valuepair.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ 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-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ 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"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+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:
+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:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+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-libtool clean-local \
+ clean-noinstLTLIBRARIES 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-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:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-local clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am 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-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 tags-am uninstall uninstall-am
+
+
+$(top_srcdir)/include/radsec/radius.h dictionaries.c: ${DICTIONARIES} convert.pl common.pl
+ $(srcdir)/convert.pl ${DICTIONARIES}
+
+static.$(OBJEXT): static.c dictionaries.c
+
+clean-local:
+ rm -f dictionaries.c
+
+$(libradsec_radius_la_SOURCES): $(top_srcdir)/include/radsec/radius.h
+
+# 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/radius/attrs.c b/radius/attrs.c
new file mode 100644
index 0000000..21cd3f0
--- /dev/null
+++ b/radius/attrs.c
@@ -0,0 +1,1411 @@
+/*
+Copyright (c) 2011, Network RADIUS SARL
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file attrs.c
+ * \brief Attribute encoding and decoding routines.
+ */
+
+#include "client.h"
+
+/*
+ * Encodes the data portion of an attribute.
+ * Returns -1 on error, or the length of the data portion.
+ */
+static ssize_t vp2data_any(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ int nest,
+ const VALUE_PAIR **pvp,
+ uint8_t *start, size_t room)
+{
+ uint32_t lvalue;
+ ssize_t len;
+ const uint8_t *data;
+ uint8_t *ptr = start;
+ uint8_t array[4];
+ const VALUE_PAIR *vp = *pvp;
+
+#ifdef RS_TYPE_TLV
+ /*
+ * See if we need to encode a TLV. The low portion of
+ * the attribute has already been placed into the packer.
+ * If there are still attribute bytes left, then go
+ * encode them as TLVs.
+ *
+ * If we cared about the stack, we could unroll the loop.
+ */
+ if ((nest > 0) && (nest <= nr_attr_max_tlv) &&
+ ((vp->da->attr >> nr_attr_shift[nest]) != 0)) {
+ return vp2data_tlvs(packet, original, nest, pvp,
+ start, room);
+ }
+#else
+ nest = nest; /* -Wunused */
+#endif
+
+ /*
+ * Set up the default sources for the data.
+ */
+ data = vp->vp_octets;
+ len = vp->length;
+
+ switch(vp->da->type) {
+ case RS_TYPE_IPV6PREFIX:
+ len = sizeof(vp->vp_ipv6prefix);
+ break;
+
+ case RS_TYPE_STRING:
+ case RS_TYPE_OCTETS:
+ case RS_TYPE_IFID:
+ case RS_TYPE_IPV6ADDR:
+#ifdef RS_TYPE_ABINARY
+ case RS_TYPE_ABINARY:
+#endif
+ /* nothing more to do */
+ break;
+
+ case RS_TYPE_BYTE:
+ len = 1; /* just in case */
+ array[0] = vp->vp_integer & 0xff;
+ data = array;
+ break;
+
+ case RS_TYPE_SHORT:
+ len = 2; /* just in case */
+ array[0] = (vp->vp_integer >> 8) & 0xff;
+ array[1] = vp->vp_integer & 0xff;
+ data = array;
+ break;
+
+ case RS_TYPE_INTEGER:
+ len = 4; /* just in case */
+ lvalue = htonl(vp->vp_integer);
+ memcpy(array, &lvalue, sizeof(lvalue));
+ data = array;
+ break;
+
+ case RS_TYPE_IPADDR:
+ data = (const uint8_t *) &vp->vp_ipaddr;
+ len = 4; /* just in case */
+ break;
+
+ /*
+ * There are no tagged date attributes.
+ */
+ case RS_TYPE_DATE:
+ lvalue = htonl(vp->vp_date);
+ data = (const uint8_t *) &lvalue;
+ len = 4; /* just in case */
+ break;
+
+#ifdef VENDORPEC_WIMAX
+ case RS_TYPE_SIGNED:
+ {
+ int32_t slvalue;
+
+ len = 4; /* just in case */
+ slvalue = htonl(vp->vp_signed);
+ memcpy(array, &slvalue, sizeof(slvalue));
+ break;
+ }
+#endif
+
+#ifdef RS_TYPE_TLV
+ case RS_TYPE_TLV:
+ data = vp->vp_tlv;
+ if (!data) {
+ nr_debug_error("ERROR: Cannot encode NULL TLV");
+ return -RSE_INVAL;
+ }
+ len = vp->length;
+ break;
+#endif
+
+ default: /* unknown type: ignore it */
+ nr_debug_error("ERROR: Unknown attribute type %d", vp->da->type);
+ return -RSE_ATTR_TYPE_UNKNOWN;
+ }
+
+ /*
+ * Bound the data to the calling size
+ */
+ if (len > (ssize_t) room) len = room;
+
+#ifndef FLAG_ENCRYPT_TUNNEL_PASSWORD
+ original = original; /* -Wunused */
+#endif
+
+ /*
+ * Encrypt the various password styles
+ *
+ * Attributes with encrypted values MUST be less than
+ * 128 bytes long.
+ */
+ switch (vp->da->flags.encrypt) {
+ case FLAG_ENCRYPT_USER_PASSWORD:
+ len = nr_password_encrypt(ptr, room, data, len,
+ packet->secret, packet->vector);
+ break;
+
+#ifdef FLAG_ENCRYPT_TUNNEL_PASSWORD
+ case FLAG_ENCRYPT_TUNNEL_PASSWORD:
+ lvalue = 0;
+ if (vp->da->flags.has_tag) lvalue = 1;
+
+ /*
+ * Check if there's enough room. If there isn't,
+ * we discard the attribute.
+ *
+ * This is ONLY a problem if we have multiple VSA's
+ * in one Vendor-Specific, though.
+ */
+ if (room < (18 + lvalue)) {
+ *pvp = vp->next;
+ return 0;
+ }
+
+ switch (packet->code) {
+ case PW_ACCESS_ACCEPT:
+ case PW_ACCESS_REJECT:
+ case PW_ACCESS_CHALLENGE:
+ default:
+ if (!original) {
+ nr_debug_error("ERROR: No request packet, cannot encrypt %s attribute in the vp.", vp->da->name);
+ return -RSE_REQUEST_REQUIRED;
+ }
+
+ if (lvalue) ptr[0] = vp->tag;
+ len = nr_tunnelpw_encrypt(ptr + lvalue,
+ room - lvalue, data, len,
+ packet->secret,
+ original->vector);
+ if (len < 0) return len;
+ break;
+ case PW_ACCOUNTING_REQUEST:
+ case PW_DISCONNECT_REQUEST:
+ case PW_COA_REQUEST:
+ ptr[0] = vp->tag;
+ len = nr_tunnelpw_encrypt(ptr + 1, room, data, len - 1,
+ packet->secret,
+ packet->vector);
+ if (len < 0) return len;
+ break;
+ }
+ break;
+#endif
+
+ /*
+ * The code above ensures that this attribute
+ * always fits.
+ */
+#ifdef FLAG_ENCRYPT_ASCEND_SECRET
+ case FLAG_ENCRYPT_ASCEND_SECRET:
+ make_secret(ptr, packet->vector, packet->secret, data);
+ len = AUTH_VECTOR_LEN;
+ break;
+#endif
+
+ default:
+ if (vp->da->flags.has_tag && TAG_VALID(vp->tag)) {
+ if (vp->da->type == RS_TYPE_STRING) {
+ if (len > ((ssize_t) (room - 1))) len = room - 1;
+ ptr[0] = vp->tag;
+ ptr++;
+ } else if (vp->da->type == RS_TYPE_INTEGER) {
+ array[0] = vp->tag;
+ } /* else it can't be any other type */
+ }
+ memcpy(ptr, data, len);
+ break;
+ } /* switch over encryption flags */
+
+ *(pvp) = vp->next;
+ return len + (ptr - start);;
+}
+
+
+/*
+ * Encode an RFC format TLV. This could be a standard attribute,
+ * or a TLV data type. If it's a standard attribute, then
+ * vp->da->attr == attribute. Otherwise, attribute may be
+ * something else.
+ */
+static ssize_t vp2attr_rfc(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const VALUE_PAIR **pvp,
+ unsigned int attribute, uint8_t *ptr, size_t room)
+{
+ ssize_t len;
+
+ if (room < 2) {
+ *pvp = (*pvp)->next;
+ return 0;
+ }
+
+ ptr[0] = attribute & 0xff;
+ ptr[1] = 2;
+
+ if (room > ((unsigned) 255 - ptr[1])) room = 255 - ptr[1];
+
+ len = vp2data_any(packet, original, 0, pvp, ptr + ptr[1], room);
+ if (len < 0) return len;
+
+ ptr[1] += len;
+
+ return ptr[1];
+}
+
+
+#ifndef WITHOUT_VSAS
+/*
+ * Encode a VSA which is a TLV. If it's in the RFC format, call
+ * vp2attr_rfc. Otherwise, encode it here.
+ */
+static ssize_t vp2attr_vsa(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const VALUE_PAIR **pvp,
+ unsigned int attribute, unsigned int vendor,
+ uint8_t *ptr, size_t room)
+{
+ ssize_t len;
+ const DICT_VENDOR *dv;
+
+ /*
+ * Unknown vendor: RFC format.
+ * Known vendor and RFC format: go do that.
+ */
+ dv = nr_dict_vendor_byvalue(vendor);
+ if (!dv ||
+ (
+#ifdef RS_TYPE_TLV
+ !(*pvp)->flags.is_tlv &&
+#endif
+ (dv->type == 1) && (dv->length == 1))) {
+ return vp2attr_rfc(packet, original, pvp,
+ attribute, ptr, room);
+ }
+
+#ifdef RS_TYPE_TLV
+ if ((*pvp)->flags.is_tlv) {
+ return data2vp_tlvs(packet, original, 0, pvp,
+ ptr, room);
+ }
+#endif
+
+ switch (dv->type) {
+ default:
+ nr_debug_error("vp2attr_vsa: Internal sanity check failed,"
+ " type %u", (unsigned) dv->type);
+ return -RSE_INTERNAL;
+
+ case 4:
+ ptr[0] = 0; /* attr must be 24-bit */
+ ptr[1] = (attribute >> 16) & 0xff;
+ ptr[2] = (attribute >> 8) & 0xff;
+ ptr[3] = attribute & 0xff;
+ break;
+
+ case 2:
+ ptr[0] = (attribute >> 8) & 0xff;
+ ptr[1] = attribute & 0xff;
+ break;
+
+ case 1:
+ ptr[0] = attribute & 0xff;
+ break;
+ }
+
+ switch (dv->length) {
+ default:
+ nr_debug_error("vp2attr_vsa: Internal sanity check failed,"
+ " length %u", (unsigned) dv->length);
+ return -RSE_INTERNAL;
+
+ case 0:
+ break;
+
+ case 2:
+ ptr[dv->type] = 0;
+ /* FALL-THROUGH */
+
+ case 1:
+ ptr[dv->type + dv->length - 1] = dv->type + dv->length;
+ break;
+
+ }
+
+ if (room > ((unsigned) 255 - (dv->type + dv->length))) {
+ room = 255 - (dv->type + dv->length);
+ }
+
+ len = vp2data_any(packet, original, 0, pvp,
+ ptr + dv->type + dv->length, room);
+ if (len < 0) return len;
+
+ if (dv->length) ptr[dv->type + dv->length - 1] += len;
+
+ return dv->type + dv->length + len;
+}
+
+
+/*
+ * Encode a Vendor-Specific attribute.
+ */
+ssize_t nr_vp2vsa(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
+ const VALUE_PAIR **pvp, uint8_t *ptr,
+ size_t room)
+{
+ ssize_t len;
+ uint32_t lvalue;
+ const VALUE_PAIR *vp = *pvp;
+
+#ifdef VENDORPEC_WIMAX
+ /*
+ * Double-check for WiMAX
+ */
+ if (vp->da->vendor == VENDORPEC_WIMAX) {
+ return nr_vp2wimax(packet, original, pvp,
+ ptr, room);
+ }
+#endif
+
+ if (vp->da->vendor > RS_MAX_VENDOR) {
+ nr_debug_error("nr_vp2vsa: Invalid arguments");
+ return -RSE_INVAL;
+ }
+
+ /*
+ * Not enough room for:
+ * attr, len, vendor-id
+ */
+ if (room < 6) {
+ *pvp = vp->next;
+ return 0;
+ }
+
+ /*
+ * Build the Vendor-Specific header
+ */
+ ptr[0] = PW_VENDOR_SPECIFIC;
+ ptr[1] = 6;
+ lvalue = htonl(vp->da->vendor);
+ memcpy(ptr + 2, &lvalue, 4);
+
+ if (room > ((unsigned) 255 - ptr[1])) room = 255 - ptr[1];
+
+ len = vp2attr_vsa(packet, original, pvp,
+ vp->da->attr, vp->da->vendor,
+ ptr + ptr[1], room);
+ if (len < 0) return len;
+
+ ptr[1] += len;
+
+ return ptr[1];
+}
+#endif
+
+
+/*
+ * Encode an RFC standard attribute 1..255
+ */
+ssize_t nr_vp2rfc(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const VALUE_PAIR **pvp,
+ uint8_t *ptr, size_t room)
+{
+ const VALUE_PAIR *vp = *pvp;
+
+ if (vp->da->vendor != 0) {
+ nr_debug_error("nr_vp2rfc called with VSA");
+ return -RSE_INVAL;
+ }
+
+ if ((vp->da->attr == 0) || (vp->da->attr > 255)) {
+ nr_debug_error("nr_vp2rfc called with non-standard attribute %u", vp->da->attr);
+ return -RSE_INVAL;
+ }
+
+#ifdef PW_CHARGEABLE_USER_IDENTITY
+ if ((vp->length == 0) &&
+ (vp->da != RS_DA_CHARGEABLE_USER_IDENTITY)) {
+ *pvp = vp->next;
+ return 0;
+ }
+#endif
+
+ return vp2attr_rfc(packet, original, pvp, vp->da->attr,
+ ptr, room);
+}
+
+#ifdef PW_CHAP_PASSWORD
+/*
+ * Encode an RFC standard attribute 1..255
+ */
+static ssize_t nr_chap2rfc(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const VALUE_PAIR **pvp,
+ uint8_t *ptr, size_t room)
+{
+ ssize_t rcode;
+ const VALUE_PAIR *vp = *pvp;
+ RS_MD5_CTX ctx;
+ uint8_t buffer[RS_MAX_STRING_LEN*2 + 1], *p;
+ VALUE_PAIR chap = {
+ RS_DA_CHAP_PASSWORD,
+ 17,
+ 0,
+ NULL,
+ {
+ .octets = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ },
+ };
+
+ if ((vp->da->vendor != 0) || (vp->da != RS_DA_CHAP_PASSWORD)) {
+ nr_debug_error("nr_chap2rfc called with non-CHAP");
+ return -RSE_INVAL;
+ }
+
+ p = buffer;
+ *(p++) = nr_rand() & 0xff; /* id */
+
+ memcpy(p, vp->vp_strvalue, strlen(vp->vp_strvalue));
+ p += strlen(vp->vp_strvalue);
+
+ vp = nr_vps_find(packet->vps, PW_CHAP_CHALLENGE, 0);
+ if (vp) {
+ memcpy(p, vp->vp_octets, vp->length);
+ p += vp->length;
+ } else {
+ memcpy(p, packet->vector, sizeof(packet->vector));
+ p += sizeof(packet->vector);
+ }
+
+ RS_MD5Init(&ctx);
+ RS_MD5Update(&ctx, buffer, p - buffer);
+ RS_MD5Final(&chap.vp_octets[1], &ctx);
+
+ chap.vp_octets[0] = buffer[0];
+ vp = &chap;
+
+ rcode = vp2attr_rfc(packet, original, &vp, chap.da->attr,
+ ptr, room);
+ if (rcode < 0) return rcode;
+
+ *pvp = (*pvp)->next;
+ return rcode;
+}
+#endif /* PW_CHAP_PASSWORD */
+
+#ifdef PW_MESSAGE_AUTHENTICATOR
+/** Fake Message-Authenticator.
+ *
+ * This structure is used to replace a Message-Authenticator in the
+ * input list of VALUE_PAIRs when encoding a packet. If the caller
+ * asks us to encode a Message-Authenticator, we ignore the one given
+ * to us by the caller (which may have the wrong length, etc.), and
+ * instead use this one, which has the correct length and data.
+ */
+static const VALUE_PAIR fake_ma = {
+ RS_DA_MESSAGE_AUTHENTICATOR,
+ 16,
+ 0,
+ NULL,
+ {
+ .octets = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ }
+};
+#endif /* PW_MESSAGE_AUTHENTICATOR */
+
+/*
+ * Parse a data structure into a RADIUS attribute.
+ */
+ssize_t nr_vp2attr(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
+ const VALUE_PAIR **pvp, uint8_t *start,
+ size_t room)
+{
+ const VALUE_PAIR *vp = *pvp;
+
+ /*
+ * RFC format attributes take the fast path.
+ */
+ if (vp->da->vendor != 0) {
+#ifdef VENDORPEC_EXTENDED
+ if (vp->da->vendor > RS_MAX_VENDOR) {
+ return nr_vp2attr_extended(packet, original,
+ pvp, start, room);
+
+ }
+#endif
+
+#ifdef VENDORPEC_WIMAX
+ if (vp->da->vendor == VENDORPEC_WIMAX) {
+ return nr_vp2attr_wimax(packet, original,
+ pvp, start, room);
+ }
+#endif
+
+#ifndef WITHOUT_VSAS
+ return nr_vp2vsa(packet, original, pvp, start, room);
+#else
+ nr_debug_error("VSAs are not supported");
+ return -RSE_UNSUPPORTED;
+#endif
+ }
+
+ /*
+ * Ignore non-protocol attributes.
+ */
+ if (vp->da->attr > 255) {
+ *pvp = vp->next;
+ return 0;
+ }
+
+#ifdef PW_MESSAGE_AUTHENTICATOR
+ /*
+ * The caller wants a Message-Authenticator, but doesn't
+ * know how to calculate it, or what the correct values
+ * are. So... create one for him.
+ */
+ if (vp->da == RS_DA_MESSAGE_AUTHENTICATOR) {
+ ssize_t rcode;
+
+ vp = &fake_ma;
+ rcode = nr_vp2rfc(packet, original, &vp, start, room);
+ if (rcode <= 0) return rcode;
+ *pvp = (*pvp)->next;
+ return rcode;
+ }
+#endif
+
+#ifdef PW_CHAP_PASSWORD
+ /*
+ * The caller wants a CHAP-Password, but doesn't know how
+ * to calculate it, or what the correct values are. To
+ * help, we calculate it for him.
+ */
+ if (vp->da == RS_DA_CHAP_PASSWORD) {
+ int encoded = 0;
+
+ /*
+ * CHAP is ID + MD5(...). If it's length is NOT
+ * 17, then the caller has passed us a password,
+ * and wants us to encode it. If the length IS
+ * 17, then we need to double-check if the caller
+ * has already encoded it.
+ */
+ if (vp->length == 17) {
+ int i;
+
+ /*
+ * ASCII and UTF-8 disallow values 0..31.
+ * If they appear, then the CHAP-Password
+ * has already been encoded by the
+ * caller. The probability of a
+ * CHAP-Password being all 32..256 is
+ * (1-32/256)^17 =~ .10
+ *
+ * This check isn't perfect, but it
+ * should be pretty rare for people to
+ * have 17-character passwords *and* have
+ * them all 32..256.
+ */
+ for (i = 0; i < 17; i++) {
+ if (vp->vp_octets[i] < 32) {
+ encoded = 1;
+ break;
+ }
+ }
+ }
+
+ if (!encoded) {
+ return nr_chap2rfc(packet, original, pvp, start, room);
+ }
+ }
+#endif
+
+ return nr_vp2rfc(packet, original, pvp,
+ start, room);
+}
+
+
+/*
+ * Ignore unknown attributes, but "decoding" them into nothing.
+ */
+static ssize_t data2vp_raw(UNUSED const RADIUS_PACKET *packet,
+ UNUSED const RADIUS_PACKET *original,
+ unsigned int attribute,
+ unsigned int vendor,
+ const uint8_t *data, size_t length,
+ VALUE_PAIR **pvp)
+{
+ VALUE_PAIR *vp;
+
+ if (length > sizeof(vp->vp_octets)) return -RSE_ATTR_OVERFLOW;
+
+ vp = nr_vp_alloc_raw(attribute, vendor);
+ if (!vp) return -RSE_NOMEM;
+
+ memcpy(vp->vp_octets, data, length);
+ vp->length = length;
+
+ *pvp = vp;
+ return length;
+}
+
+ssize_t nr_attr2vp_raw(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const uint8_t *data, size_t length,
+ VALUE_PAIR **pvp)
+{
+
+ if (length < 2) return -RSE_PACKET_TOO_SMALL;
+ if (data[1] < 2) return -RSE_ATTR_TOO_SMALL;
+ if (data[1] > length) return -RSE_ATTR_OVERFLOW;
+
+ return data2vp_raw(packet, original, data[0], 0,
+ data + 2, data[1] - 2, pvp);
+}
+
+/*
+ * Create any kind of VP from the attribute contents.
+ *
+ * Will return -1 on error, or "length".
+ */
+static ssize_t data2vp_any(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ int nest,
+ unsigned int attribute, unsigned int vendor,
+ const uint8_t *data, size_t length,
+ VALUE_PAIR **pvp)
+{
+#ifdef FLAG_ENCRYPT_TUNNEL_PASSWORD
+ ssize_t rcode;
+#endif
+ int data_offset = 0;
+ const DICT_ATTR *da;
+ VALUE_PAIR *vp = NULL;
+
+ if (length == 0) {
+ /*
+ * Hacks for CUI. The WiMAX spec says that it
+ * can be zero length, even though this is
+ * forbidden by the RADIUS specs. So... we make
+ * a special case for it.
+ */
+ if ((vendor == 0) &&
+ (attribute == PW_CHARGEABLE_USER_IDENTITY)) {
+ data = (const uint8_t *) "";
+ length = 1;
+ } else {
+ *pvp = NULL;
+ return 0;
+ }
+ }
+
+ da = nr_dict_attr_byvalue(attribute, vendor);
+
+ /*
+ * Unknown attribute. Create it as a "raw" attribute.
+ */
+ if (!da) {
+ raw:
+ if (vp) nr_vp_free(&vp);
+ return data2vp_raw(packet, original,
+ attribute, vendor, data, length, pvp);
+ }
+
+#ifdef RS_TYPE_TLV
+ /*
+ * TLVs are handled first. They can't be tagged, and
+ * they can't be encrypted.
+ */
+ if (da->da->type == RS_TYPE_TLV) {
+ return data2vp_tlvs(packet, original,
+ attribute, vendor, nest,
+ data, length, pvp);
+ }
+#else
+ nest = nest; /* -Wunused */
+#endif
+
+ /*
+ * The attribute is known, and well formed. We can now
+ * create it. The main failure from here on in is being
+ * out of memory.
+ */
+ vp = nr_vp_alloc(da);
+ if (!vp) return -RSE_NOMEM;
+
+ /*
+ * Handle tags.
+ */
+ if (vp->da->flags.has_tag) {
+ if (TAG_VALID(data[0])
+#ifdef FLAG_ENCRYPT_TUNNEL_PASSWORD
+ || (vp->da->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD)
+#endif
+ ) {
+ /*
+ * Tunnel passwords REQUIRE a tag, even
+ * if don't have a valid tag.
+ */
+ vp->tag = data[0];
+
+ if ((vp->da->type == RS_TYPE_STRING) ||
+ (vp->da->type == RS_TYPE_OCTETS)) {
+ if (length == 0) goto raw;
+ data_offset = 1;
+ }
+ }
+ }
+
+ /*
+ * Copy the data to be decrypted
+ */
+ vp->length = length - data_offset;
+ memcpy(&vp->vp_octets[0], data + data_offset, vp->length);
+
+ /*
+ * Decrypt the attribute.
+ */
+ switch (vp->da->flags.encrypt) {
+ /*
+ * User-Password
+ */
+ case FLAG_ENCRYPT_USER_PASSWORD:
+ if (original) {
+ rcode = nr_password_encrypt(vp->vp_octets,
+ sizeof(vp->vp_strvalue),
+ data + data_offset, vp->length,
+ packet->secret,
+ original->vector);
+ } else {
+ rcode = nr_password_encrypt(vp->vp_octets,
+ sizeof(vp->vp_strvalue),
+ data + data_offset, vp->length,
+ packet->secret,
+ packet->vector);
+ }
+ if (rcode < 0) goto raw;
+ vp->vp_strvalue[128] = '\0';
+ vp->length = strlen(vp->vp_strvalue);
+ break;
+
+ /*
+ * Tunnel-Password's may go ONLY
+ * in response packets.
+ */
+#ifdef FLAG_ENCRYPT_TUNNEL_PASSWORD
+ case FLAG_ENCRYPT_TUNNEL_PASSWORD:
+ if (!original) goto raw;
+
+ rcode = nr_tunnelpw_decrypt(vp->vp_octets,
+ sizeof(vp->vp_octets),
+ data + data_offset, vp->length,
+ packet->secret, original->vector);
+ if (rcode < 0) goto raw;
+ vp->length = rcode;
+ break;
+#endif
+
+
+#ifdef FLAG_ENCRYPT_ASCEND_SECRET
+ /*
+ * Ascend-Send-Secret
+ * Ascend-Receive-Secret
+ */
+ case FLAG_ENCRYPT_ASCEND_SECRET:
+ if (!original) {
+ goto raw;
+ } else {
+ uint8_t my_digest[AUTH_VECTOR_LEN];
+ make_secret(my_digest,
+ original->vector,
+ packet->secret, data);
+ memcpy(vp->vp_strvalue, my_digest,
+ AUTH_VECTOR_LEN );
+ vp->vp_strvalue[AUTH_VECTOR_LEN] = '\0';
+ vp->length = strlen(vp->vp_strvalue);
+ }
+ break;
+#endif
+
+ default:
+ break;
+ } /* switch over encryption flags */
+
+ /*
+ * Expected a certain length, but got something else.
+ */
+ if ((vp->da->flags.length != 0) &&
+ (vp->length != vp->da->flags.length)) {
+ goto raw;
+ }
+
+ switch (vp->da->type) {
+ case RS_TYPE_STRING:
+ case RS_TYPE_OCTETS:
+#ifdef RS_TYPE_ABINARY
+ case RS_TYPE_ABINARY:
+#endif
+ /* nothing more to do */
+ break;
+
+ case RS_TYPE_BYTE:
+ vp->vp_integer = vp->vp_octets[0];
+ break;
+
+
+ case RS_TYPE_SHORT:
+ vp->vp_integer = (vp->vp_octets[0] << 8) | vp->vp_octets[1];
+ break;
+
+ case RS_TYPE_INTEGER:
+ memcpy(&vp->vp_integer, vp->vp_octets, 4);
+ vp->vp_integer = ntohl(vp->vp_integer);
+
+ if (vp->da->flags.has_tag) vp->vp_integer &= 0x00ffffff;
+ break;
+
+ case RS_TYPE_DATE:
+ memcpy(&vp->vp_date, vp->vp_octets, 4);
+ vp->vp_date = ntohl(vp->vp_date);
+ break;
+
+
+ case RS_TYPE_IPADDR:
+ memcpy(&vp->vp_ipaddr, vp->vp_octets, 4);
+ break;
+
+ /*
+ * IPv6 interface ID is 8 octets long.
+ */
+ case RS_TYPE_IFID:
+ /* vp->vp_ifid == vp->vp_octets */
+ break;
+
+ /*
+ * IPv6 addresses are 16 octets long
+ */
+ case RS_TYPE_IPV6ADDR:
+ /* vp->vp_ipv6addr == vp->vp_octets */
+ break;
+
+ /*
+ * IPv6 prefixes are 2 to 18 octets long.
+ *
+ * RFC 3162: The first octet is unused.
+ * The second is the length of the prefix
+ * the rest are the prefix data.
+ *
+ * The prefix length can have value 0 to 128.
+ */
+ case RS_TYPE_IPV6PREFIX:
+ if (vp->length < 2 || vp->length > 18) goto raw;
+ if (vp->vp_octets[1] > 128) goto raw;
+
+ /*
+ * FIXME: double-check that
+ * (vp->vp_octets[1] >> 3) matches vp->length + 2
+ */
+ if (vp->length < 18) {
+ memset(vp->vp_octets + vp->length, 0,
+ 18 - vp->length);
+ }
+ break;
+
+#ifdef VENDORPEC_WIMAX
+ case RS_TYPE_SIGNED:
+ if (vp->length != 4) goto raw;
+
+ /*
+ * Overload vp_integer for ntohl, which takes
+ * uint32_t, not int32_t
+ */
+ memcpy(&vp->vp_integer, vp->vp_octets, 4);
+ vp->vp_integer = ntohl(vp->vp_integer);
+ memcpy(&vp->vp_signed, &vp->vp_integer, 4);
+ break;
+#endif
+
+#ifdef RS_TYPE_TLV
+ case RS_TYPE_TLV:
+ nr_vp_free(&vp);
+ nr_debug_error("data2vp_any: Internal sanity check failed");
+ return -RSE_ATTR_TYPE_UNKNOWN;
+#endif
+
+#ifdef VENDORPEC_WIMAX
+ case RS_TYPE_COMBO_IP:
+ if (vp->length == 4) {
+ vp->da->type = RS_TYPE_IPADDR;
+ memcpy(&vp->vp_ipaddr, vp->vp_octets, 4);
+ break;
+
+ } else if (vp->length == 16) {
+ vp->da->type = RS_TYPE_IPV6ADDR;
+ /* vp->vp_ipv6addr == vp->vp_octets */
+ break;
+
+ }
+ /* FALL-THROUGH */
+#endif
+
+ default:
+ goto raw;
+ }
+
+ *pvp = vp;
+
+ return length;
+}
+
+
+/*
+ * Create a "standard" RFC VALUE_PAIR from the given data.
+ */
+ssize_t nr_attr2vp_rfc(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const uint8_t *data, size_t length,
+ VALUE_PAIR **pvp)
+{
+ ssize_t rcode;
+
+ if (length < 2) return -RSE_PACKET_TOO_SMALL;
+ if (data[1] < 2) return -RSE_ATTR_TOO_SMALL;
+ if (data[1] > length) return -RSE_ATTR_OVERFLOW;
+
+ rcode = data2vp_any(packet, original, 0,
+ data[0], 0, data + 2, data[1] - 2, pvp);
+ if (rcode < 0) return rcode;
+
+ return data[1];
+}
+
+#ifndef WITHOUT_VSAS
+/*
+ * Check if a set of RADIUS formatted TLVs are OK.
+ */
+int nr_tlv_ok(const uint8_t *data, size_t length,
+ size_t dv_type, size_t dv_length)
+{
+ const uint8_t *end = data + length;
+
+ if ((dv_length > 2) || (dv_type == 0) || (dv_type > 4)) {
+ nr_debug_error("nr_tlv_ok: Invalid arguments");
+ return -RSE_INVAL;
+ }
+
+ while (data < end) {
+ size_t attrlen;
+
+ if ((data + dv_type + dv_length) > end) {
+ nr_debug_error("Attribute header overflow");
+ return -RSE_ATTR_TOO_SMALL;
+ }
+
+ switch (dv_type) {
+ case 4:
+ if ((data[0] == 0) && (data[1] == 0) &&
+ (data[2] == 0) && (data[3] == 0)) {
+ zero:
+ nr_debug_error("Invalid attribute 0");
+ return -RSE_ATTR_INVALID;
+ }
+
+ if (data[0] != 0) {
+ nr_debug_error("Invalid attribute > 2^24");
+ return -RSE_ATTR_INVALID;
+ }
+ break;
+
+ case 2:
+ if ((data[1] == 0) && (data[1] == 0)) goto zero;
+ break;
+
+ case 1:
+ if (data[0] == 0) goto zero;
+ break;
+
+ default:
+ nr_debug_error("Internal sanity check failed");
+ return -RSE_INTERNAL;
+ }
+
+ switch (dv_length) {
+ case 0:
+ return 0;
+
+ case 2:
+ if (data[dv_type + 1] != 0) {
+ nr_debug_error("Attribute is longer than 256 octets");
+ return -RSE_ATTR_TOO_LARGE;
+ }
+ /* FALL-THROUGH */
+ case 1:
+ attrlen = data[dv_type + dv_length - 1];
+ break;
+
+
+ default:
+ nr_debug_error("Internal sanity check failed");
+ return -RSE_INTERNAL;
+ }
+
+ if (attrlen < (dv_type + dv_length)) {
+ nr_debug_error("Attribute header has invalid length");
+ return -RSE_PACKET_TOO_SMALL;
+ }
+
+ if (attrlen > length) {
+ nr_debug_error("Attribute overflows container");
+ return -RSE_ATTR_OVERFLOW;
+ }
+
+ data += attrlen;
+ length -= attrlen;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Convert a top-level VSA to a VP.
+ */
+static ssize_t attr2vp_vsa(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ unsigned int vendor,
+ size_t dv_type, size_t dv_length,
+ const uint8_t *data, size_t length,
+ VALUE_PAIR **pvp)
+{
+ unsigned int attribute;
+ ssize_t attrlen, my_len;
+
+#ifndef NDEBUG
+ if (length <= (dv_type + dv_length)) {
+ nr_debug_error("attr2vp_vsa: Failure to call nr_tlv_ok");
+ return -RSE_PACKET_TOO_SMALL;
+ }
+#endif
+
+ switch (dv_type) {
+ case 4:
+ /* data[0] must be zero */
+ attribute = data[1] << 16;
+ attribute |= data[2] << 8;
+ attribute |= data[3];
+ break;
+
+ case 2:
+ attribute = data[0] << 8;
+ attribute |= data[1];
+ break;
+
+ case 1:
+ attribute = data[0];
+ break;
+
+ default:
+ nr_debug_error("attr2vp_vsa: Internal sanity check failed");
+ return -RSE_INTERNAL;
+ }
+
+ switch (dv_length) {
+ case 2:
+ /* data[dv_type] must be zero */
+ attrlen = data[dv_type + 1];
+ break;
+
+ case 1:
+ attrlen = data[dv_type];
+ break;
+
+ case 0:
+ attrlen = length;
+ break;
+
+ default:
+ nr_debug_error("attr2vp_vsa: Internal sanity check failed");
+ return -RSE_INTERNAL;
+ }
+
+#ifndef NDEBUG
+ if (attrlen <= (ssize_t) (dv_type + dv_length)) {
+ nr_debug_error("attr2vp_vsa: Failure to call nr_tlv_ok");
+ return -RSE_PACKET_TOO_SMALL;
+ }
+#endif
+
+ attrlen -= (dv_type + dv_length);
+
+ my_len = data2vp_any(packet, original, 0,
+ attribute, vendor,
+ data + dv_type + dv_length, attrlen, pvp);
+ if (my_len < 0) return my_len;
+
+#ifndef NDEBUG
+ if (my_len != attrlen) {
+ nr_vp_free(pvp);
+ nr_debug_error("attr2vp_vsa: Incomplete decode %d != %d",
+ (int) my_len, (int) attrlen);
+ return -RSE_INTERNAL;
+ }
+#endif
+
+ return dv_type + dv_length + attrlen;
+}
+
+
+/*
+ * Create Vendor-Specifc VALUE_PAIRs from a RADIUS attribute.
+ */
+ssize_t nr_attr2vp_vsa(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const uint8_t *data, size_t length,
+ VALUE_PAIR **pvp)
+{
+ size_t dv_type, dv_length;
+ ssize_t my_len;
+ uint32_t lvalue;
+ const DICT_VENDOR *dv;
+
+ if (length < 2) return -RSE_PACKET_TOO_SMALL;
+ if (data[1] < 2) return -RSE_ATTR_TOO_SMALL;
+ if (data[1] > length) return -RSE_ATTR_OVERFLOW;
+
+ if (data[0] != PW_VENDOR_SPECIFIC) {
+ nr_debug_error("nr_attr2vp_vsa: Invalid attribute");
+ return -RSE_INVAL;
+ }
+
+ /*
+ * Not enough room for a Vendor-Id.
+ * Or the high octet of the Vendor-Id is set.
+ */
+ if ((data[1] < 6) || (data[2] != 0)) {
+ return nr_attr2vp_raw(packet, original,
+ data, length, pvp);
+ }
+
+ memcpy(&lvalue, data + 2, 4);
+ lvalue = ntohl(lvalue);
+
+#ifdef VENDORPEC_WIMAX
+ /*
+ * WiMAX gets its own set of magic.
+ */
+ if (lvalue == VENDORPEC_WIMAX) {
+ return nr_attr2vp_wimax(packet, original,
+ data, length, pvp);
+ }
+#endif
+
+ dv_type = dv_length = 1;
+ dv = nr_dict_vendor_byvalue(lvalue);
+ if (!dv) {
+ return nr_attr2vp_rfc(packet, original,
+ data, length, pvp);
+ }
+
+ dv_type = dv->type;
+ dv_length = dv->length;
+
+ /*
+ * Attribute is not in the correct form.
+ */
+ if (nr_tlv_ok(data + 6, data[1] - 6, dv_type, dv_length) < 0) {
+ return nr_attr2vp_raw(packet, original,
+ data, length, pvp);
+ }
+
+ my_len = attr2vp_vsa(packet, original,
+ lvalue, dv_type, dv_length,
+ data + 6, data[1] - 6, pvp);
+ if (my_len < 0) return my_len;
+
+#ifndef NDEBUG
+ if (my_len != (data[1] - 6)) {
+ nr_vp_free(pvp);
+ nr_debug_error("nr_attr2vp_vsa: Incomplete decode");
+ return -RSE_INTERNAL;
+ }
+#endif
+
+ return data[1];
+}
+#endif /* WITHOUT_VSAS */
+
+
+/*
+ * Create a "normal" VALUE_PAIR from the given data.
+ */
+ssize_t nr_attr2vp(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const uint8_t *data, size_t length,
+ VALUE_PAIR **pvp)
+{
+ if (length < 2) return -RSE_PACKET_TOO_SMALL;
+ if (data[1] < 2) return -RSE_ATTR_TOO_SMALL;
+ if (data[1] > length) return -RSE_ATTR_OVERFLOW;
+
+#ifndef WITHOUT_VSAS
+ /*
+ * VSAs get their own handler.
+ */
+ if (data[0] == PW_VENDOR_SPECIFIC) {
+ return nr_attr2vp_vsa(packet, original,
+ data, length, pvp);
+ }
+#endif
+
+#ifdef VENDORPEC_EXTENDED
+ /*
+ * Extended attribute format gets their own handler.
+ */
+ if (nr_dict_attr_byvalue(data[0], VENDORPEC_EXTENDED) != NULL) {
+ return nr_attr2vp_extended(packet, original,
+ data, length, pvp);
+ }
+#endif
+
+ return nr_attr2vp_rfc(packet, original, data, length, pvp);
+}
+
+ssize_t nr_attr2data(const RADIUS_PACKET *packet, ssize_t start,
+ unsigned int attribute, unsigned int vendor,
+ const uint8_t **pdata, size_t *plength)
+{
+ uint8_t *data, *attr;
+ const uint8_t *end;
+
+ if (!packet || !pdata || !plength) return -RSE_INVAL;
+
+ if (!packet->data) return -RSE_INVAL;
+ if (packet->length < 20) return -RSE_INVAL;
+
+ /*
+ * Too long or short, not good.
+ */
+ if ((start < 0) ||
+ ((start > 0) && (start < 20))) return -RSE_INVAL;
+
+ if ((size_t) start >= (packet->length - 2)) return -RSE_INVAL;
+
+ end = packet->data + packet->length;
+
+ /*
+ * Loop over the packet, converting attrs to VPs.
+ */
+ if (start == 0) {
+ data = packet->data + 20;
+ } else {
+ data = packet->data + start;
+ data += data[1];
+ if (data >= end) return 0;
+ }
+
+ for (attr = data; attr < end; attr += attr[1]) {
+ const DICT_VENDOR *dv = NULL;
+
+#ifndef NEBUG
+ /*
+ * This code is copied from packet_ok().
+ * It could be put into a separate function.
+ */
+ if ((attr + 2) > end) {
+ nr_debug_error("Attribute overflows packet");
+ return -RSE_ATTR_OVERFLOW;
+ }
+
+ if (attr[1] < 2) {
+ nr_debug_error("Attribute length is too small");
+ return -RSE_ATTR_TOO_SMALL;
+ }
+
+ if ((attr + attr[1]) > end) {
+ nr_debug_error("Attribute length is too large");
+ return -RSE_ATTR_TOO_LARGE;
+ }
+#endif
+
+ if ((vendor == 0) && (attr[0] == attribute)) {
+ *pdata = attr + 2;
+ *plength = attr[1] - 2;
+ return attr - packet->data;
+ }
+
+#ifndef WITHOUT_VSAS
+ if (vendor != 0) {
+ uint32_t vendorpec;
+
+ if (attr[0] != PW_VENDOR_SPECIFIC) continue;
+
+ if (attr[1] < 6) continue;
+
+ memcpy(&vendorpec, attr + 2, 4);
+ vendorpec = ntohl(vendorpec);
+ if (vendor != vendorpec) continue;
+
+ if (!dv) {
+ dv = nr_dict_vendor_byvalue(vendor);
+ if (dv &&
+ ((dv->type != 1) || (dv->length != 1))) {
+ return -RSE_VENDOR_UNKNOWN;
+ }
+ }
+
+ /*
+ * No data.
+ */
+ if (attr[1] < 9) continue;
+
+ /*
+ * Malformed, or more than one VSA in
+ * the Vendor-Specific
+ */
+ if (attr[7] + 6 != attr[1]) continue;
+
+ /*
+ * Not the right VSA.
+ */
+ if (attr[6] != attribute) continue;
+
+ *pdata = attr + 8;
+ *plength = attr[1] - 8;
+ return attr - packet->data;
+ }
+#endif
+ }
+
+ return 0; /* nothing more: stop */
+}
+
diff --git a/radius/client.h b/radius/client.h
new file mode 100644
index 0000000..ab4718a
--- /dev/null
+++ b/radius/client.h
@@ -0,0 +1,1302 @@
+/*
+Copyright (c) 2011, Network RADIUS SARL
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file client.h
+ * \brief Main header file.
+ */
+
+#ifndef _RADIUS_CLIENT_H_
+#define _RADIUS_CLIENT_H_ 1
+
+/*
+ * System-specific header files.
+ */
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdarg.h>
+#include <sys/types.h>
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <radsec/radsec.h>
+#include <radsec/radsec-impl.h>
+#include <radsec/radius.h>
+
+/** \defgroup build Build Helpers
+ *
+ * These definitions give the GNU C compiler more information about
+ * the functions being compiled. They are used to either remove
+ * warnings, or to enable better warnings.
+ **/
+
+/** \defgroup custom Portability Functions
+ *
+ * These functions and definitions should be modified for your local
+ * system. See the individual definitions for details.
+ */
+
+/** \defgroup error Error handling
+ *
+ * These definitions and routines manage errors.
+ */
+
+/** \defgroup value_pair Attribute manipulation
+ *
+ * These routines manage structures which map to attributes.
+ */
+
+/**\defgroup dict Dictionary Lookup Functions
+ *
+ * \sa doc/dictionaries.txt
+ *
+ * The RADIUS dictionaries perform name to number mappings. The names
+ * are used only for administrator convenience, for parsing
+ * configuration files, and printing humanly-readable output. The
+ * numbers are used when encoding data in a packet.
+ *
+ * When attributes are decoded from a packet, the numbers are used to
+ * look up the associated name, which is then placed into a data
+ * structure.
+ *
+ * When the data structures are encoded into a packet, the numbers are
+ * used to create RFC and VSA format attributes.
+ *
+ * \attention The definitions, structures, and functions given below
+ * are useful only for implementing "low level" RADIUS
+ * functionality. There is usually no need to refer to them in a
+ * client application. The library should be used at a higher level,
+ * which exposes a much simpler API.
+ */
+
+/** \defgroup packet Packet manipulation
+ *
+ * These routines perform encoding and decoding of RADIUS packets.
+ */
+
+/** \defgroup print Print / parse functions
+ *
+ * These routines convert the internal data structures to a printable
+ * form, or parse them.
+ */
+
+/** \defgroup id ID allocation and freeing
+ *
+ * These routines manage RADIUS ID allocation.
+ */
+
+/** \defgroup attr Low-level attribute encode/decoding
+ *
+ * These routines perform "low level" encoding, decoding, sending, and
+ * reception of RADIUS attributes. They are called by the \ref packet
+ * functions.
+ *
+ * \attention The structures and functions given below are useful only
+ * for implementing "low level" RADIUS functionality. There is usually
+ * no need to refer to them in a client application. The library
+ * should be used at a higher level, which exposes a much simpler API.
+ */
+
+/** \defgroup internal Internal support functions.
+ *
+ * These functions are required to perform internal or "low-level"
+ * data manipulation. While they are exposed for completeness, they
+ * should not be called by any application.
+ */
+
+#ifdef PW_EAP_MESSAGE
+#ifndef PW_MESSAGE_AUTHENTICATOR
+#error EAP-Message requires Message-Authenticator
+#endif
+#endif
+
+#ifdef WITHOUT_OPENSSL
+#include "md5.h"
+#else
+#include <openssl/md5.h>
+#endif
+
+/** Define for compile-time selection of the MD5 functions. Defaults to using the OpenSSL functions. \ingroup custom */
+#define RS_MD5_CTX MD5_CTX
+/** Define for compile-time selection of the MD5 functions. Defaults to using the OpenSSL functions. \ingroup custom */
+#define RS_MD5Init MD5_Init
+/** Define for compile-time selection of the MD5 functions. Defaults to using the OpenSSL functions. \ingroup custom */
+#define RS_MD5Update MD5_Update
+/** Define for compile-time selection of the MD5 functions. Defaults to using the OpenSSL functions. \ingroup custom */
+#define RS_MD5Final MD5_Final
+
+
+#ifndef RS_MAX_PACKET_LEN
+/** The maximum size of a packet that the library will send or receive. \ingroup custom
+ *
+ * The RFC requirement is to handle at least 4K packets. However, if
+ * you expect to only do username/password authentication, this value
+ * can be set to a smaller value, such as 256.
+ *
+ * Be warned that any packets larger than this value will be ignored
+ * and silently discarded.
+ */
+#define RS_MAX_PACKET_LEN (4096)
+#endif
+
+#ifndef RS_MAX_ATTRIBUTES
+/** The maximum number of attributes that the library will allow in a packet. \ingroup custom
+ *
+ * Packets which contain more than ::RS_MAX_ATTRIBUTES will generate
+ * an error. This value is configurable because there may be a need
+ * to accept a large mumber of attributes.
+ *
+ * This value is ignored when packets are sent. The library will
+ * send as many attributes as it is told to send.
+ */
+#define RS_MAX_ATTRIBUTES (200)
+#endif
+
+#undef RS_MAX_PACKET_CODE
+/** The maximum RADIUS_PACKET::code which we can accept. \ingroup dict
+ *
+ * \attention This should not be changed, as it is used by other
+ * structures such as ::nr_packet_codes.
+ */
+#define RS_MAX_PACKET_CODE PW_COA_NAK
+
+/** The maximum vendor number which is permitted. \ingroup dict
+ *
+ * The RFCs require that the Vendor Id or Private Enterprise Number
+ * be encoded as 32 bits, with the upper 8 bits being zero.
+ */
+#define RS_MAX_VENDOR (1 << 24)
+
+/** Data Type Definitions. \ingroup dict
+ */
+#define TAG_VALID(x) ((x) < 0x20)
+
+/** The attribute is not encrypted. */
+#define FLAG_ENCRYPT_NONE (0)
+
+/** The attribute is encrypted using the RFC 2865 User-Password method */
+#define FLAG_ENCRYPT_USER_PASSWORD (1)
+
+/** The attribute is encrypted using the RFC 2868 Tunnel-Password method */
+#define FLAG_ENCRYPT_TUNNEL_PASSWORD (2)
+
+/** A set of flags which determine how the attribute should be handled.
+ *
+ * Most attributes are "normal", and do not require special handling.
+ * However, some require "encryption", tagging, or have other special
+ * formats. This structure contains the various options for the
+ * attribute formats.
+ */
+typedef struct attr_flags {
+ unsigned int has_tag : 1; /**< Attribute has an RFC 2868 tag */
+ unsigned int unknown : 1; /**< Attribute is unknown */
+#ifdef RS_TYPE_TLV
+ unsigned int has_tlv : 1; /* has sub attributes */
+ unsigned int is_tlv : 1; /* is a sub attribute */
+#endif
+ unsigned int extended : 1; /* extended attribute */
+ unsigned int extended_flags : 1; /* with flag */
+ unsigned int evs : 1; /* extended VSA */
+ uint8_t encrypt; /**< Attribute encryption method */
+ uint8_t length; /**< The expected length of the attribute */
+} ATTR_FLAGS;
+
+
+/** Defines an dictionary mapping for an attribute. \ingroup dict
+ *
+ * The RADIUS dictionaries map humanly readable names to protocol
+ * numbers. The protocol numbers are used to encode/decode the
+ * attributes in a packet.
+ */
+typedef struct nr_dict_attr {
+ unsigned int attr; /**< Attribute number */
+ rs_attr_type_t type; /**< Data type */
+ unsigned int vendor; /**< Vendor-Id number */
+ ATTR_FLAGS flags;
+ const char *name; /**< Printable name */
+} DICT_ATTR;
+
+/** Defines a dictionary mapping for a named enumeration. \ingroup dict
+ *
+ * This structure is currently not used.
+ */
+typedef struct nr_dict_value {
+ const DICT_ATTR *da; /**< pointer to a ::DICT_ATTR */
+ int value; /**< enumerated value */
+ char name[1]; /**< printable name */
+} DICT_VALUE;
+
+/** Defines an dictionary mapping for a vendor. \ingroup dict
+ *
+ * The RADIUS dictionaries map humanly readable vendor names to a
+ * Vendor-Id (or Private Enterprise Code) assigned by IANA. The
+ * Vendor-Id is used to encode/decode Vendor-Specific attributes in a
+ * packet.
+ */
+typedef struct nr_dict_vendor {
+ unsigned int vendor; /**< Vendor Private Enterprise Code */
+ size_t type; /**< size of Vendor-Type field */
+ size_t length; /**< size of Vendor-Length field */
+ const char *name; /**< Printable name */
+} DICT_VENDOR;
+
+/** Union holding all possible types of data for a ::VALUE_PAIR. \ingroup value_pair
+ *
+ */
+typedef union value_pair_data {
+ char strvalue[RS_MAX_STRING_LEN]; /* +1 for NUL */
+ uint8_t octets[253];
+ struct in_addr ipaddr;
+ struct in6_addr ipv6addr;
+ uint32_t date;
+ uint32_t integer;
+#ifdef RS_TYPE_SIGNED
+ int32_t sinteger;
+#endif
+#ifdef RS_TYPE_ABINARY
+ uint8_t filter[32];
+#endif
+ uint8_t ifid[8]; /* struct? */
+ uint8_t ipv6prefix[18]; /* struct? */
+#ifdef RS_TYPE_TLV
+ uint8_t *tlv;
+#endif
+} VALUE_PAIR_DATA;
+
+
+/** C structure version of a RADIUS attribute. \ingroup value_pair
+ *
+ * The library APIs use this structure to avoid depending on the
+ * details of the protocol.
+ */
+typedef struct value_pair {
+ const DICT_ATTR *da; /**< dictionary definition */
+ size_t length; /**< number of octets in the data */
+ int tag; /**< tag value if da->flags.has_tag */
+ struct value_pair *next; /**< enables a linked list of values */
+ VALUE_PAIR_DATA data; /**< the data of the attribute */
+} VALUE_PAIR;
+#define vp_strvalue data.strvalue
+#define vp_octets data.octets
+#define vp_ipv6addr data.ipv6addr
+#define vp_ifid data.ifid
+#define vp_ipv6prefix data.ipv6prefix
+#define vp_ipaddr data.ipaddr.s_addr
+#define vp_date data.integer
+#define vp_integer data.integer
+#ifdef RS_TYPE_ABINARY
+#define vp_filter data.filter
+#endif
+#ifdef RS_TYPE_ETHER
+#define vp_ether data.ether
+#endif
+#ifdef RS_TYPE_SIGNED
+#define vp_signed data.sinteger
+#endif
+#ifdef RS_TYPE_TLV
+#define vp_tlv data.tlv
+#endif
+
+#ifdef RS_TYPE_TLV
+#define RS_ATTR_MAX_TLV (4)
+extern const int nr_attr_shift[RS_ATTR_MAX_TLV];
+extern const int nr_attr_mask[RS_ATTR_MAX_TLV];
+extern const unsigned int nr_attr_max_tlv;
+#endif
+
+/** A structure which describes a RADIUS packet. \ingroup packet
+ *
+ * In general, it should not be necessary to refererence the elements
+ * of this structure.
+ */
+typedef struct radius_packet {
+ int sockfd; /** The socket descriptor */
+ struct sockaddr_storage src; /**< The packet source address */
+ struct sockaddr_storage dst; /**< the packet destination address */
+ const char *secret; /**< The shared secret */
+ size_t sizeof_secret; /**< Length of the shared secret */
+ unsigned int code; /**< The RADIUS Packet Code */
+ int id; /**< The RADIUS Packet Id */
+ size_t length; /**< The RADIUS Packet Length. This will be no larger than RADIUS_PACKET::sizeof_data */
+ uint8_t vector[16]; /**< A copy of the authentication vector */
+ int flags; /**< Internal flags. Do not modify this field. */
+ int attempts; /**< The number of transmission attempt */
+ uint8_t *data; /**< The raw packet data */
+ size_t sizeof_data; /**< size of the data buffer */
+ VALUE_PAIR *vps; /**< linked list of ::VALUE_PAIR */
+} RADIUS_PACKET;
+
+#define RS_PACKET_ENCODED (1 << 0)
+#define RS_PACKET_HEADER (1 << 1)
+#define RS_PACKET_SIGNED (1 << 2)
+#define RS_PACKET_OK (1 << 3)
+#define RS_PACKET_VERIFIED (1 << 4)
+#define RS_PACKET_DECODED (1 << 5)
+
+
+/** Track packets sent to a server. \ingroup id
+ *
+ * This data structure tracks Identifiers which are used to
+ * communicate with a particular destination server. The application
+ * should call nr_server_init() to initialize it. If necessary, the
+ * application should then call nr_server_set_ipv4() to open an IPv4
+ * socket to the server.
+ *
+ * If the RADIUS packets are being transported over an encapsulation
+ * layer (e.g. RADIUS over TLS), then nr_server_set_ipv4() does not
+ * need to be called. The ::nr_server_t structure should instead be
+ * associated wih the TLS session / socket.
+ */
+typedef struct nr_server_t {
+ int sockfd; /**< socket for sending packets */
+ int code; /**< default value for the Code */
+
+ struct sockaddr_storage src; /**< Source address of the packet */
+ struct sockaddr_storage dst; /**< Destination address of the packet */
+
+ /** The shared secret.
+ *
+ * See also nr_packet_send() and nr_packet_recv().
+ */
+ const char *secret;
+
+ /** The length of the shared secret.
+ *
+ * See also nr_packet_send() and nr_packet_recv().
+ */
+ size_t sizeof_secret;
+
+ int used; /**< Number of used IDs */
+
+ void *free_list; /**< For managing packets */
+
+ RADIUS_PACKET *ids[256]; /**< Pointers to "in flight" packets */
+} nr_server_t;
+
+
+/** Return a printable error message. \ingroup error
+ *
+ * This function returns a string describing the last error that
+ * occurred. These messages are intended for developers, and are not
+ * suitable for display to an end user. The application using this
+ * library should instead produce a "summary" message when an error
+ * occurs. e.g. "Failed to receive a response", is better than
+ * messages produced by this function, which contain text like
+ * "invalid response authentication vector". The first is
+ * understandable, the second is not.
+ *
+ * @param[in] error The error code (can be less than zero)
+ * @return A printable string describing the error.
+ */
+extern const char *nr_strerror(int error);
+
+/** Allocate a ::VALUE_PAIR which refers to a ::DICT_ATTR. \ingroup value_pair
+ *
+ * This returned ::VALUE_PAIR has no data associated with it. The
+ * nr_vp_set_data() function must be called before placing the
+ * ::VALUE_PAIR in a ::RADIUS_PACKET.
+ *
+ * @param[in] da The ::DICT_ATTR associated with the ::VALUE_PAIR
+ * @return The created ::VALUE_PAIR, or NULL on error.
+ */
+extern VALUE_PAIR *nr_vp_alloc(const DICT_ATTR *da);
+
+/** Free a ::VALUE_PAIR. \ingroup value_pair
+ *
+ * This function frees the ::VALUE_PAIR, and sets the head pointer to NULL.
+ * If head refers to a ::VALUE_PAIR list, then all of the structures in the
+ * list are freed.
+ *
+ * @param[in,out] head The pointer to a ::VALUE_PAIR, or a ::VALUE_PAIR list.
+ */
+extern void nr_vp_free(VALUE_PAIR **head);
+
+/** Initializes a ::VALUE_PAIR from a ::DICT_ATTR \ingroup value_pair
+ *
+ * This function assumes that the ::VALUE_PAIR points to existing
+ * and writable memory.
+ *
+ * @param[in,out] vp The ::VALUE_PAIR to be initialized
+ * @param[in] da The ::DICT_ATTR used to initialize the ::VALUE_PAIR
+ * @return The initialized ::VALUE_PAIR, or NULL on error.
+ */
+extern VALUE_PAIR *nr_vp_init(VALUE_PAIR *vp, const DICT_ATTR *da);
+
+/** Allocate a ::VALUE_PAIR which refers to an unknown attribute. \ingroup value_pair
+ *
+ * It is used when an attribute is received, and that attribute does
+ * not exist in the dictionaries.
+ *
+ * The returned ::VALUE_PAIR has no data (i.e. VALUE_PAIR::length is
+ * zero). The nr_vp_set_data() function must be called before
+ * placing the ::VALUE_PAIR in a ::RADIUS_PACKET.
+ *
+ * @param[in] attr The attribute number, 0..2^16
+ * @param[in] vendor The vendor number, 0..2^16
+ * @return The created ::VALUE_PAIR, or NULL on error.
+ */
+extern VALUE_PAIR *nr_vp_alloc_raw(unsigned int attr, unsigned int vendor);
+
+/** Set the data associated with a previously allocated ::VALUE_PAIR. \ingroup value_pair
+ *
+ * If this function succeeds, VALUE_PAIR::length is no longer zero,
+ * and the structure contains the data.
+ *
+ * @param[in,out] vp The ::VALUE_PAIR to update
+ * @param[in] data Data to set inside of the ::VALUE_PAIR
+ * @param[in] data_len Length of the data field
+ * @return <0 on error, 0 for "data was truncated"
+ * >0 for "data successfully added"
+ */
+extern int nr_vp_set_data(VALUE_PAIR *vp, const void *data, size_t data_len);
+
+/** Create a ::VALUE_PAIR and set its data. \ingroup value_pair
+ *
+ * @param[in] attr The attribute number of the ::VALUE_PAIR to create
+ * @param[in] vendor The vendor number of the ::VALUE_PAIR to create
+ * @param[in] data Data to set inside of the ::VALUE_PAIR
+ * @param[in] data_len Length of the data field
+ * @return The created ::VALUE_PAIR, or NULL on error.
+ */
+extern VALUE_PAIR *nr_vp_create(int attr, int vendor, const void *data,
+ size_t data_len);
+
+/** Append a ::VALUE_PAIR to the end of a ::VALUE_PAIR list. \ingroup value_pair
+ *
+ * @param[in,out] head The head of the ::VALUE_PAIR list. May not be NULL.
+ * @param[in] vp The ::VALUE_PAIR to append to the list.
+ */
+extern void nr_vps_append(VALUE_PAIR **head, VALUE_PAIR *vp);
+
+/** Search a ::VALUE_PAIR list for one of a given number. \ingroup value_pair
+ *
+ * @param[in] head The head of the ::VALUE_PAIR list to search.
+ * @param[in] attr The attribute number of the ::VALUE_PAIR to find
+ * @param[in] vendor The vendor number of the ::VALUE_PAIR to find
+ * @return The found ::VALUE_PAIR, or NULL if it was not found.
+ */
+extern VALUE_PAIR *nr_vps_find(VALUE_PAIR *head,
+ unsigned int attr, unsigned int vendor);
+
+/** Look up an attribute in the dictionaries. \ingroup dict
+ *
+ * The dictionary mapping contains information about the attribute,
+ * such as printable name, data type (ipaddr, integer, etc), and
+ * various other things used to encode/decode the attribute in a
+ * packet.
+ *
+ * \attention There is usually no need to call this function. Use
+ * the RS_DA_* definitions instead.
+ *
+ * @param[in] attr Value of the attribute
+ * @param[in] vendor Value of the vendor
+ * @return NULL for "not found", or a pointer to the attribute mapping.
+ */
+extern const DICT_ATTR *nr_dict_attr_byvalue(unsigned int attr,
+ unsigned int vendor);
+
+/** Look up an attribute in the dictionaries. \ingroup dict
+ *
+ * The dictionary mapping contains information about the attribute,
+ * such as printable name, data type (ipaddr, integer, etc), and
+ * various other things used to encode/decode the attribute in a
+ * packet.
+ *
+ * \attention There is usually no need to call this function.
+ *
+ * @param[in] name Name of the attribute
+ * @return NULL for "not found", or a pointer to the attribute mapping.
+ */
+extern const DICT_ATTR *nr_dict_attr_byname(const char *name);
+
+/** Converts raw data to a ::DICT_ATTR structure. \ingroup dict
+ *
+ * It is called when the library is asked to decode an attribute
+ * which is not in the pre-defined dictionaries.
+ *
+ * \attention There is usually no need to call this function.
+ *
+ * @param[in,out] da The ::DICT_ATTR structure to initialize
+ * @param[in] attr The attribute number
+ * @param[in] vendor The vendor number
+ * @param[in] buffer The buffer where the name of the attribute is stored
+ * @param[in] bufsize Size of the buffer
+ * @return <0 for error, 0 for success
+ */
+extern int nr_dict_attr_2struct(DICT_ATTR *da,
+ unsigned int attr, unsigned int vendor,
+ char *buffer, size_t bufsize);
+
+/** Unused. \ngroup dict
+ *
+ */
+extern const DICT_VALUE *nr_dict_value_byattr(unsigned int attr,
+ unsigned int vendor,
+ int value);
+
+/** Unused. \ngroup dict
+ *
+ */
+const DICT_VALUE *nr_dict_value_byname(unsigned int attr,
+ unsigned int vendor,
+ const char *name);
+
+/** Look up a vendor in the dictionaries. \ingroup dict
+ *
+ * The dictionary mapping contains information about the vendor, such
+ * as printable name, VSA encoding method, etc.
+ *
+ * \attention There is usually no need to call this function.
+ * Applications do not need access to low-level RADIUS protocol
+ * information.
+ *
+ * @param[in] name Name of the vendor.
+ * @return NULL for "not found", or a pointer to the vendor mapping.
+ */
+extern int nr_dict_vendor_byname(const char *name);
+
+/** Look up an vendor in the dictionaries. \ingroup dict
+ *
+ * The dictionary mapping contains information about the vendor, such
+ * as printable name, VSA encoding method, etc.
+ *
+ * \attention There is usually no need to call this function.
+ *
+ * @param[in] vendor Vendor-Id (or Private Enterprise code) for the vendor.
+ * @return NULL for "not found", or a pointer to the vendor mapping.
+ */
+extern const DICT_VENDOR *nr_dict_vendor_byvalue(unsigned int vendor);
+
+/** Static array of known vendors. \ingroup dict
+ *
+ * \attention This structure should only be accessed by internal RADIUS library
+ * functions.
+ */
+extern const DICT_VENDOR nr_dict_vendors[];
+
+/** The number of attribute definitions in the dictionary. \ingroup dict
+ *
+ * This number is guaranteed to be at least 256, for speed.
+ *
+ * \attention This variable should only be accessed by internal RADIUS library
+ * functions.
+ */
+extern const int nr_dict_num_attrs;
+
+/** The list of attribute definitions. \ingroup dict
+ *
+ * The "standard" RFC attributes are located in the first 256
+ * entries. Standard attributes without a dictionary definition are
+ * given an empty entry.
+ *
+ * The attributes are orderd by (vendor, attribute), in increasing
+ * order. This allows the dictionary lookups to find attributes by a
+ * binary search.
+ *
+ * \attention This variable should only be accessed by internal RADIUS library
+ * functions.
+ */
+extern const DICT_ATTR nr_dict_attrs[];
+
+/** The number of attributes with names. \ingroup dict
+ *
+ * \attention This variable should only be accessed by internal RADIUS library
+ * functions.
+ */
+extern const int nr_dict_num_names;
+
+/** The list of attribute definitions, organized by name. \ingroup dict
+ *
+ * The attributes are orderd by name (case insensitive), in
+ * increasing order. This allows the dictionary lookups to find
+ * attributes by a binary search.
+ *
+ * \attention This variable should only be accessed by internal RADIUS library
+ * functions.
+ */
+extern const DICT_ATTR const *nr_dict_attr_names[];
+
+/** Static array containing names the RADIUS_PACKET::code field. \ingroup dict
+ *
+ * The names are hard-coded and not in any dictionary because they do
+ * not change.
+ *
+ * The names are exported because they may be useful in your
+ * application. Packet codes which are not handled by the library
+ * have NULL for their names.
+ */
+extern const char *nr_packet_codes[RS_MAX_PACKET_CODE + 1];
+
+/** Verifies that a packet is "well formed". \ingroup packet
+ *
+ * This function performs basic validation to see if the packet is
+ * well formed. It is automatically called by nr_packet_decode().
+ *
+ * @param[in] packet A pointer to the ::RADIUS_PACKET data.
+ * @return <0 means malformed, >= 0 means well-formed.
+ */
+extern int nr_packet_ok(RADIUS_PACKET *packet);
+
+/** Verifies that a packet is "well formed". \ingroup packet
+ *
+ * This function performs basic validation to see if the packet is
+ * well formed. You should normally use nr_packet_ok() instead of
+ * this function.
+ *
+ * @param[in] data A pointer to the raw packet data.
+ * @param[in] sizeof_data The length of the raw packet data
+ * @return <0 means malformed, >= 0 means well-formed.
+ */
+extern int nr_packet_ok_raw(const uint8_t *data, size_t sizeof_data);
+
+/** Encodes a packet. \ingroup packet
+ *
+ * This function encodes a packet using the fields of the
+ * ::RADIUS_PACKET structure. The RADIUS_PACKET::code and
+ * RADIUS_PACKET::id fields are used to fill in the relevant fields
+ * of the raw (encoded) packet. The RADIUS_PACKET::vps list is
+ * walked to encode the attributes. The packet is signed, if
+ * required.
+ *
+ * The raw packet is placed into the RADIUS_PACKET::data field, up to
+ * RADIUS_PACKET::sizeof_data bytes. the RADIUS_PACKET::length field
+ * is updated with the length of the raw packet. This field is
+ * always less than, or equal to, the RADIUS_PACKET::size_data field.
+ * If there is insufficient room to store all of the attributes, then
+ * some attributes are silently discarded.
+ *
+ * The RADIUS_PACKET::vector field is either calculated as part of
+ * the signing process, or is initialized by this function to be a
+ * random sequence of bytes. That field should therefore be left
+ * alone by the caller.
+ *
+ * When the encoding has been successful, it sets the
+ * RADIUS_PACKET::encoded field to non-zero.
+ *
+ * In addition, all required attribute "encryption" is performed.
+ *
+ * User-Password. The vp_strvalue field is assumed to contain the
+ * "clear-text" version of the password. The encrypted version is
+ * calculated, and placed in the packet.
+ *
+ * CHAP-Password. The vp_strvalue field is assumed to contain the
+ * "clear-text" version of the password. The encrypted version is
+ * calculated, and placed in the packet. If the RADIUS_PACKET::vps
+ * list contains a CHAP-Challenge attribute, it is used. Otherwise
+ * the RADIUS_PACKET::vector field is used a the challenge.
+ *
+ * Message-Authenticator. The contents of the Message-Authenticator
+ * in the RADIUS_PACKET::vps list are ignored. Instead, a
+ * "place-holder" is put into the packt. Tthe correct value is
+ * calculated and placed into the packet by nr_packet_sign().
+ *
+ * The RADIUS_PACKET::vps list is left untouched by this function,
+ * even when attribute encryption or signing is performed. Any
+ * VALUE_PAIR structures can therefore be taken from static "const"
+ * variables.
+ *
+ * @param[in] packet The RADIUS packet to encode.
+ * @param[in] original The original request, when encoding a response.
+ * @return <0 on error, >= 0 on success.
+ */
+extern int nr_packet_encode(RADIUS_PACKET *packet, const RADIUS_PACKET *original);
+
+/** Decodes a packet. \ingroup packet
+ *
+ * This function decodes a packet from the RADIUS_PACKET::data field
+ * into a sequence of ::VALUE_PAIR structures in the
+ * RADIUS_PACKET::vps list.
+ *
+ * @param[in] packet The RADIUS packet to decode.
+ * @param[in] original The original request, when decoding a response.
+ * @return <0 on error, >= 0 on success.
+ */
+extern int nr_packet_decode(RADIUS_PACKET *packet, const RADIUS_PACKET *original);
+
+/** Signs a packet so that it can be sent. \ingroup packet
+ *
+ * This function calculates the Message-Authenticator (if required),
+ * and signs the packet.
+ *
+ * @param[in] packet The RADIUS packet to sign.
+ * @param[in] original The original request, when signing a response.
+ * @return <0 on error, >= 0 on success.
+ */
+extern int nr_packet_sign(RADIUS_PACKET *packet, const RADIUS_PACKET *original);
+
+/** Verifies that a packet is well-formed and contains the correct signature. \ingroup packet
+ *
+ * If "original" is specified, it also verifies that the packet is a
+ * response to the original request, and that it has the correct
+ * signature.
+ *
+ * @param[in] packet The RADIUS packet to verify.
+ * @param[in] original The original request, when verifying a response.
+ * @return <0 on error, >= 0 on success.
+ */
+extern int nr_packet_verify(RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original);
+
+/** Pretty-prints a hex dump of a RADIUS packet. \ingroup packet print
+ *
+ * This function is available only in debugging builds of the
+ * library. It is useful during development, but should not be used
+ * in a production system.
+ *
+ * The packet headers are printed individually, and each attribute is
+ * printed as "type length data..."
+ *
+ * @param[in] packet The RADIUS packet to print
+ */
+extern void nr_packet_print_hex(RADIUS_PACKET *packet);
+
+
+/** Return the given number of random bytes. \ingroup custom
+ *
+ * This function should be replaced by one that is specific to your
+ * system.
+ *
+ * This is a wrapper function which enables the library to be more
+ * portable.
+ *
+ * @param[in] data Location where the random bytes will be stored
+ * @param[in] data_len Number of bytes to store
+ * @return <0 on error, or the total number of bytes stored.
+ */
+extern ssize_t nr_rand_bytes(uint8_t *data, size_t data_len);
+
+/** Return a random 32-bit integer. \ingroup custom
+ *
+ * This function should be replaced by one that is specific to your
+ * system. The version supplied here just calls nr_rand_bytes() each
+ * time, which is slow.
+ *
+ * This is a wrapper function which enables the library to be more
+ * portable.
+ *
+ * @return An unsigned 32-bit random integer.
+ */
+extern uint32_t nr_rand(void);
+
+/** Add a time to the given ::struct timeval. \ingroup custom
+ *
+ * This is a wrapper function which enables the library to be more
+ * portable.
+ *
+ * @param[in,out] t The timeval to which the time is added.
+ * @param[in] seconds Time in seconds to add
+ * @param[in] usec Time in microseconds to add
+ */
+extern void nr_timeval_add(struct timeval *t, unsigned int seconds,
+ unsigned int usec);
+
+/** Compare two times. \ingroup custom
+ *
+ * This is a wrapper function which enables the library to be more
+ * portable.
+ *
+ * @param[in] a One timeval
+ * @param[in] b Another one
+ * @return a <=> b
+ */
+extern int nr_timeval_cmp(const struct timeval *a, const struct timeval *b);
+
+/** Initializes an ::nr_server_t. \ingroup id
+ *
+ * @param[in,ut] s The ::nr_server_t to initialize
+ * @param[in] code The packet code used for packets sent to this server
+ * @param[in] secret The shared secret used for packet sent to this server
+ * @return <0 for error, >= 0 for success
+ */
+extern int nr_server_init(nr_server_t *s, int code, const char *secret);
+
+/** Closes an ::nr_server_t data structure. \ingroup id
+ *
+ * Ensures that all IDs are free, and closes the socket.
+ *
+ * @param[in] s The server structure to close.
+ * @return <0 for error, 0 for success
+ */
+extern int nr_server_close(const nr_server_t *s);
+
+/** Allocate a RADIUS_PACKET::id value for sending a packet to a server. \ingroup id
+ *
+ * This function allocates a RADIUS_PACKET::id from the ::nr_server_t
+ * structure. It also fills in the RADIUS_PACKET::sockfd,
+ * RADIUS_PACKET::code, and RADIUS_PACKET::dst fields.
+ *
+ * @param[in] s The server structure which tracks the ID
+ * @param[in] packet The packet which needs an ID
+ * @return <0 for error, 0 for success
+ */
+extern int nr_server_id_alloc(nr_server_t *id, RADIUS_PACKET *packet);
+
+/** Re-allocate a RADIUS_PACKET::id value for sending a packet to a server. \ingroup id
+ *
+ * It is used when retransmitting an Accounting-Request packet to a
+ * server, after updating the Acct-Delay-Time field. The "realloc"
+ * name means that the new ID is allocated, and is guaranteed to be
+ * different from the old one.
+ *
+ * @param[in] s The server structure which tracks the ID
+ * @param[in] packet The packet which needs a new ID
+ * @return <0 for error, 0 for success
+ */
+extern int nr_server_id_realloc(nr_server_t *id, RADIUS_PACKET *packet);
+
+/** Free a RADIUS_PACKET::id value after sending a packet to a server. \ingroup id
+ *
+ * @param[in] s The server structure which tracks the ID
+ * @param[in] packet The packet which has an ID, and wants to free it
+ * @return <0 for error, 0 for success
+ */
+extern int nr_server_id_free(nr_server_t *id, RADIUS_PACKET *packet);
+
+
+/** Allocates a packet using malloc(), and initializes it. \ingroup id
+ *
+ * @param[in] s The server structure
+ * @param[in,out] packet_p Pointer to the ::RADIUS_PACKET to be allocated
+ * @return <0 for error, 0 for success
+ */
+extern int nr_server_packet_alloc(const nr_server_t *s, RADIUS_PACKET **packet_p);
+
+/** Record a humanly readable error message. \ingroup error
+ *
+ * \attention This structure should only be accessed by internal
+ * RADIUS library functions.
+ *
+ * @param[in] fmt The format to use.
+ */
+extern void nr_strerror_printf(const char *fmt, ...);
+
+#ifndef NDEBUG
+#define nr_debug_error nr_strerror_printf /** \ingroup error */
+#else
+#define nr_debug_error if (0) nr_strerror_printf
+#endif
+
+/** Encrypts or decrypts a User-Password attribute. \ingroup internal
+ *
+ * \attention This structure should only be accessed by internal
+ * RADIUS library functions.
+ *
+ * @param[out] output Buffer where the password is stored
+ * @param[out] outlen Size of the output buffer
+ * @param[in] input Input buffer with password
+ * @param[in] inlen Length of the input buffer
+ * @param[in] secret The shared secret
+ * @param[in] vector Authentication vector
+ * @return <0 on error, or the length of data in "output"
+ */
+extern ssize_t nr_password_encrypt(uint8_t *output, size_t outlen,
+ const uint8_t *input, size_t inlen,
+ const char *secret, const uint8_t *vector);
+
+/** Encrypts a Tunnel-Password attribute. \ingroup internal
+ *
+ * \attention This structure should only be accessed by internal
+ * RADIUS library functions.
+ *
+ * @param[out] output Buffer where the password is stored
+ * @param[out] outlen Size of the output buffer
+ * @param[in] input Input buffer with password
+ * @param[in] inlen Length of the input buffer
+ * @param[in] secret The shared secret
+ * @param[in] vector Authentication vector
+ * @return <0 on error, or the length of data in "output"
+ */
+extern ssize_t nr_tunnelpw_encrypt(uint8_t *output, size_t outlen,
+ const uint8_t *input, size_t inlen,
+ const char *secret, const uint8_t *vector);
+
+/** Decrypts a Tunnel-Password attribute. \ingroup internal
+ *
+ *
+ * \attention This structure should only be accessed by internal
+ * RADIUS library functions.
+ *
+ * @param[out] output Buffer where the password is stored
+ * @param[out] outlen Size of the output buffer
+ * @param[in] input Input buffer with password
+ * @param[in] inlen Length of the input buffer
+ * @param[in] secret The shared secret
+ * @param[in] vector Authentication vector
+ * @return <0 on error, or the length of data in "output"
+ */
+extern ssize_t nr_tunnelpw_decrypt(uint8_t *output, size_t outlen,
+ const uint8_t *input, size_t inlen,
+ const char *secret, const uint8_t *vector);
+
+/** Calculates an HMAC-MD5. \ingroup internal
+ *
+ * @param[in] data Data to be hashed
+ * @param[in] data_len Length of data to be hashed
+ * @param[in] key Key for the HMAC
+ * @param[in] key_len Length of the key
+ * @param[out] digest
+ */
+extern void nr_hmac_md5(const uint8_t *data, size_t data_len,
+ const uint8_t *key, size_t key_len,
+ uint8_t digest[16]);
+
+/** Checks if a TLV is properly formatted. \ingroup internal
+ *
+ * \attention This structure should only be accessed by internal
+ * RADIUS library functions.
+ *
+ * @param[in] data Data to check
+ * @param[in] length Length of the data field
+ * @param[in] dv_type Length of the TLV "type" field
+ * @param[in] dv_length Length of the TLV "length" field
+ * @return <0 on error, 0 for "TLV is OK"
+ */
+extern int nr_tlv_ok(const uint8_t *data, size_t length,
+ size_t dv_type, size_t dv_length);
+
+/** A callback function used by nr_packet_walk(). \ingroup packet
+ *
+ * The function should return 0 on success (i.e. keep walking), and
+ * otherwise a negative number indicating an error code
+ * (::nr_error_t). That negative number will be used as the return
+ * code for nr_packet_walk().
+ */
+typedef int (*nr_packet_walk_func_t)(void *, const DICT_ATTR *, const uint8_t *, size_t);
+
+/** Walks over all attributes in a packet. \ingroup packet
+ *
+ * This function is an iterator which calls a user-supplied callback
+ * function for each attribute in the packet. It should be used
+ * instead of manually walking over the attributes. There are a
+ * number of odd corner cases when handling Vendor-Specific
+ * attributes, and it is easy to get those corner cases wrong.
+ *
+ * This function iterates over *all* attributes, including nested
+ * VSAs. That is its main value.
+ *
+ * Encrypted attributes such as User-Password are not decrypted.
+ *
+ * @param[in] packet The packet containing the data
+ * @param[in] ctx A user-supplied context. May be NULL
+ * @param[in] callback The callback function where the information is passed.
+ *
+ * @return <0 for error,
+ * 0 for success.
+ */
+extern int nr_packet_walk(RADIUS_PACKET *packet, void *ctx,
+ nr_packet_walk_func_t callback);
+
+/** Initialize a packet
+ *
+ * If original is specified, the packet is initialized as a response
+ * to the original request.
+ *
+ * @param[in,out] packet The packet to initialize
+ * @param[in] original The original request (if any) to use as a template
+ * @param[in] secret Shared secret
+ * @param[in] code RADIUS Code field.
+ * @param[in] data Buffer where packets will be stored (RADIUS_PACKET::data)
+ * @param[in] sizeof_data Size of buffer (RADIUS_PACKET::sizeof_data)
+ * @return <0 on error, 0 for success.
+ */
+extern int nr_packet_init(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
+ const char *secret, int code,
+ void *data, size_t sizeof_data);
+
+/** Add one attribute to the packet.
+ *
+ * This function can be used to add "raw" data to a packet. It
+ * allows the caller to extend the RADIUS packet without using a
+ * ::VALUE_PAIR data structure.
+ *
+ * Some attributes are handled specially by this function.
+ *
+ * EAP-Message. This attribute is automatically split into 253-octet
+ * chunks.
+ *
+ * User-Password, CHAP-Password, and Message-Authenticator. These
+ * attributes are automatically encrypted, as is done by
+ * nr_packet_encode().
+ *
+ * @param[in] packet The packet to edit
+ * @param[in] original The original request (if any)
+ * @param[in] da Pointer to the attribute definition
+ * @param[in] data Data to append to the packet
+ * @param[in] data_len Length of data to append to the packet
+ *
+ * @return <0 for error, >= 0 for "successfully appended data"
+ * The function returns the number of octets appended to the packet.
+ */
+extern ssize_t nr_packet_attr_append(RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const DICT_ATTR *da,
+ const void *data, size_t data_len);
+
+
+/** Encodes any ::VALUE_PAIR into an attribute. \ingroup attr
+ *
+ * This function can be called for any ::VALUE_PAIR. It will examine
+ * that structure, and call one of nr_vp2rfc() or nr_vp2vsa() as
+ * necessary.
+ *
+ * \attention This function should not be called.
+ *
+ * @param[in] packet Where to place the encoded attribute.
+ * @param[in] original The original request (optional), if "packet" is a response
+ * @param[in,out] pvp The ::VALUE_PAIR to encode. On any return >=0, it is updated to point to the "next" ::VALUE_PAIR which should be encoded.
+ * @param[in] data Where the attribute is to be encoded.
+ * @param[in] room How many octets are available for attribute encoding.
+ *
+ * @return <0 for error, or the number of octets used to encode the attribute.
+ */
+extern ssize_t nr_vp2attr(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const VALUE_PAIR **pvp, uint8_t *data, size_t room);
+
+/** Encodes an RFC "standard" ::VALUE_PAIR into an attribute. \ingroup attr
+ *
+ * \attention This function should not be called.
+ *
+ * @param[in] packet Where to place the encoded attribute.
+ * @param[in] original The original request (optional), if "packet" is a response
+ * @param[in,out] pvp The ::VALUE_PAIR to encode. On any return >=0, it is updated to point to the "next" ::VALUE_PAIR which should be encoded.
+ * @param[in] data Where the attribute is to be encoded.
+ * @param[in] room How many octets are available for attribute encoding.
+ *
+ * @return <0 for error, or the number of octets used to encode the attribute.
+ */
+extern ssize_t nr_vp2rfc(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const VALUE_PAIR **pvp,
+ uint8_t *data, size_t room);
+
+/** Decodes any attribute into a ::VALUE_PAIR. \ingroup attr
+ *
+ * \attention This function should not be called.
+ *
+ * @param[in] packet The packet containing the attribute to be decoded.
+ * @param[in] original The original request (optional), if "packet" is a response
+ * @param[out] pvp Where to place the decoded ::VALUE_PAIR. On any return >=0, it is updated to point to the ::VALUE_PAIR which was decoded from the packet.
+ * @param[in] data Where the attribute is to be encoded.
+ * @param[in] length How many octets are available for attribute decoding.
+ *
+ * @return <0 for error, or the number of octets used to decode the attribute.
+ */
+extern ssize_t nr_attr2vp(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
+ const uint8_t *data, size_t length,
+ VALUE_PAIR **pvp);
+
+/** Decodes an RFC "standard" attribute into a ::VALUE_PAIR. \ingroup attr
+ *
+ * \attention This function should not be called.
+ *
+ * @param[in] packet The packet containing the attribute to be decoded.
+ * @param[in] original The original request (optional), if "packet" is a response
+ * @param[out] pvp Where to place the decoded ::VALUE_PAIR. On any return >=0, it is updated to point to the ::VALUE_PAIR which was decoded from the packet.
+ * @param[in] data Where the attribute is to be encoded.
+ * @param[in] length How many octets are available for attribute decoding.
+ *
+ * @return <0 for error, or the number of octets used to decode the attribute.
+ */
+extern ssize_t nr_attr2vp_rfc(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const uint8_t *data, size_t length,
+ VALUE_PAIR **pvp);
+
+/** Decodes a Vendor-Specific attribute into a ::VALUE_PAIR. \ingroup attr
+ *
+ * \attention This function should not be called.
+ *
+ * @param[in] packet The packet containing the attribute to be decoded.
+ * @param[in] original The original request (optional), if "packet" is a response
+ * @param[out] pvp Where to place the decoded ::VALUE_PAIR. On any return >=0, it is updated to point to the ::VALUE_PAIR which was decoded from the packet.
+ * @param[in] data Where the attribute is to be encoded.
+ * @param[in] length How many octets are available for attribute decoding.
+ *
+ * @return <0 for error, or the number of octets used to decode the attribute.
+ */
+extern ssize_t nr_attr2vp_vsa(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const uint8_t *data, size_t length,
+ VALUE_PAIR **pvp);
+
+/** Decodes an attribute with an unexpected length into a ::VALUE_PAIR. \ingroup attr
+ *
+ * \attention This function should not be called.
+ *
+ * @param[in] packet The packet containing the attribute to be decoded.
+ * @param[in] original The original request (optional), if "packet" is a response
+ * @param[out] pvp Where to place the decoded ::VALUE_PAIR. On any return >=0, it is updated to point to the ::VALUE_PAIR which was decoded from the packet.
+ * @param[in] data Where the attribute is to be encoded.
+ * @param[in] length How many octets are available for attribute decoding.
+ *
+ * @return <0 for error, or the number of octets used to decode the attribute.
+ */
+extern ssize_t nr_attr2vp_raw(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const uint8_t *data, size_t length,
+ VALUE_PAIR **pvp);
+
+/** Encodes a Vendor-Specific ::VALUE_PAIR into an attribute.
+ *
+ * \attention This function should not be called.
+ *
+ * @param[in] packet Where to place the encoded attribute.
+ * @param[in] original The original request (optional), if "packet" is a response
+ * @param[in,out] pvp The ::VALUE_PAIR to encode. On any return >=0, it is updated to point to the "next" ::VALUE_PAIR which should be encoded.
+ * @param[in] data Where the attribute is to be encoded.
+ * @param[in] room How many octets are available for attribute encoding.
+ *
+ * @return <0 for error, or the number of octets used to encode the attribute.
+ */
+extern ssize_t nr_vp2vsa(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
+ const VALUE_PAIR **pvp, uint8_t *data,
+ size_t room);
+
+/** Returns raw data from the RADIUS packet, for a given attribute. \ingroup attr
+ *
+ * This function can be called repeatedly to find all instances of a
+ * given attribute. The first time it is called, the "start"
+ * parameter should be zero. If the function returns a non-zero
+ * positive number, it means that there *may* be more attributes
+ * available. The returned value should be then passed via the
+ * "start" option in any subsequent calls to the function.
+ *
+ * This function should be called by an application when it wants
+ * access to data which is not in the pre-defined dictionaries.
+ *
+ * @param[in] packet The packet containing the attribute.
+ * @param[in] start Where in the packet we start searching for the attribute.
+ * @param[in] attr Value of the attribute to search for
+ * @param[in] vendor Value of the vendor (use 0 for IETF attributes)
+ * @param[out] pdata Pointer to the data. If no data was found, the pointer is unchanged.
+ * @param[out] plength Length of the data. If no data was found, the value pointed to is unchanged.
+ *
+ * @return <0 for error,
+ * 0 for "no attribute found, stop searching"
+ * >0 offset where the attribute was found.
+ */
+extern ssize_t nr_attr2data(const RADIUS_PACKET *packet, ssize_t start,
+ unsigned int attr, unsigned int vendor,
+ const uint8_t **pdata, size_t *plength);
+
+/** Pretty-print the entire ::VALUE_PAIR \ingroup print
+ *
+ * All data is printed in ASCII format. The data type of "octets" is
+ * printed as a hex string (e.g. 0xabcdef01...). The data type of
+ * "ipaddr" is printed as a dotted-quad (e.g. 192.0.2.15).
+ *
+ * The format is "Attribute-Name = value"
+ *
+ * @param[out] buffer Where the printable version of the ::VALUE_PAIR is stored
+ * @param[in] bufsize size of the output buffer
+ * @param[in] vp ::VALUE_PAIR to print
+ * @return length of data in buffer
+ */
+extern size_t nr_vp_snprintf(char *buffer, size_t bufsize, const VALUE_PAIR *vp);
+
+/** Pretty-print the VALUE_PAIR::data field \ingroup print
+ *
+ * Prints the value of a ::VALUE_PAIR, without the name or "=" sign.
+ *
+ * @param[out] buffer Where the printable version of the ::VALUE_PAIR is stored
+ * @param[in] bufsize size of the output buffer
+ * @param[in] vp ::VALUE_PAIR to print
+ * @return length of data in buffer
+ */
+extern size_t nr_vp_snprintf_value(char *buffer, size_t bufsize, const VALUE_PAIR *vp);
+
+/** Prints a list of :VALUE_PAIR structures to the given output. \ingroup print
+ *
+ * @param[in] fp Where to print the results
+ * @param[in] vps Linked list of ::VALUE_PAIR to print
+ */
+extern void nr_vp_fprintf_list(FILE *fp, const VALUE_PAIR *vps);
+
+/** Scan a string into a ::VALUE_PAIR. The counterpart to
+ * nr_vp_snprintf_value() \ingroup print
+ *
+ * @param[in] string Printable version of the ::VALUE_PAIR
+ * @param[out] pvp Newly allocated ::VALUE_PAIR
+ * @return <0 on error, 0 for success.
+ */
+extern int nr_vp_sscanf(const char *string, VALUE_PAIR **pvp);
+
+/** Scan the data portion of a ::VALUE_PAIR. The counterpart to
+ * nr_vp_snprintf_value() \ingroup print
+ *
+ * @param[in,out] vp The ::VALUE_PAIR where the data will be stored
+ * @param[in] value The string version of the data to be parsed
+ * @return <0 on error, >=0 for the number of characters parsed in value.
+ */
+extern ssize_t nr_vp_sscanf_value(VALUE_PAIR *vp, const char *value);
+
+#if defined(__GNUC__)
+# define PRINTF_LIKE(n) __attribute__ ((format(printf, n, n+1)))
+# define NEVER_RETURNS __attribute__ ((noreturn))
+# define UNUSED __attribute__ ((unused))
+# define BLANK_FORMAT " " /* GCC_LINT whines about empty formats */
+#else
+
+/** Macro used to quiet compiler warnings inside of the library. \ingroup build
+ *
+ */
+# define PRINTF_LIKE(n)
+
+/** Macro used to quiet compiler warnings inside of the library. \ingroup build
+ *
+ */
+# define NEVER_RETURNS
+
+/** Macro used to quiet compiler warnings inside of the library. \ingroup build
+ *
+ */
+# define UNUSED
+
+/** Macro used to quiet compiler warnings inside of the library. \ingroup build
+ *
+ */
+# define BLANK_FORMAT ""
+#endif
+
+#endif /* _RADIUS_CLIENT_H_ */
diff --git a/radius/common.pl b/radius/common.pl
new file mode 100644
index 0000000..7042fe5
--- /dev/null
+++ b/radius/common.pl
@@ -0,0 +1,220 @@
+######################################################################
+# Copyright (c) 2011, Network RADIUS SARL
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the <organization> nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+######################################################################
+our %attributes;
+our %vendor;
+our %vendorpec;
+our $begin_vendor = 0;
+
+$vendorpec{'0'} = "IETF";
+
+sub do_file()
+{
+ my $filename = shift;
+ my $fh;
+
+ $dir = $filename;
+ $dir =~ s:/[^/]+?$::;
+ $lineno = 0;
+
+ open $fh, "<$filename" or die "Failed to open $filename: $!\n";
+
+ while (<$fh>) {
+ $lineno++;
+ next if (/^\s*#/);
+ next if (/^\s*$/);
+ s/#.*//;
+ s/\s+$//;
+
+ next if ($_ eq "");
+
+ #
+ # Remember the vendor
+ #
+ if (/^VENDOR\s+([\w-]+)\s+(\w+)(.*)/) {
+ my $me = $1;
+
+ $vendor{$me}{'pec'} = $2;
+ $vendorpec{$2} = $me;
+
+ $vendor{$me}{'type'} = 1;
+ $vendor{$me}{'length'} = 1;
+
+ if ($3) {
+ $format=$3;
+ $format =~ s/^\s+//;
+
+ if ($format !~ /^format=(\d+),(\d+)$/) {
+ die "Unknown format $format\n";
+ }
+ $vendor{$me}{'type'} = $1;
+ $vendor{$me}{'length'} = $2;
+ }
+ next;
+ }
+
+ #
+ # Remember if we did begin-vendor.
+ #
+ if (/^BEGIN-VENDOR\s+([\w-]+)/) {
+ if (!defined $vendor{$1}) {
+ die "Unknown vendor $1\n";
+ }
+ $begin_vendor = $vendor{$1}{'pec'};
+ next;
+ }
+
+ #
+ # Remember if we did this.
+ #
+ if (/^END-VENDOR/) {
+ $begin_vendor = 0;
+ next;
+ }
+
+ #
+ # Get attribute.
+ #
+ if (/^ATTRIBUTE\s+([\w-\/.]+)\s+(\w+)\s+(\w+)(.*)/) {
+ $name=$1;
+ $value = $2;
+ $type = $3;
+ $stuff = $4;
+
+ $value =~ tr/[A-F]/[a-f]/; # normal form for hex
+ $value =~ tr/X/x/;
+
+ if ($value =~ /^0x/) {
+ $index = hex $value;
+ } else {
+ $index = $value;
+ }
+
+ next if (($begin_vendor == 0) && ($index > 255));
+
+ $index += ($begin_vendor << 16);
+
+ $attributes{$index}{'name'} = $name;
+ $attributes{$index}{'value'} = $value;
+ if ($begin_vendor ne "") {
+ $attributes{$index}{'vendor'} = $begin_vendor;
+ }
+
+ $type =~ tr/a-z/A-Z/;
+ $attributes{$index}{'type'} = "RS_TYPE_$type";
+
+ $stuff =~ s/^\s*//;
+
+ if ($stuff) {
+ foreach $text (split /,/, $stuff) {
+ if ($text eq "encrypt=1") {
+ $attributes{$index}{'flags'}{'encrypt'} = "FLAG_ENCRYPT_USER_PASSWORD";
+ } elsif ($text eq "encrypt=2") {
+ $attributes{$index}{'flags'}{'encrypt'} = "FLAG_ENCRYPT_TUNNEL_PASSWORD";
+
+ } elsif ($text eq "encrypt=3") {
+ $attributes{$index}{'flags'}{'encrypt'} = "FLAG_ENCRYPT_ASCEND_SECRET";
+
+ } elsif ($text eq "has_tag") {
+ $attributes{$index}{'flags'}{'has_tag'} = "1";
+
+ } elsif ($text =~ /\[(\d+)\]/) {
+ $attributes{$index}{'flags'}{'length'} = $1;
+
+ } else {
+ die "$filename: $lineno - Unknown flag $text\n";
+ }
+ }
+ }
+
+ if ($type eq "BYTE") {
+ $attributes{$index}{'flags'}{'length'} = "1";
+
+ } elsif ($type eq "SHORT") {
+ $attributes{$index}{'flags'}{'length'} = "2";
+
+ } elsif ($type eq "INTEGER") {
+ $attributes{$index}{'flags'}{'length'} = "4";
+
+ } elsif ($type eq "IPADDR") {
+ $attributes{$index}{'flags'}{'length'} = "4";
+
+ } elsif ($type eq "DATE") {
+ $attributes{$index}{'flags'}{'length'} = "4";
+
+ } elsif ($type eq "IFID") {
+ $attributes{$index}{'flags'}{'length'} = "8";
+
+ } elsif ($type eq "IPV6ADDR") {
+
+ $attributes{$index}{'flags'}{'length'} = "16";
+ }
+
+ $name2val{$name} = $index;
+ next;
+ }
+
+ #
+ # Values.
+ #
+ if (/^VALUE\s+([\d\w-\/.]+)\s+([\w-\/,.+]+)\s+(\w+)(.*)/) {
+ next;
+
+ $attr = $1;
+ $name = $2;
+ $value = $3;
+ $stuff = $d;
+
+ $value =~ tr/[A-F]/[a-f]/; # normal form for hex
+ $value =~ tr/X/x/;
+
+ if ($value =~ /^0x/) {
+ $index = hex $value;
+ } else {
+ $index = $value;
+ }
+
+ if (!defined $name2val{$attr}) {
+ print "# FIXME: FORWARD REF?\nVALUE $attr $name $value$stuff\n";
+ next;
+ }
+
+ $values{$name2val{$attr}}{$index} = "$attr $name $value$stuff";
+ next;
+ }
+
+ if (/^\$INCLUDE\s+(.*)$/) {
+ do_file("$dir/$1");
+ next;
+ }
+
+ die "unknown text in line $lineno of $filename: $_\n";
+ }
+
+ close $fh;
+}
+
+1;
diff --git a/radius/convert.pl b/radius/convert.pl
new file mode 100755
index 0000000..7ca424e
--- /dev/null
+++ b/radius/convert.pl
@@ -0,0 +1,197 @@
+#!/usr/bin/env perl
+######################################################################
+# Copyright (c) 2011, Network RADIUS SARL
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the <organization> nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+######################################################################
+#
+# Converts dictionaries to C structures. Does not yet do "VALUE"s.
+#
+# Usage: ./convert.pl dictionary ...
+#
+# Reads input dictionaries, and outputs "radius.h" and "dictionaries.c"
+#
+# $Id$
+#
+require "common.pl";
+
+#
+# Read all of the dictionaries
+#
+while (@ARGV) {
+ $filename = shift;
+ do_file($filename);
+}
+
+#
+# For speed, the dictionary data structures have the first 256
+# attributes at fixed offsets in the array. If the user didn't
+# define them, then we set them here to be "raw" or unknown.
+#
+foreach $attr_val (0..255) {
+ next if defined $attributes{$attr_val};
+
+ $attributes{$attr_val}{'raw'} = 1;
+}
+
+if (scalar keys %attributes == 0) {
+ die "No attributes were defined\n";
+}
+
+
+open DICT, ">dictionaries.c" or die "Failed creating dictionaries.c: $!\n";
+
+#
+# Print out the data structues for the vendors.
+#
+if (scalar keys %vendor > 0) {
+ print DICT "const DICT_VENDOR nr_dict_vendors[] = {\n";
+ foreach $v (sort keys %vendor) {
+ print DICT " { \n";
+ print DICT " " . $vendor{$v}{'pec'} . ", \n";
+ print DICT " " . $vendor{$v}{'type'} . ",\n";
+ print DICT " " . $vendor{$v}{'length'} . ",\n";
+ print DICT " \"" . $v, "\"\n";
+ print DICT " },\n";
+ }
+ print DICT " { \n";
+ print DICT " 0,\n";
+ print DICT " 0,\n";
+ print DICT " 0,\n";
+ print DICT " NULL\n";
+ print DICT " },\n";
+ print DICT "};\n\n";
+}
+
+# needed for later.
+$vendor{""}{'pec'} = 0;
+
+sub printAttrFlag
+{
+ my $tmp = $attributes{$attr_val}{'flags'}{$_[0]};
+
+ if (!$tmp) {
+ $tmp = 0;
+ }
+
+ print DICT $tmp . ", ";
+}
+
+#
+# Print DICT out the attributes sorted by number.
+#
+my $offset = 0;
+my $num_names = 0;
+print DICT "const DICT_ATTR nr_dict_attrs[] = {\n";
+foreach $attr_val (sort {$a <=> $b} keys %attributes) {
+ print DICT " { /* $offset */ \n";
+
+ if (defined $attributes{$attr_val}{'raw'}) {
+ print DICT " 0\n",
+ } else {
+ print DICT " ", $attributes{$attr_val}{'value'}, ", \n";
+ print DICT " ", $attributes{$attr_val}{'type'}, ", \n";
+ print DICT " ", $attributes{$attr_val}{'vendor'}, ", \n";
+ print DICT " { ";
+ &printAttrFlag('has_tag');
+ &printAttrFlag('unknown');
+# &printAttrFlag('has_tlv');
+# &printAttrFlag('is_tlv');
+ &printAttrFlag('extended');
+ &printAttrFlag('extended_flags');
+ &printAttrFlag('evs');
+ &printAttrFlag('encrypt');
+ &printAttrFlag('length');
+ print DICT "},\n";
+ print DICT " \"", $attributes{$attr_val}{'name'}, "\", \n";
+ $num_names++;
+ }
+
+ $attributes{$attr_val}{'offset'} = $offset++;
+
+ print DICT " },\n";
+
+}
+print DICT "};\n\n";
+
+print DICT "const int nr_dict_num_attrs = ", $offset - 1, ";\n\n";
+print DICT "const int nr_dict_num_names = ", $num_names - 1, ";\n\n";
+
+my $offset = 0;
+print DICT "const DICT_ATTR *nr_dict_attr_names[] = {\n";
+foreach $attr_val (sort {lc($attributes{$a}{'name'}) cmp lc($attributes{$b}{'name'})} keys %attributes) {
+ next if (defined $attributes{$attr_val}{'raw'});
+
+ print DICT " &nr_dict_attrs[", $attributes{$attr_val}{'offset'}, "], /* ", $attributes{$attr_val}{'name'}, " */\n";
+}
+
+print DICT "};\n\n";
+close DICT;
+
+open HDR, ">../include/radsec/radius.h" or die "Failed creating radius.c: $!\n";
+
+print HDR "/* Automatically generated file. Do not edit */\n\n";
+
+foreach $v (sort keys %vendor) {
+ next if ($v eq "");
+
+ $name = $v;
+ $name =~ tr/a-z/A-Z/; # uppercase
+ $name =~ tr/A-Z0-9/_/c; # any ELSE becomes _
+
+ print HDR "#define VENDORPEC_", $name, " ", $vendor{$v}{'pec'}, "\n";
+}
+print HDR "\n";
+
+$begin_vendor = -1;
+foreach $attr_val (sort {$a <=> $b} keys %attributes) {
+ next if (defined $attributes{$attr_val}{'raw'});
+
+ if ($attributes{$attr_val}{'vendor'} != $begin_vendor) {
+ print HDR "\n/* ", $vendorpec{$attributes{$attr_val}{'vendor'}}, " */\n";
+ $begin_vendor = $attributes{$attr_val}{'vendor'};
+ }
+
+ $name = $attributes{$attr_val}{'name'};
+ $name =~ tr/a-z/A-Z/;
+ $name =~ tr/A-Z0-9/_/c;
+
+ print HDR "#define PW_", $name, " ", $attributes{$attr_val}{'value'}, "\n";
+}
+print HDR "\n";
+
+print HDR "/* Fixed offsets to dictionary definitions of attributes */\n";
+foreach $attr_val (sort {$a <=> $b} keys %attributes) {
+ next if (defined $attributes{$attr_val}{'raw'});
+
+ $name = $attributes{$attr_val}{'name'};
+ $name =~ tr/a-z/A-Z/;
+ $name =~ tr/-/_/;
+
+ print HDR "#define RS_DA_$name (&nr_dict_attrs[$attributes{$attr_val}{'offset'}])\n";
+}
+
+print HDR "/* Automatically generated file. Do not edit */\n";
+
+close HDR;
diff --git a/radius/crypto.c b/radius/crypto.c
new file mode 100644
index 0000000..21cc7d0
--- /dev/null
+++ b/radius/crypto.c
@@ -0,0 +1,233 @@
+/*
+Copyright (c) 2011, Network RADIUS SARL
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file crypto.c
+ * \brief Data obfuscation and signing, using MD5.
+ *
+ * The "encryption" methods defined here are export-safe. The
+ * technical cryptography name for these functions is "obfuscation".
+ * They cannot properly be called "encryption", in the same way that
+ * DES or AES performs encryption.
+ */
+
+/** \cond PRIVATE */
+
+#include "client.h"
+
+
+ssize_t nr_password_encrypt(uint8_t *output, size_t outlen,
+ const uint8_t *input, size_t inlen,
+ const char *secret, const uint8_t *vector)
+{
+ size_t i, j, len;
+ uint8_t digest[16];
+ RS_MD5_CTX ctx, secret_ctx;
+
+ if (!output || (outlen < 16) || !input || (inlen == 0) ||
+ !secret || !vector) {
+ return -RSE_INVAL;
+ }
+
+ len = inlen;
+ if (len > 128) return -RSE_ATTR_OVERFLOW;
+
+ len = (len + 0x0f) & ~0x0f; /* round up to 16 byte boundary */
+
+ if (outlen < len) return -RSE_ATTR_OVERFLOW;
+
+ memcpy(output, input, len);
+ memset(output + len, 0, 128 - len);
+
+ RS_MD5Init(&secret_ctx);
+ RS_MD5Update(&secret_ctx, (const uint8_t *) secret, strlen(secret));
+
+ for (j = 0; j < len; j += 16) {
+ ctx = secret_ctx;
+
+ if (j == 0) {
+ RS_MD5Update(&ctx, vector, 16);
+ RS_MD5Final(digest, &ctx);
+ } else {
+ RS_MD5Update(&ctx, &output[j - 16], 16);
+ RS_MD5Final(digest, &ctx);
+ }
+
+ for (i = 0; i < 16; i++) {
+ output[i + j] ^= digest[i];
+ }
+ }
+
+ return len;
+}
+
+#ifdef FLAG_ENCRYPT_TUNNEL_PASSWORD
+ssize_t nr_tunnelpw_encrypt(uint8_t *output, size_t outlen,
+ const uint8_t *input, size_t inlen,
+ const char *secret, const uint8_t *vector)
+{
+ size_t i, j, len;
+ RS_MD5_CTX ctx, secret_ctx;
+ uint8_t digest[16];
+
+ if (!output || (outlen < 18) || !input || (inlen == 0) ||
+ !secret || !vector) {
+ return -RSE_INVAL;
+ }
+
+ len = ((inlen + 1) + 0x0f) & ~0x0f;
+ if (len > 251) return -RSE_ATTR_OVERFLOW;
+
+ output[0] = (nr_rand() & 0xff) | 0x80;
+ output[1] = nr_rand() & 0xff;
+ output[2] = inlen;
+
+ memcpy(output + 3, input, inlen);
+ memset(output + 3 + inlen, 0, len - inlen - 1);
+
+ RS_MD5Init(&secret_ctx);
+ RS_MD5Update(&secret_ctx, (const uint8_t *) secret, strlen(secret));
+
+ for (j = 0; j < len; j += 16) {
+ ctx = secret_ctx;
+
+ if (j == 0) {
+ RS_MD5Update(&ctx, vector, 16);
+ RS_MD5Update(&ctx, output, 2);
+ RS_MD5Final(digest, &ctx);
+ } else {
+ RS_MD5Update(&ctx, &output[j + 2 - 16], 16);
+ RS_MD5Final(digest, &ctx);
+ }
+
+ for (i = 0; i < 16; i++) {
+ output[i + j + 2] ^= digest[i];
+ }
+ }
+
+ return len + 2;
+}
+
+ssize_t nr_tunnelpw_decrypt(uint8_t *output, size_t outlen,
+ const uint8_t *input, size_t inlen,
+ const char *secret, const uint8_t *vector)
+{
+ size_t i, j, len, encoded_len;
+ RS_MD5_CTX ctx, secret_ctx;
+ uint8_t digest[16];
+
+ if (!output || (outlen < 1) || !input || (inlen < 2) ||
+ !secret || !vector) {
+ return -RSE_INVAL;
+ }
+
+ if (inlen <= 3) {
+ output[0] = 0;
+ return 0;
+ }
+
+ len = inlen - 2;
+
+ if (outlen < (len - 1)) return -RSE_ATTR_OVERFLOW;
+
+ RS_MD5Init(&secret_ctx);
+ RS_MD5Update(&secret_ctx, (const uint8_t *) secret, strlen(secret));
+
+ ctx = secret_ctx;
+
+ RS_MD5Update(&ctx, vector, 16); /* MD5(secret + vector + salt) */
+ RS_MD5Update(&ctx, input, 2);
+ RS_MD5Final(digest, &ctx);
+
+ encoded_len = input[2] ^ digest[0];
+ if (encoded_len >= len) {
+ return -RSE_ATTR_TOO_LARGE;
+ }
+
+ for (i = 0; i < 15; i++) {
+ output[i] = input[i + 3] ^ digest[i + 1];
+ }
+
+ for (j = 16; j < len; j += 16) {
+ ctx = secret_ctx;
+
+ RS_MD5Update(&ctx, input + j - 16 + 2, 16);
+ RS_MD5Final(digest, &ctx);
+
+ for (i = 0; i < 16; i++) {
+ output[i + j - 1] = input[i + j + 2] ^ digest[i];
+ }
+
+
+ }
+
+ output[encoded_len] = '\0';
+ return encoded_len;
+}
+#endif
+
+void
+nr_hmac_md5(const uint8_t *data, size_t data_len,
+ const uint8_t *key, size_t key_len,
+ uint8_t digest[16])
+{
+ size_t i;
+ uint8_t k_ipad[64];
+ uint8_t k_opad[64];
+ uint8_t tk[16];
+ RS_MD5_CTX ctx;
+
+ if (key_len > 64) {
+ RS_MD5Init(&ctx);
+ RS_MD5Update(&ctx, key, key_len);
+ RS_MD5Final(tk, &ctx);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ memset(k_ipad, 0, sizeof(k_ipad));
+ memset(k_opad, 0, sizeof(k_opad));
+ memcpy(k_ipad, key, key_len);
+ memcpy(k_opad, key, key_len);
+
+ for (i = 0; i < sizeof(k_ipad); i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ RS_MD5Init(&ctx);
+ RS_MD5Update(&ctx, k_ipad, sizeof(k_ipad));
+ RS_MD5Update(&ctx, data, data_len);
+ RS_MD5Final(digest, &ctx);
+
+ RS_MD5Init(&ctx);
+ RS_MD5Update(&ctx, k_opad, sizeof(k_opad));
+ RS_MD5Update(&ctx, digest, 16);
+ RS_MD5Final(digest, &ctx);
+}
+
+/** \endcond */
diff --git a/radius/custom.c b/radius/custom.c
new file mode 100644
index 0000000..917939a
--- /dev/null
+++ b/radius/custom.c
@@ -0,0 +1,163 @@
+/*
+Copyright (c) 2011, Network RADIUS SARL
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2006 Kungliga Tekniska HAÎåÎÝgskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/** \file custom.c
+ * \brief Functions which should be customized for your local system.
+ */
+
+#include "client.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef WIN32
+#include <wincrypt.h>
+
+volatile static HCRYPTPROV nr_cryptprovider = 0;
+
+static HCRYPTPROV
+nr_CryptProvider(void)
+{
+ BOOL rv;
+ HCRYPTPROV cryptprovider = 0;
+
+ if (nr_cryptprovider != 0)
+ return nr_cryptprovider;
+
+ rv = CryptAcquireContext(&cryptprovider, NULL,
+ MS_ENHANCED_PROV, PROV_RSA_FULL,
+ 0);
+
+ if (GetLastError() == NTE_BAD_KEYSET) {
+ if(!rv)
+ rv = CryptAcquireContext(&cryptprovider, NULL,
+ MS_ENHANCED_PROV, PROV_RSA_FULL,
+ CRYPT_NEWKEYSET);
+ }
+
+ if (rv &&
+ InterlockedCompareExchangePointer((PVOID *) &nr_cryptprovider,
+ (PVOID) cryptprovider, 0) != 0) {
+
+ CryptReleaseContext(cryptprovider, 0);
+ cryptprovider = nr_cryptprovider;
+ }
+
+ return cryptprovider;
+}
+
+ssize_t nr_rand_bytes(uint8_t *data, size_t data_len)
+{
+ if (CryptGenRandom(nr_CryptProvider(), data_len, data))
+ return 0;
+ return data_len;
+}
+#else
+ssize_t nr_rand_bytes(uint8_t *data, size_t data_len)
+{
+ static int fd = -1;
+
+ if (fd < 0) {
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0) {
+ nr_strerror_printf("Error opening randomness: %s",
+ strerror(errno));
+ return 0;
+ }
+ }
+
+ return read(fd, data, data_len);
+}
+#endif /* WIN32 */
+
+uint32_t nr_rand(void)
+{
+ uint32_t lvalue;
+
+ nr_rand_bytes((void *)&lvalue, sizeof(lvalue));
+ return lvalue;
+}
+
+
+#ifndef USEC
+#define USEC (1000000)
+#endif
+
+void nr_timeval_add(struct timeval *t, unsigned int seconds, unsigned int usec)
+{
+ t->tv_sec += seconds;
+ t->tv_sec += usec / USEC;
+ t->tv_usec += usec % USEC;
+ if (t->tv_usec > USEC) {
+ t->tv_sec++;
+ t->tv_usec -= USEC;
+ }
+}
+
+int nr_timeval_cmp(const struct timeval *a, const struct timeval *b)
+{
+ if (a->tv_sec > b->tv_sec) return +1;
+ if (a->tv_sec < b->tv_sec) return -1;
+
+ if (a->tv_usec > b->tv_usec) return +1;
+ if (a->tv_usec < b->tv_usec) return -1;
+
+ return 0;
+}
+
diff --git a/radius/dict.c b/radius/dict.c
new file mode 100644
index 0000000..fc04ee2
--- /dev/null
+++ b/radius/dict.c
@@ -0,0 +1,172 @@
+/*
+Copyright (c) 2011, Network RADIUS SARL
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "client.h"
+#include <ctype.h>
+
+/** \file dict.c
+ * \brief Functions for name to number, and number to name mappings.
+ */
+
+const DICT_ATTR *nr_dict_attr_byvalue(unsigned int attr, unsigned int vendor)
+{
+ int start, half, end;
+
+ if (!vendor && (attr > 0) && (attr < 256)) {
+ if (nr_dict_attrs[attr].name) {
+ return &nr_dict_attrs[attr];
+ }
+ return NULL;
+ }
+
+ if (!vendor) return NULL; /* no "non-protocol" attributes */
+
+ start = 256; /* first 256 entries are "standard" ones */
+ end = nr_dict_num_attrs;
+
+ do {
+ half = (start + end) / 2;
+
+ if ((nr_dict_attrs[half].vendor == vendor) &&
+ (nr_dict_attrs[half].attr == attr)) {
+ return &nr_dict_attrs[half];
+ }
+
+ if ((vendor >= nr_dict_attrs[half].vendor) &&
+ (attr > nr_dict_attrs[half].attr)) {
+ start = half + 1;
+ } else {
+ end = half - 1;
+ }
+
+ } while (start <= end);
+
+ return NULL;
+}
+
+const DICT_ATTR *nr_dict_attr_byname(const char *name)
+{
+ int start, half, end;
+
+ start = 1;
+ end = nr_dict_num_names;
+
+ if (!name || !*name) return NULL;
+
+ do {
+ int rcode;
+
+ half = (start + end) / 2;
+
+ rcode = strcasecmp(name, nr_dict_attr_names[half]->name);
+ if (rcode == 0) return nr_dict_attr_names[half];
+
+ if (rcode > 0) {
+ start = half + 1;
+ } else {
+ end = half - 1;
+ }
+
+
+ } while (start <= end);
+
+ return NULL;
+}
+
+int nr_dict_attr_2struct(DICT_ATTR *da, unsigned int attr, unsigned int vendor,
+ char *buffer, size_t bufsize)
+{
+ if (!da || !buffer) return -RSE_INVAL;
+
+ if (!vendor) {
+ if (attr > 256) return -RSE_INVAL;
+
+ } else if (vendor > (1 << 24)) {
+ return -RSE_INVAL;
+ }
+
+ memset(da, 0, sizeof(*da));
+ da->attr = attr;
+ da->flags.unknown = 1;
+ da->type = RS_TYPE_OCTETS;
+ da->vendor = vendor;
+
+ if (da->vendor) {
+ snprintf(buffer, bufsize, "Attr-26.%u.%u",
+ vendor, attr);
+ } else {
+ snprintf(buffer, bufsize, "Attr-%u", attr);
+ }
+ da->name = buffer;
+
+ return 0;
+}
+
+
+const DICT_VALUE *nr_dict_value_byattr(UNUSED unsigned int attr,
+ UNUSED unsigned int vendor,
+ UNUSED int value)
+{
+ return NULL;
+}
+
+const DICT_VALUE *nr_dict_value_byname(UNUSED unsigned int attr,
+ UNUSED unsigned int vendor,
+ UNUSED const char *name)
+{
+ return NULL;
+}
+
+int nr_dict_vendor_byname(const char *name)
+{
+ const DICT_VENDOR *dv;
+
+ if (!name || !*name) return 0;
+
+ /*
+ * O(n) lookup.
+ */
+ for (dv = &nr_dict_vendors[0]; dv->name != NULL; dv++) {
+ if (strcasecmp(dv->name, name) == 0) return dv->vendor;
+ }
+
+ return 0;
+}
+
+const DICT_VENDOR *nr_dict_vendor_byvalue(unsigned int vendor)
+{
+ const DICT_VENDOR *dv;
+
+ /*
+ * O(n) lookup.
+ */
+ for (dv = &nr_dict_vendors[0]; dv->name != NULL; dv++) {
+ if (dv->vendor == vendor) return dv;
+ }
+
+ return NULL;
+}
diff --git a/radius/dictionaries.c b/radius/dictionaries.c
new file mode 100644
index 0000000..5c60fc8
--- /dev/null
+++ b/radius/dictionaries.c
@@ -0,0 +1,1713 @@
+const DICT_VENDOR nr_dict_vendors[] = {
+ {
+ 2636,
+ 1,
+ 1,
+ "Juniper"
+ },
+ {
+ 311,
+ 1,
+ 1,
+ "Microsoft"
+ },
+ {
+ 25622,
+ 1,
+ 1,
+ "UKERNA"
+ },
+ {
+ 0,
+ 0,
+ 0,
+ NULL
+ },
+};
+
+const DICT_ATTR nr_dict_attrs[] = {
+ { /* 0 */
+ 0
+ },
+ { /* 1 */
+ 1,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "User-Name",
+ },
+ { /* 2 */
+ 2,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, FLAG_ENCRYPT_USER_PASSWORD, 0, },
+ "User-Password",
+ },
+ { /* 3 */
+ 3,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "CHAP-Password",
+ },
+ { /* 4 */
+ 4,
+ RS_TYPE_IPADDR,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "NAS-IP-Address",
+ },
+ { /* 5 */
+ 5,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "NAS-Port",
+ },
+ { /* 6 */
+ 6,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Service-Type",
+ },
+ { /* 7 */
+ 7,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Framed-Protocol",
+ },
+ { /* 8 */
+ 8,
+ RS_TYPE_IPADDR,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Framed-IP-Address",
+ },
+ { /* 9 */
+ 9,
+ RS_TYPE_IPADDR,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Framed-IP-Netmask",
+ },
+ { /* 10 */
+ 10,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Framed-Routing",
+ },
+ { /* 11 */
+ 11,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Filter-Id",
+ },
+ { /* 12 */
+ 12,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Framed-MTU",
+ },
+ { /* 13 */
+ 13,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Framed-Compression",
+ },
+ { /* 14 */
+ 14,
+ RS_TYPE_IPADDR,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Login-IP-Host",
+ },
+ { /* 15 */
+ 15,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Login-Service",
+ },
+ { /* 16 */
+ 16,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Login-TCP-Port",
+ },
+ { /* 17 */
+ 0
+ },
+ { /* 18 */
+ 18,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Reply-Message",
+ },
+ { /* 19 */
+ 19,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Callback-Number",
+ },
+ { /* 20 */
+ 20,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Callback-Id",
+ },
+ { /* 21 */
+ 0
+ },
+ { /* 22 */
+ 22,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Framed-Route",
+ },
+ { /* 23 */
+ 23,
+ RS_TYPE_IPADDR,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Framed-IPX-Network",
+ },
+ { /* 24 */
+ 24,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "State",
+ },
+ { /* 25 */
+ 25,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Class",
+ },
+ { /* 26 */
+ 26,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Vendor-Specific",
+ },
+ { /* 27 */
+ 27,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Session-Timeout",
+ },
+ { /* 28 */
+ 28,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Idle-Timeout",
+ },
+ { /* 29 */
+ 29,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Termination-Action",
+ },
+ { /* 30 */
+ 30,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Called-Station-Id",
+ },
+ { /* 31 */
+ 31,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Calling-Station-Id",
+ },
+ { /* 32 */
+ 32,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "NAS-Identifier",
+ },
+ { /* 33 */
+ 33,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Proxy-State",
+ },
+ { /* 34 */
+ 34,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Login-LAT-Service",
+ },
+ { /* 35 */
+ 35,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Login-LAT-Node",
+ },
+ { /* 36 */
+ 36,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Login-LAT-Group",
+ },
+ { /* 37 */
+ 37,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Framed-AppleTalk-Link",
+ },
+ { /* 38 */
+ 38,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Framed-AppleTalk-Network",
+ },
+ { /* 39 */
+ 39,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Framed-AppleTalk-Zone",
+ },
+ { /* 40 */
+ 40,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Acct-Status-Type",
+ },
+ { /* 41 */
+ 41,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Acct-Delay-Time",
+ },
+ { /* 42 */
+ 42,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Acct-Input-Octets",
+ },
+ { /* 43 */
+ 43,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Acct-Output-Octets",
+ },
+ { /* 44 */
+ 44,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Acct-Session-Id",
+ },
+ { /* 45 */
+ 45,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Acct-Authentic",
+ },
+ { /* 46 */
+ 46,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Acct-Session-Time",
+ },
+ { /* 47 */
+ 47,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Acct-Input-Packets",
+ },
+ { /* 48 */
+ 48,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Acct-Output-Packets",
+ },
+ { /* 49 */
+ 49,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Acct-Terminate-Cause",
+ },
+ { /* 50 */
+ 50,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Acct-Multi-Session-Id",
+ },
+ { /* 51 */
+ 51,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Acct-Link-Count",
+ },
+ { /* 52 */
+ 52,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Acct-Input-Gigawords",
+ },
+ { /* 53 */
+ 53,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Acct-Output-Gigawords",
+ },
+ { /* 54 */
+ 0
+ },
+ { /* 55 */
+ 55,
+ RS_TYPE_DATE,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Event-Timestamp",
+ },
+ { /* 56 */
+ 56,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Egress-VLANID",
+ },
+ { /* 57 */
+ 57,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Ingress-Filters",
+ },
+ { /* 58 */
+ 58,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Egress-VLAN-Name",
+ },
+ { /* 59 */
+ 59,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "User-Priority-Table",
+ },
+ { /* 60 */
+ 60,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "CHAP-Challenge",
+ },
+ { /* 61 */
+ 61,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "NAS-Port-Type",
+ },
+ { /* 62 */
+ 62,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Port-Limit",
+ },
+ { /* 63 */
+ 63,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Login-LAT-Port",
+ },
+ { /* 64 */
+ 64,
+ RS_TYPE_INTEGER,
+ 0,
+ { 1, 0, 0, 0, 0, 0, 4, },
+ "Tunnel-Type",
+ },
+ { /* 65 */
+ 65,
+ RS_TYPE_INTEGER,
+ 0,
+ { 1, 0, 0, 0, 0, 0, 4, },
+ "Tunnel-Medium-Type",
+ },
+ { /* 66 */
+ 66,
+ RS_TYPE_STRING,
+ 0,
+ { 1, 0, 0, 0, 0, 0, 0, },
+ "Tunnel-Client-Endpoint",
+ },
+ { /* 67 */
+ 67,
+ RS_TYPE_STRING,
+ 0,
+ { 1, 0, 0, 0, 0, 0, 0, },
+ "Tunnel-Server-Endpoint",
+ },
+ { /* 68 */
+ 68,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Acct-Tunnel-Connection",
+ },
+ { /* 69 */
+ 69,
+ RS_TYPE_STRING,
+ 0,
+ { 1, 0, 0, 0, 0, FLAG_ENCRYPT_TUNNEL_PASSWORD, 0, },
+ "Tunnel-Password",
+ },
+ { /* 70 */
+ 70,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 16, },
+ "ARAP-Password",
+ },
+ { /* 71 */
+ 71,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 14, },
+ "ARAP-Features",
+ },
+ { /* 72 */
+ 72,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "ARAP-Zone-Access",
+ },
+ { /* 73 */
+ 73,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "ARAP-Security",
+ },
+ { /* 74 */
+ 74,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "ARAP-Security-Data",
+ },
+ { /* 75 */
+ 75,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Password-Retry",
+ },
+ { /* 76 */
+ 76,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Prompt",
+ },
+ { /* 77 */
+ 77,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Connect-Info",
+ },
+ { /* 78 */
+ 78,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Configuration-Token",
+ },
+ { /* 79 */
+ 79,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "EAP-Message",
+ },
+ { /* 80 */
+ 80,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Message-Authenticator",
+ },
+ { /* 81 */
+ 81,
+ RS_TYPE_STRING,
+ 0,
+ { 1, 0, 0, 0, 0, 0, 0, },
+ "Tunnel-Private-Group-Id",
+ },
+ { /* 82 */
+ 82,
+ RS_TYPE_STRING,
+ 0,
+ { 1, 0, 0, 0, 0, 0, 0, },
+ "Tunnel-Assignment-Id",
+ },
+ { /* 83 */
+ 83,
+ RS_TYPE_INTEGER,
+ 0,
+ { 1, 0, 0, 0, 0, 0, 4, },
+ "Tunnel-Preference",
+ },
+ { /* 84 */
+ 84,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 8, },
+ "ARAP-Challenge-Response",
+ },
+ { /* 85 */
+ 85,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Acct-Interim-Interval",
+ },
+ { /* 86 */
+ 86,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Acct-Tunnel-Packets-Lost",
+ },
+ { /* 87 */
+ 87,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "NAS-Port-Id",
+ },
+ { /* 88 */
+ 88,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Framed-Pool",
+ },
+ { /* 89 */
+ 89,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Chargeable-User-Identity",
+ },
+ { /* 90 */
+ 90,
+ RS_TYPE_STRING,
+ 0,
+ { 1, 0, 0, 0, 0, 0, 0, },
+ "Tunnel-Client-Auth-Id",
+ },
+ { /* 91 */
+ 91,
+ RS_TYPE_STRING,
+ 0,
+ { 1, 0, 0, 0, 0, 0, 0, },
+ "Tunnel-Server-Auth-Id",
+ },
+ { /* 92 */
+ 92,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "NAS-Filter-Rule",
+ },
+ { /* 93 */
+ 0
+ },
+ { /* 94 */
+ 0
+ },
+ { /* 95 */
+ 95,
+ RS_TYPE_IPV6ADDR,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 16, },
+ "NAS-IPv6-Address",
+ },
+ { /* 96 */
+ 96,
+ RS_TYPE_IFID,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 8, },
+ "Framed-Interface-Id",
+ },
+ { /* 97 */
+ 97,
+ RS_TYPE_IPV6PREFIX,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Framed-IPv6-Prefix",
+ },
+ { /* 98 */
+ 98,
+ RS_TYPE_IPV6ADDR,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 16, },
+ "Login-IPv6-Host",
+ },
+ { /* 99 */
+ 99,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Framed-IPv6-Route",
+ },
+ { /* 100 */
+ 100,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Framed-IPv6-Pool",
+ },
+ { /* 101 */
+ 101,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Error-Cause",
+ },
+ { /* 102 */
+ 102,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "EAP-Key-Name",
+ },
+ { /* 103 */
+ 103,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-Response",
+ },
+ { /* 104 */
+ 104,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-Realm",
+ },
+ { /* 105 */
+ 105,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-Nonce",
+ },
+ { /* 106 */
+ 106,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-Response-Auth",
+ },
+ { /* 107 */
+ 107,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-Nextnonce",
+ },
+ { /* 108 */
+ 108,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-Method",
+ },
+ { /* 109 */
+ 109,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-URI",
+ },
+ { /* 110 */
+ 110,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-Qop",
+ },
+ { /* 111 */
+ 111,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-Algorithm",
+ },
+ { /* 112 */
+ 112,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-Entity-Body-Hash",
+ },
+ { /* 113 */
+ 113,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-CNonce",
+ },
+ { /* 114 */
+ 114,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-Nonce-Count",
+ },
+ { /* 115 */
+ 115,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-Username",
+ },
+ { /* 116 */
+ 116,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-Opaque",
+ },
+ { /* 117 */
+ 117,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-Auth-Param",
+ },
+ { /* 118 */
+ 118,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-AKA-Auts",
+ },
+ { /* 119 */
+ 119,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-Domain",
+ },
+ { /* 120 */
+ 120,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-Stale",
+ },
+ { /* 121 */
+ 121,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Digest-HA1",
+ },
+ { /* 122 */
+ 122,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "SIP-AOR",
+ },
+ { /* 123 */
+ 123,
+ RS_TYPE_IPV6PREFIX,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Delegated-IPv6-Prefix",
+ },
+ { /* 124 */
+ 0
+ },
+ { /* 125 */
+ 0
+ },
+ { /* 126 */
+ 126,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Operator-Name",
+ },
+ { /* 127 */
+ 127,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Location-Information",
+ },
+ { /* 128 */
+ 128,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Location-Data",
+ },
+ { /* 129 */
+ 129,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Basic-Location-Policy-Rules",
+ },
+ { /* 130 */
+ 130,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Extended-Location-Policy-Rules",
+ },
+ { /* 131 */
+ 131,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Location-Capable",
+ },
+ { /* 132 */
+ 132,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Requested-Location-Info",
+ },
+ { /* 133 */
+ 133,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Framed-Management",
+ },
+ { /* 134 */
+ 134,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Management-Transport-Protection",
+ },
+ { /* 135 */
+ 135,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Management-Policy-Id",
+ },
+ { /* 136 */
+ 136,
+ RS_TYPE_INTEGER,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 4, },
+ "Management-Privilege-Level",
+ },
+ { /* 137 */
+ 137,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "PKM-SS-Cert",
+ },
+ { /* 138 */
+ 138,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "PKM-CA-Cert",
+ },
+ { /* 139 */
+ 139,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "PKM-Config-Settings",
+ },
+ { /* 140 */
+ 140,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "PKM-Cryptosuite-List",
+ },
+ { /* 141 */
+ 141,
+ RS_TYPE_SHORT,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 2, },
+ "PKM-SAID",
+ },
+ { /* 142 */
+ 142,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "PKM-SA-Descriptor",
+ },
+ { /* 143 */
+ 143,
+ RS_TYPE_OCTETS,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "PKM-Auth-Key",
+ },
+ { /* 144 */
+ 0
+ },
+ { /* 145 */
+ 0
+ },
+ { /* 146 */
+ 0
+ },
+ { /* 147 */
+ 0
+ },
+ { /* 148 */
+ 0
+ },
+ { /* 149 */
+ 0
+ },
+ { /* 150 */
+ 0
+ },
+ { /* 151 */
+ 0
+ },
+ { /* 152 */
+ 0
+ },
+ { /* 153 */
+ 0
+ },
+ { /* 154 */
+ 0
+ },
+ { /* 155 */
+ 0
+ },
+ { /* 156 */
+ 0
+ },
+ { /* 157 */
+ 0
+ },
+ { /* 158 */
+ 0
+ },
+ { /* 159 */
+ 0
+ },
+ { /* 160 */
+ 0
+ },
+ { /* 161 */
+ 0
+ },
+ { /* 162 */
+ 0
+ },
+ { /* 163 */
+ 0
+ },
+ { /* 164 */
+ 164,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "GSS-Acceptor-Service-Name",
+ },
+ { /* 165 */
+ 165,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "GSS-Acceptor-Host-Name",
+ },
+ { /* 166 */
+ 166,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "GSS-Acceptor-Service-Specifics",
+ },
+ { /* 167 */
+ 167,
+ RS_TYPE_STRING,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "GSS-Acceptor-Realm-Name",
+ },
+ { /* 168 */
+ 0
+ },
+ { /* 169 */
+ 0
+ },
+ { /* 170 */
+ 0
+ },
+ { /* 171 */
+ 0
+ },
+ { /* 172 */
+ 0
+ },
+ { /* 173 */
+ 0
+ },
+ { /* 174 */
+ 0
+ },
+ { /* 175 */
+ 0
+ },
+ { /* 176 */
+ 0
+ },
+ { /* 177 */
+ 0
+ },
+ { /* 178 */
+ 0
+ },
+ { /* 179 */
+ 0
+ },
+ { /* 180 */
+ 0
+ },
+ { /* 181 */
+ 0
+ },
+ { /* 182 */
+ 0
+ },
+ { /* 183 */
+ 0
+ },
+ { /* 184 */
+ 0
+ },
+ { /* 185 */
+ 0
+ },
+ { /* 186 */
+ 0
+ },
+ { /* 187 */
+ 0
+ },
+ { /* 188 */
+ 0
+ },
+ { /* 189 */
+ 0
+ },
+ { /* 190 */
+ 0
+ },
+ { /* 191 */
+ 0
+ },
+ { /* 192 */
+ 0
+ },
+ { /* 193 */
+ 0
+ },
+ { /* 194 */
+ 0
+ },
+ { /* 195 */
+ 0
+ },
+ { /* 196 */
+ 0
+ },
+ { /* 197 */
+ 0
+ },
+ { /* 198 */
+ 0
+ },
+ { /* 199 */
+ 0
+ },
+ { /* 200 */
+ 0
+ },
+ { /* 201 */
+ 0
+ },
+ { /* 202 */
+ 0
+ },
+ { /* 203 */
+ 0
+ },
+ { /* 204 */
+ 0
+ },
+ { /* 205 */
+ 0
+ },
+ { /* 206 */
+ 0
+ },
+ { /* 207 */
+ 0
+ },
+ { /* 208 */
+ 0
+ },
+ { /* 209 */
+ 0
+ },
+ { /* 210 */
+ 0
+ },
+ { /* 211 */
+ 0
+ },
+ { /* 212 */
+ 0
+ },
+ { /* 213 */
+ 0
+ },
+ { /* 214 */
+ 0
+ },
+ { /* 215 */
+ 0
+ },
+ { /* 216 */
+ 0
+ },
+ { /* 217 */
+ 0
+ },
+ { /* 218 */
+ 0
+ },
+ { /* 219 */
+ 0
+ },
+ { /* 220 */
+ 0
+ },
+ { /* 221 */
+ 0
+ },
+ { /* 222 */
+ 0
+ },
+ { /* 223 */
+ 0
+ },
+ { /* 224 */
+ 0
+ },
+ { /* 225 */
+ 0
+ },
+ { /* 226 */
+ 0
+ },
+ { /* 227 */
+ 0
+ },
+ { /* 228 */
+ 0
+ },
+ { /* 229 */
+ 0
+ },
+ { /* 230 */
+ 0
+ },
+ { /* 231 */
+ 0
+ },
+ { /* 232 */
+ 0
+ },
+ { /* 233 */
+ 0
+ },
+ { /* 234 */
+ 0
+ },
+ { /* 235 */
+ 0
+ },
+ { /* 236 */
+ 0
+ },
+ { /* 237 */
+ 0
+ },
+ { /* 238 */
+ 0
+ },
+ { /* 239 */
+ 0
+ },
+ { /* 240 */
+ 0
+ },
+ { /* 241 */
+ 0
+ },
+ { /* 242 */
+ 0
+ },
+ { /* 243 */
+ 0
+ },
+ { /* 244 */
+ 0
+ },
+ { /* 245 */
+ 0
+ },
+ { /* 246 */
+ 0
+ },
+ { /* 247 */
+ 0
+ },
+ { /* 248 */
+ 0
+ },
+ { /* 249 */
+ 0
+ },
+ { /* 250 */
+ 0
+ },
+ { /* 251 */
+ 0
+ },
+ { /* 252 */
+ 0
+ },
+ { /* 253 */
+ 0
+ },
+ { /* 254 */
+ 0
+ },
+ { /* 255 */
+ 0
+ },
+ { /* 256 */
+ 1,
+ RS_TYPE_OCTETS,
+ 311,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "MS-CHAP-Response",
+ },
+ { /* 257 */
+ 2,
+ RS_TYPE_STRING,
+ 311,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "MS-CHAP-Error",
+ },
+ { /* 258 */
+ 7,
+ RS_TYPE_OCTETS,
+ 311,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "MS-MPPE-Encryption-Policy",
+ },
+ { /* 259 */
+ 8,
+ RS_TYPE_OCTETS,
+ 311,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "MS-MPPE-Encryption-Types",
+ },
+ { /* 260 */
+ 10,
+ RS_TYPE_STRING,
+ 311,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "MS-CHAP-Domain",
+ },
+ { /* 261 */
+ 11,
+ RS_TYPE_OCTETS,
+ 311,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "MS-CHAP-Challenge",
+ },
+ { /* 262 */
+ 12,
+ RS_TYPE_OCTETS,
+ 311,
+ { 0, 0, 0, 0, 0, FLAG_ENCRYPT_USER_PASSWORD, 0, },
+ "MS-CHAP-MPPE-Keys",
+ },
+ { /* 263 */
+ 16,
+ RS_TYPE_OCTETS,
+ 311,
+ { 0, 0, 0, 0, 0, FLAG_ENCRYPT_TUNNEL_PASSWORD, 0, },
+ "MS-MPPE-Send-Key",
+ },
+ { /* 264 */
+ 17,
+ RS_TYPE_OCTETS,
+ 311,
+ { 0, 0, 0, 0, 0, FLAG_ENCRYPT_TUNNEL_PASSWORD, 0, },
+ "MS-MPPE-Recv-Key",
+ },
+ { /* 265 */
+ 25,
+ RS_TYPE_OCTETS,
+ 311,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "MS-CHAP2-Response",
+ },
+ { /* 266 */
+ 26,
+ RS_TYPE_OCTETS,
+ 311,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "MS-CHAP2-Success",
+ },
+ { /* 267 */
+ 1,
+ RS_TYPE_STRING,
+ 2636,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Juniper-Local-User-Name",
+ },
+ { /* 268 */
+ 2,
+ RS_TYPE_STRING,
+ 2636,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Juniper-Allow-Commands",
+ },
+ { /* 269 */
+ 3,
+ RS_TYPE_STRING,
+ 2636,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Juniper-Deny-Commands",
+ },
+ { /* 270 */
+ 4,
+ RS_TYPE_STRING,
+ 2636,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Juniper-Allow-Configuration",
+ },
+ { /* 271 */
+ 5,
+ RS_TYPE_STRING,
+ 2636,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Juniper-Deny-Configuration",
+ },
+ { /* 272 */
+ 8,
+ RS_TYPE_STRING,
+ 2636,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Juniper-Interactive-Command",
+ },
+ { /* 273 */
+ 9,
+ RS_TYPE_STRING,
+ 2636,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Juniper-Configuration-Change",
+ },
+ { /* 274 */
+ 10,
+ RS_TYPE_STRING,
+ 2636,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "Juniper-User-Permissions",
+ },
+ { /* 275 */
+ 128,
+ RS_TYPE_STRING,
+ 25622,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "GSS-Acceptor-Service-Name-VS",
+ },
+ { /* 276 */
+ 129,
+ RS_TYPE_STRING,
+ 25622,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "GSS-Acceptor-Host-Name-VS",
+ },
+ { /* 277 */
+ 130,
+ RS_TYPE_STRING,
+ 25622,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "GSS-Acceptor-Service-Specific-VS",
+ },
+ { /* 278 */
+ 131,
+ RS_TYPE_STRING,
+ 25622,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "GSS-Acceptor-Realm-Name-VS",
+ },
+ { /* 279 */
+ 132,
+ RS_TYPE_STRING,
+ 25622,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "SAML-AAA-Assertion",
+ },
+ { /* 280 */
+ 133,
+ RS_TYPE_OCTETS,
+ 25622,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "MS-Windows-Auth-Data",
+ },
+ { /* 281 */
+ 134,
+ RS_TYPE_STRING,
+ 25622,
+ { 0, 0, 0, 0, 0, 0, 0, },
+ "MS-Windows-Group-Sid",
+ },
+};
+
+const int nr_dict_num_attrs = 281;
+
+const int nr_dict_num_names = 165;
+
+const DICT_ATTR *nr_dict_attr_names[] = {
+ &nr_dict_attrs[45], /* Acct-Authentic */
+ &nr_dict_attrs[41], /* Acct-Delay-Time */
+ &nr_dict_attrs[52], /* Acct-Input-Gigawords */
+ &nr_dict_attrs[42], /* Acct-Input-Octets */
+ &nr_dict_attrs[47], /* Acct-Input-Packets */
+ &nr_dict_attrs[85], /* Acct-Interim-Interval */
+ &nr_dict_attrs[51], /* Acct-Link-Count */
+ &nr_dict_attrs[50], /* Acct-Multi-Session-Id */
+ &nr_dict_attrs[53], /* Acct-Output-Gigawords */
+ &nr_dict_attrs[43], /* Acct-Output-Octets */
+ &nr_dict_attrs[48], /* Acct-Output-Packets */
+ &nr_dict_attrs[44], /* Acct-Session-Id */
+ &nr_dict_attrs[46], /* Acct-Session-Time */
+ &nr_dict_attrs[40], /* Acct-Status-Type */
+ &nr_dict_attrs[49], /* Acct-Terminate-Cause */
+ &nr_dict_attrs[68], /* Acct-Tunnel-Connection */
+ &nr_dict_attrs[86], /* Acct-Tunnel-Packets-Lost */
+ &nr_dict_attrs[84], /* ARAP-Challenge-Response */
+ &nr_dict_attrs[71], /* ARAP-Features */
+ &nr_dict_attrs[70], /* ARAP-Password */
+ &nr_dict_attrs[73], /* ARAP-Security */
+ &nr_dict_attrs[74], /* ARAP-Security-Data */
+ &nr_dict_attrs[72], /* ARAP-Zone-Access */
+ &nr_dict_attrs[129], /* Basic-Location-Policy-Rules */
+ &nr_dict_attrs[20], /* Callback-Id */
+ &nr_dict_attrs[19], /* Callback-Number */
+ &nr_dict_attrs[30], /* Called-Station-Id */
+ &nr_dict_attrs[31], /* Calling-Station-Id */
+ &nr_dict_attrs[60], /* CHAP-Challenge */
+ &nr_dict_attrs[3], /* CHAP-Password */
+ &nr_dict_attrs[89], /* Chargeable-User-Identity */
+ &nr_dict_attrs[25], /* Class */
+ &nr_dict_attrs[78], /* Configuration-Token */
+ &nr_dict_attrs[77], /* Connect-Info */
+ &nr_dict_attrs[123], /* Delegated-IPv6-Prefix */
+ &nr_dict_attrs[118], /* Digest-AKA-Auts */
+ &nr_dict_attrs[111], /* Digest-Algorithm */
+ &nr_dict_attrs[117], /* Digest-Auth-Param */
+ &nr_dict_attrs[113], /* Digest-CNonce */
+ &nr_dict_attrs[119], /* Digest-Domain */
+ &nr_dict_attrs[112], /* Digest-Entity-Body-Hash */
+ &nr_dict_attrs[121], /* Digest-HA1 */
+ &nr_dict_attrs[108], /* Digest-Method */
+ &nr_dict_attrs[107], /* Digest-Nextnonce */
+ &nr_dict_attrs[105], /* Digest-Nonce */
+ &nr_dict_attrs[114], /* Digest-Nonce-Count */
+ &nr_dict_attrs[116], /* Digest-Opaque */
+ &nr_dict_attrs[110], /* Digest-Qop */
+ &nr_dict_attrs[104], /* Digest-Realm */
+ &nr_dict_attrs[103], /* Digest-Response */
+ &nr_dict_attrs[106], /* Digest-Response-Auth */
+ &nr_dict_attrs[120], /* Digest-Stale */
+ &nr_dict_attrs[109], /* Digest-URI */
+ &nr_dict_attrs[115], /* Digest-Username */
+ &nr_dict_attrs[102], /* EAP-Key-Name */
+ &nr_dict_attrs[79], /* EAP-Message */
+ &nr_dict_attrs[58], /* Egress-VLAN-Name */
+ &nr_dict_attrs[56], /* Egress-VLANID */
+ &nr_dict_attrs[101], /* Error-Cause */
+ &nr_dict_attrs[55], /* Event-Timestamp */
+ &nr_dict_attrs[130], /* Extended-Location-Policy-Rules */
+ &nr_dict_attrs[11], /* Filter-Id */
+ &nr_dict_attrs[37], /* Framed-AppleTalk-Link */
+ &nr_dict_attrs[38], /* Framed-AppleTalk-Network */
+ &nr_dict_attrs[39], /* Framed-AppleTalk-Zone */
+ &nr_dict_attrs[13], /* Framed-Compression */
+ &nr_dict_attrs[96], /* Framed-Interface-Id */
+ &nr_dict_attrs[8], /* Framed-IP-Address */
+ &nr_dict_attrs[9], /* Framed-IP-Netmask */
+ &nr_dict_attrs[100], /* Framed-IPv6-Pool */
+ &nr_dict_attrs[97], /* Framed-IPv6-Prefix */
+ &nr_dict_attrs[99], /* Framed-IPv6-Route */
+ &nr_dict_attrs[23], /* Framed-IPX-Network */
+ &nr_dict_attrs[133], /* Framed-Management */
+ &nr_dict_attrs[12], /* Framed-MTU */
+ &nr_dict_attrs[88], /* Framed-Pool */
+ &nr_dict_attrs[7], /* Framed-Protocol */
+ &nr_dict_attrs[22], /* Framed-Route */
+ &nr_dict_attrs[10], /* Framed-Routing */
+ &nr_dict_attrs[165], /* GSS-Acceptor-Host-Name */
+ &nr_dict_attrs[276], /* GSS-Acceptor-Host-Name-VS */
+ &nr_dict_attrs[167], /* GSS-Acceptor-Realm-Name */
+ &nr_dict_attrs[278], /* GSS-Acceptor-Realm-Name-VS */
+ &nr_dict_attrs[164], /* GSS-Acceptor-Service-Name */
+ &nr_dict_attrs[275], /* GSS-Acceptor-Service-Name-VS */
+ &nr_dict_attrs[277], /* GSS-Acceptor-Service-Specific-VS */
+ &nr_dict_attrs[166], /* GSS-Acceptor-Service-Specifics */
+ &nr_dict_attrs[28], /* Idle-Timeout */
+ &nr_dict_attrs[57], /* Ingress-Filters */
+ &nr_dict_attrs[268], /* Juniper-Allow-Commands */
+ &nr_dict_attrs[270], /* Juniper-Allow-Configuration */
+ &nr_dict_attrs[273], /* Juniper-Configuration-Change */
+ &nr_dict_attrs[269], /* Juniper-Deny-Commands */
+ &nr_dict_attrs[271], /* Juniper-Deny-Configuration */
+ &nr_dict_attrs[272], /* Juniper-Interactive-Command */
+ &nr_dict_attrs[267], /* Juniper-Local-User-Name */
+ &nr_dict_attrs[274], /* Juniper-User-Permissions */
+ &nr_dict_attrs[131], /* Location-Capable */
+ &nr_dict_attrs[128], /* Location-Data */
+ &nr_dict_attrs[127], /* Location-Information */
+ &nr_dict_attrs[14], /* Login-IP-Host */
+ &nr_dict_attrs[98], /* Login-IPv6-Host */
+ &nr_dict_attrs[36], /* Login-LAT-Group */
+ &nr_dict_attrs[35], /* Login-LAT-Node */
+ &nr_dict_attrs[63], /* Login-LAT-Port */
+ &nr_dict_attrs[34], /* Login-LAT-Service */
+ &nr_dict_attrs[15], /* Login-Service */
+ &nr_dict_attrs[16], /* Login-TCP-Port */
+ &nr_dict_attrs[135], /* Management-Policy-Id */
+ &nr_dict_attrs[136], /* Management-Privilege-Level */
+ &nr_dict_attrs[134], /* Management-Transport-Protection */
+ &nr_dict_attrs[80], /* Message-Authenticator */
+ &nr_dict_attrs[261], /* MS-CHAP-Challenge */
+ &nr_dict_attrs[260], /* MS-CHAP-Domain */
+ &nr_dict_attrs[257], /* MS-CHAP-Error */
+ &nr_dict_attrs[262], /* MS-CHAP-MPPE-Keys */
+ &nr_dict_attrs[256], /* MS-CHAP-Response */
+ &nr_dict_attrs[265], /* MS-CHAP2-Response */
+ &nr_dict_attrs[266], /* MS-CHAP2-Success */
+ &nr_dict_attrs[258], /* MS-MPPE-Encryption-Policy */
+ &nr_dict_attrs[259], /* MS-MPPE-Encryption-Types */
+ &nr_dict_attrs[264], /* MS-MPPE-Recv-Key */
+ &nr_dict_attrs[263], /* MS-MPPE-Send-Key */
+ &nr_dict_attrs[280], /* MS-Windows-Auth-Data */
+ &nr_dict_attrs[281], /* MS-Windows-Group-Sid */
+ &nr_dict_attrs[92], /* NAS-Filter-Rule */
+ &nr_dict_attrs[32], /* NAS-Identifier */
+ &nr_dict_attrs[4], /* NAS-IP-Address */
+ &nr_dict_attrs[95], /* NAS-IPv6-Address */
+ &nr_dict_attrs[5], /* NAS-Port */
+ &nr_dict_attrs[87], /* NAS-Port-Id */
+ &nr_dict_attrs[61], /* NAS-Port-Type */
+ &nr_dict_attrs[126], /* Operator-Name */
+ &nr_dict_attrs[75], /* Password-Retry */
+ &nr_dict_attrs[143], /* PKM-Auth-Key */
+ &nr_dict_attrs[138], /* PKM-CA-Cert */
+ &nr_dict_attrs[139], /* PKM-Config-Settings */
+ &nr_dict_attrs[140], /* PKM-Cryptosuite-List */
+ &nr_dict_attrs[142], /* PKM-SA-Descriptor */
+ &nr_dict_attrs[141], /* PKM-SAID */
+ &nr_dict_attrs[137], /* PKM-SS-Cert */
+ &nr_dict_attrs[62], /* Port-Limit */
+ &nr_dict_attrs[76], /* Prompt */
+ &nr_dict_attrs[33], /* Proxy-State */
+ &nr_dict_attrs[18], /* Reply-Message */
+ &nr_dict_attrs[132], /* Requested-Location-Info */
+ &nr_dict_attrs[279], /* SAML-AAA-Assertion */
+ &nr_dict_attrs[6], /* Service-Type */
+ &nr_dict_attrs[27], /* Session-Timeout */
+ &nr_dict_attrs[122], /* SIP-AOR */
+ &nr_dict_attrs[24], /* State */
+ &nr_dict_attrs[29], /* Termination-Action */
+ &nr_dict_attrs[82], /* Tunnel-Assignment-Id */
+ &nr_dict_attrs[90], /* Tunnel-Client-Auth-Id */
+ &nr_dict_attrs[66], /* Tunnel-Client-Endpoint */
+ &nr_dict_attrs[65], /* Tunnel-Medium-Type */
+ &nr_dict_attrs[69], /* Tunnel-Password */
+ &nr_dict_attrs[83], /* Tunnel-Preference */
+ &nr_dict_attrs[81], /* Tunnel-Private-Group-Id */
+ &nr_dict_attrs[91], /* Tunnel-Server-Auth-Id */
+ &nr_dict_attrs[67], /* Tunnel-Server-Endpoint */
+ &nr_dict_attrs[64], /* Tunnel-Type */
+ &nr_dict_attrs[1], /* User-Name */
+ &nr_dict_attrs[2], /* User-Password */
+ &nr_dict_attrs[59], /* User-Priority-Table */
+ &nr_dict_attrs[26], /* Vendor-Specific */
+};
+
diff --git a/radius/id.c b/radius/id.c
new file mode 100644
index 0000000..4ccd032
--- /dev/null
+++ b/radius/id.c
@@ -0,0 +1,181 @@
+/*
+Copyright (c) 2011, Network RADIUS SARL
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "client.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/** \file id.c
+ * \brief Handling of ID allocation / freeing
+ *
+ */
+
+static int find_id(nr_server_t *s)
+{
+ int i;
+ uint32_t lvalue;
+
+ if ((s->used < 0) || (s->used > 256)) return -RSE_INTERNAL;
+
+ /*
+ * Ensure that the ID allocation is random.
+ */
+ lvalue = nr_rand();
+
+ for (i = 0; i < 256; i++) {
+ int offset = (i + lvalue) & 0xff;
+
+ if (!s->ids[offset]) return offset;
+ }
+
+ nr_strerror_printf("Out of IDs for server");
+ return -1;
+}
+
+int nr_server_id_alloc(nr_server_t *s, RADIUS_PACKET *packet)
+{
+ int new_id;
+
+ if (!s || !packet) return -RSE_INVAL;
+
+ new_id = find_id(s);
+ if (new_id < 0) return -new_id;
+
+ s->ids[new_id] = packet;
+ s->used++;
+ packet->sockfd = s->sockfd;
+ packet->code = s->code;
+ packet->src = s->src;
+ packet->dst = s->dst;
+ packet->id = new_id;
+
+ return 0;
+}
+
+int nr_server_id_free(nr_server_t *s, RADIUS_PACKET *packet)
+{
+ if (!s || !packet) return -RSE_INVAL;
+
+ if ((packet->id < 0) || (packet->id > 255) || !s->ids[packet->id]) {
+ return -RSE_INVAL;
+ }
+
+ if (s->ids[packet->id] != packet) return -RSE_INTERNAL;
+
+ s->ids[packet->id] = NULL;
+ s->used--;
+ packet->sockfd = -1;
+
+ return 0;
+}
+
+int nr_server_id_realloc(nr_server_t *s, RADIUS_PACKET *packet)
+{
+ int new_id;
+
+ if (!s || !packet) return -RSE_INVAL;
+
+ if ((packet->id < 0) || (packet->id > 255) || !s->ids[packet->id]) {
+ return -RSE_INVAL;
+ }
+
+ if (s->ids[packet->id] != packet) return -RSE_INTERNAL;
+
+ new_id = find_id(s);
+ if (new_id < 0) return new_id;
+
+ s->ids[packet->id] = NULL;
+ packet->id = new_id;
+ s->ids[packet->id] = packet;
+
+ return 0;
+}
+
+
+int nr_server_init(nr_server_t *s, int code, const char *secret)
+{
+ if (!s || !secret || !*secret ||
+ (code == 0) || (code > RS_MAX_PACKET_CODE)) {
+ return -RSE_INVAL;
+ }
+
+ memset(s, 0, sizeof(*s));
+
+ s->sockfd = -1;
+ s->code = code;
+ s->secret = secret;
+ s->sizeof_secret = strlen(secret);
+ s->src.ss_family = AF_UNSPEC;
+ s->dst.ss_family = AF_UNSPEC;
+
+ return 0;
+}
+
+
+int nr_server_close(const nr_server_t *s)
+{
+ if (!s) return -RSE_INVAL;
+
+ if (s->used > 0) return -RSE_INUSE;
+
+ if (s->sockfd >= 0) evutil_closesocket(s->sockfd);
+
+ return 0;
+}
+
+int nr_server_packet_alloc(const nr_server_t *s, RADIUS_PACKET **packet_p)
+{
+ int rcode;
+ RADIUS_PACKET *packet;
+
+ if (!packet_p) return -RSE_INVAL;
+
+ packet = malloc(sizeof(*packet) + RS_MAX_PACKET_LEN);
+ if (!packet) return -RSE_NOMEM;
+
+ memset(packet, 0, sizeof(*packet));
+
+ if (!s) {
+ packet->data = (uint8_t *)(packet + 1);
+ packet->sizeof_data = RS_MAX_PACKET_LEN;
+
+ *packet_p = packet;
+ return 0;
+ }
+
+ rcode = nr_packet_init(packet, NULL, s->secret, s->code,
+ (uint8_t *)(packet + 1), RS_MAX_PACKET_LEN);
+ if (rcode < 0) {
+ free(packet);
+ return rcode;
+ }
+
+ *packet_p = packet;
+ return 0;
+}
diff --git a/radius/parse.c b/radius/parse.c
new file mode 100644
index 0000000..8446306
--- /dev/null
+++ b/radius/parse.c
@@ -0,0 +1,149 @@
+/*
+Copyright (c) 2011, Network RADIUS SARL
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file parse.c
+ * \brief Routines to parse strings into internal data structures
+ */
+
+#include "client.h"
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+ssize_t nr_vp_sscanf_value(VALUE_PAIR *vp, const char *value)
+{
+ char *end;
+
+ switch (vp->da->type) {
+ case RS_TYPE_STRING: {
+ size_t len = strlen(value);
+
+ if (len >= RS_MAX_STRING_LEN)
+ return -RSE_ATTR_TOO_LARGE;
+
+ memcpy(vp->vp_strvalue, value, len + 1);
+ return (vp->length = len);
+ }
+ case RS_TYPE_DATE:
+ case RS_TYPE_INTEGER:
+ vp->vp_integer = strtoul(value, &end, 10);
+ if ((value == end) || (*end != '\0')) {
+ nr_debug_error("Invalid value");
+ return -RSE_ATTR_VALUE_MALFORMED;
+ }
+ return (end - value);
+
+ case RS_TYPE_IPADDR:
+ if (inet_pton(AF_INET, value, &vp->vp_ipaddr) < 0) {
+ return -RSE_NOSYS;
+ }
+ return strlen(value);
+
+#ifdef RS_TYPE_IPV6ADDR
+ case RS_TYPE_IPV6ADDR:
+ if (inet_pton(AF_INET6, value, &vp-vp>ipv6addr) < 0) {
+ return -RSE_NOSYS;
+ }
+ return strlen(value);
+#endif
+
+#ifdef RS_TYPE_IFID
+ case RS_TYPE_IFID:
+ {
+ int i, array[8];
+
+ if (sscanf(value, "%02x%02x%02x%02x%02x%02x%02x%02x",
+ &array[0], &array[1], &array[2], &array[3],
+ &array[4], &array[5], &array[6], &array[7]) != 8) {
+ return -RSE_SYSTEM;
+ }
+
+ for (i = 0; i < 8; i++) vp->vp_ifid[i] = array[i] & 0xff;
+
+ }
+ break;
+#endif
+
+ default:
+ nr_debug_error("Invalid type");
+ return -RSE_ATTR_TYPE_UNKNOWN;
+ }
+
+ return 0;
+}
+
+int nr_vp_sscanf(const char *string, VALUE_PAIR **pvp)
+{
+ int rcode;
+ const char *p;
+ char *q;
+ const DICT_ATTR *da;
+ VALUE_PAIR *vp;
+ char buffer[256];
+
+ if (!string || !pvp) return -RSE_INVAL;
+
+ p = string;
+ q = buffer;
+ while (*p && (*p != ' ') && (*p != '=')) {
+ *(q++) = *(p++);
+ }
+ *q = '\0';
+
+ if (q == buffer) {
+ nr_debug_error("No Attribute name");
+ return -RSE_ATTR_BAD_NAME;
+ }
+
+ da = nr_dict_attr_byname(buffer);
+ if (!da) {
+ nr_debug_error("Unknown attribute \"%s\"", buffer);
+ return -RSE_ATTR_UNKNOWN;
+ }
+
+ while (*p == ' ') p++;
+ if (*p != '=') {
+ nr_debug_error("Unexpected text after attribute name");
+ return -RSE_ATTR_BAD_NAME;
+ }
+
+ p++;
+ while (*p == ' ') p++;
+
+ vp = nr_vp_alloc(da);
+ if (!vp) return -RSE_NOMEM;
+
+ rcode = nr_vp_sscanf_value(vp, p);
+ if (rcode < 0) {
+ nr_vp_free(&vp);
+ return rcode;
+ }
+
+ *pvp = vp;
+ return 0;
+}
diff --git a/radius/print.c b/radius/print.c
new file mode 100644
index 0000000..6fa06d7
--- /dev/null
+++ b/radius/print.c
@@ -0,0 +1,227 @@
+/*
+Copyright (c) 2011, Network RADIUS SARL
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file print.c
+ * \brief Functions to print things.
+ */
+
+#include "client.h"
+#include <string.h>
+#ifdef RS_TYPE_IPV6ADDR
+#include <arpa/inet.h>
+#endif
+
+#ifndef NDEBUG
+void nr_packet_print_hex(RADIUS_PACKET *packet)
+{
+ int i;
+
+ if (!packet->data) return;
+
+ printf(" Code:\t\t%u\n", packet->data[0]);
+ printf(" Id:\t\t%u\n", packet->data[1]);
+ printf(" Length:\t%u\n", ((packet->data[2] << 8) |
+ (packet->data[3])));
+ printf(" Vector:\t");
+ for (i = 4; i < 20; i++) {
+ printf("%02x", packet->data[i]);
+ }
+ printf("\n");
+ if ((packet->flags & RS_PACKET_SIGNED) == 0) printf("\t\tWARNING: nr_packet_sign() was not called!\n");
+
+ if (packet->length > 20) {
+ int total;
+ const uint8_t *ptr;
+ printf(" Data:");
+
+ total = packet->length - 20;
+ ptr = packet->data + 20;
+
+ while (total > 0) {
+ int attrlen;
+
+ printf("\t\t");
+ if (total < 2) { /* too short */
+ printf("%02x\n", *ptr);
+ break;
+ }
+
+ if (ptr[1] > total) { /* too long */
+ for (i = 0; i < total; i++) {
+ printf("%02x ", ptr[i]);
+ }
+ break;
+ }
+
+ printf("%02x %02x ", ptr[0], ptr[1]);
+ attrlen = ptr[1] - 2;
+ ptr += 2;
+ total -= 2;
+
+ for (i = 0; i < attrlen; i++) {
+ if ((i > 0) && ((i & 0x0f) == 0x00))
+ printf("\t\t\t");
+ printf("%02x ", ptr[i]);
+ if ((i & 0x0f) == 0x0f) printf("\n");
+ }
+
+ if (!attrlen || ((attrlen & 0x0f) != 0x00)) printf("\n");
+
+ ptr += attrlen;
+ total -= attrlen;
+ }
+ }
+ printf("\n");
+ fflush(stdout);
+}
+#endif
+
+size_t nr_vp_snprintf_value(char *buffer, size_t buflen, const VALUE_PAIR *vp)
+{
+ size_t i, len;
+ char *p = buffer;
+
+ switch (vp->da->type) {
+ case RS_TYPE_STRING:
+ /*
+ * FIXME: escape backslash && quotes!
+ */
+ len = snprintf(p, buflen, "%s", vp->vp_strvalue);
+ break;
+
+ case RS_TYPE_DATE:
+ case RS_TYPE_INTEGER:
+ case RS_TYPE_SHORT:
+ case RS_TYPE_BYTE:
+ len = snprintf(p, buflen, "%u", vp->vp_integer);
+ break;
+
+ case RS_TYPE_IPADDR:
+ len = snprintf(p, buflen, "%u.%u.%u.%u",
+ (vp->vp_ipaddr >> 24) & 0xff,
+ (vp->vp_ipaddr >> 16) & 0xff,
+ (vp->vp_ipaddr >> 8) & 0xff,
+ vp->vp_ipaddr & 0xff);
+ break;
+
+#ifdef RS_TYPE_IPV6ADDR
+ case RS_TYPE_IPV6ADDR:
+ if (!inet_ntop(AF_INET6, &vp->vp_ipv6addr, buffer, buflen)) {
+ return -RSE_SYSTEM;
+ }
+ break;
+#endif
+
+#ifdef RS_TYPE_IFID
+ case RS_TYPE_IFID:
+ len = snprintf(p, buflen, "%02x%02x%02x%02x%02x%02x%02x%02x",
+ vp->vp_ifid[0], vp->vp_ifid[1],
+ vp->vp_ifid[2], vp->vp_ifid[3],
+ vp->vp_ifid[4], vp->vp_ifid[5],
+ vp->vp_ifid[6], vp->vp_ifid[7]);
+ break;
+#endif
+
+ case RS_TYPE_OCTETS:
+ len = snprintf(p, buflen, "0x");
+ if (len >= buflen) return 0;
+
+ p += len;
+ buflen -= len;
+
+ for (i = 0; i < vp->length; i++) {
+ len = snprintf(p, buflen, "%02x", vp->vp_octets[i]);
+ if (len >= buflen) return 0;
+
+ p += len;
+ buflen -= len;
+ }
+ len = 0;
+ break;
+
+ default:
+ len = 0;
+ break;
+ }
+
+ if (len >= buflen) return 0;
+
+ p += len;
+ buflen -= len;
+
+ return p - buffer;
+}
+
+size_t nr_vp_snprintf(char *buffer, size_t buflen, const VALUE_PAIR *vp)
+{
+ size_t len;
+ char *p = buffer;
+
+ len = snprintf(p, buflen, "%s = ", vp->da->name);
+ if (len >= buflen) return 0;
+
+ p += len;
+ buflen -= len;
+
+ len = nr_vp_snprintf_value(p, buflen, vp);
+ if (len == 0) return 0;
+
+ if (len >= buflen) return 0;
+
+ p += len;
+
+ return p - buffer;
+}
+
+#ifndef NDEBUG
+void nr_vp_fprintf_list(FILE *fp, const VALUE_PAIR *vps)
+{
+ const VALUE_PAIR *vp;
+ char buffer[1024];
+
+ for (vp = vps; vp != NULL; vp = vp->next) {
+ nr_vp_snprintf(buffer, sizeof(buffer), vp);
+ fprintf(fp, "\t%s\n", buffer);
+ }
+}
+#endif
+
+/** \cond PRIVATE */
+#define NR_STRERROR_BUFSIZE (1024)
+static char nr_strerror_buffer[NR_STRERROR_BUFSIZE];
+
+void nr_strerror_printf(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(nr_strerror_buffer, sizeof(nr_strerror_buffer), fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr, "ERROR: %s\n", nr_strerror_buffer);
+}
+/** \endcond */
+
diff --git a/radius/radpkt.c b/radius/radpkt.c
new file mode 100644
index 0000000..d9486ea
--- /dev/null
+++ b/radius/radpkt.c
@@ -0,0 +1,920 @@
+/*
+Copyright (c) 2011, Network RADIUS SARL
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file packet.c
+ * \brief Encoding and decoding packets
+ */
+
+#include "client.h"
+
+#if RS_MAX_PACKET_LEN < 64
+#error RS_MAX_PACKET_LEN is too small. It should be at least 64.
+#endif
+
+#if RS_MAX_PACKET_LEN > 16384
+#error RS_MAX_PACKET_LEN is too large. It should be smaller than 16K.
+#endif
+
+const char *nr_packet_codes[RS_MAX_PACKET_CODE + 1] = {
+ NULL,
+ "Access-Request",
+ "Access-Accept",
+ "Access-Reject",
+ "Accounting-Request",
+ "Accounting-Response",
+ NULL, NULL, NULL, NULL, NULL,
+ "Access-Challenge",
+ "Status-Server", /* 12 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 19 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 20..29 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 30..39 */
+ "Disconnect-Request",
+ "Disconnect-ACK",
+ "Disconnect-NAK",
+ "CoA-Request",
+ "CoA-ACK",
+ "CoA-NAK"
+};
+
+
+static uint64_t allowed_responses[RS_MAX_PACKET_CODE + 1] = {
+ 0,
+ (1 << PW_ACCESS_ACCEPT) | (1 << PW_ACCESS_REJECT) | (1 << PW_ACCESS_CHALLENGE),
+ 0, 0,
+ 1 << PW_ACCOUNTING_RESPONSE,
+ 0,
+ 0, 0, 0, 0, 0,
+ 0,
+ (1 << PW_ACCESS_ACCEPT) | (1 << PW_ACCESS_REJECT) | (1 << PW_ACCESS_CHALLENGE) | (1 << PW_ACCOUNTING_RESPONSE),
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20..29 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30..39 */
+ (((uint64_t) 1) << PW_DISCONNECT_ACK) | (((uint64_t) 1) << PW_DISCONNECT_NAK),
+ 0,
+ 0,
+ (((uint64_t) 1) << PW_COA_ACK) | (((uint64_t) 1) << PW_COA_NAK),
+ 0,
+ 0
+};
+
+
+int nr_packet_ok_raw(const uint8_t *data, size_t sizeof_data)
+{
+ size_t packet_len;
+ const uint8_t *attr, *end;
+
+ if (!data || (sizeof_data < 20)) {
+ nr_debug_error("Invalid argument");
+ return -RSE_INVAL;
+ }
+
+ packet_len = (data[2] << 8) | data[3];
+ if (packet_len < 20) {
+ nr_debug_error("Packet length is too small");
+ return -RSE_PACKET_TOO_SMALL;
+ }
+
+ if (packet_len > sizeof_data) {
+ nr_debug_error("Packet length overflows received data");
+ return -RSE_PACKET_TOO_LARGE;
+ }
+
+ /*
+ * If we receive 100 bytes, and the header says it's 20 bytes,
+ * then it's 20 bytes.
+ */
+ end = data + packet_len;
+
+ for (attr = data + 20; attr < end; attr += attr[1]) {
+ if ((attr + 2) > end) {
+ nr_debug_error("Attribute overflows packet");
+ return -RSE_ATTR_OVERFLOW;
+ }
+
+ if (attr[1] < 2) {
+ nr_debug_error("Attribute length is too small");
+ return -RSE_ATTR_TOO_SMALL;
+ }
+
+ if ((attr + attr[1]) > end) {
+ nr_debug_error("Attribute length is too large");
+ return -RSE_ATTR_TOO_LARGE;
+ }
+ }
+
+ return 0;
+}
+
+int nr_packet_ok(RADIUS_PACKET *packet)
+{
+ int rcode;
+
+ if (!packet) return -RSE_INVAL;
+
+ if ((packet->flags & RS_PACKET_OK) != 0) return 0;
+
+ rcode = nr_packet_ok_raw(packet->data, packet->length);
+ if (rcode < 0) return rcode;
+
+ packet->flags |= RS_PACKET_OK;
+ return 0;
+}
+
+
+/*
+ * Comparison function that is time-independent. Using "memcmp"
+ * would satisfy the "comparison" part. However, it would also
+ * leak information about *which* bytes are wrong. Attackers
+ * could use that leak to create a "correct" RADIUS packet which
+ * will be accepted by the client and/or server.
+ */
+static int digest_cmp(const uint8_t *a, const uint8_t *b, size_t length)
+{
+ int result = 0;
+ size_t i;
+
+ for (i = 0; i < length; i++) {
+ result |= (a[i] ^ b[i]);
+ }
+
+ return result;
+}
+
+
+#ifdef PW_MESSAGE_AUTHENTICATOR
+static int msg_auth_ok(const RADIUS_PACKET *original,
+ uint8_t *ma,
+ uint8_t *data, size_t length)
+{
+ uint8_t packet_vector[sizeof(original->vector)];
+ uint8_t msg_auth_vector[sizeof(original->vector)];
+ uint8_t calc_auth_vector[sizeof(original->vector)];
+
+ if (ma[1] != 18) {
+ nr_debug_error("Message-Authenticator has invalid length");
+ return -RSE_MSG_AUTH_LEN;
+ }
+
+ memcpy(packet_vector, data + 4, sizeof(packet_vector));
+ memcpy(msg_auth_vector, ma + 2, sizeof(msg_auth_vector));
+ memset(ma + 2, 0, sizeof(msg_auth_vector));
+
+ switch (data[0]) {
+ default:
+ break;
+
+ case PW_ACCOUNTING_REQUEST:
+ case PW_ACCOUNTING_RESPONSE:
+ case PW_DISCONNECT_REQUEST:
+ case PW_DISCONNECT_ACK:
+ case PW_DISCONNECT_NAK:
+ case PW_COA_REQUEST:
+ case PW_COA_ACK:
+ case PW_COA_NAK:
+ memset(data + 4, 0, sizeof(packet_vector));
+ break;
+
+ case PW_ACCESS_ACCEPT:
+ case PW_ACCESS_REJECT:
+ case PW_ACCESS_CHALLENGE:
+ if (!original) {
+ nr_debug_error("Cannot validate response without request");
+ return -RSE_REQUEST_REQUIRED;
+ }
+ memcpy(data + 4, original->vector, sizeof(original->vector));
+ break;
+ }
+
+ nr_hmac_md5(data, length,
+ (const uint8_t *) original->secret, original->sizeof_secret,
+ calc_auth_vector);
+
+ memcpy(ma + 2, msg_auth_vector, sizeof(msg_auth_vector));
+ memcpy(data + 4, packet_vector, sizeof(packet_vector));
+
+ if (digest_cmp(calc_auth_vector, msg_auth_vector,
+ sizeof(calc_auth_vector)) != 0) {
+ nr_debug_error("Invalid Message-Authenticator");
+ return -RSE_MSG_AUTH_WRONG;
+ }
+
+ return 1;
+}
+#endif
+
+/*
+ * The caller ensures that the packet codes are as expected.
+ */
+static int packet_auth_ok(const RADIUS_PACKET *original,
+ uint8_t *data, size_t length)
+{
+ uint8_t packet_vector[sizeof(original->vector)];
+ uint8_t calc_digest[sizeof(original->vector)];
+ RS_MD5_CTX ctx;
+
+ if ((data[0] == PW_ACCESS_REQUEST) ||
+ (data[0] == PW_STATUS_SERVER)) return 1;
+
+ memcpy(packet_vector, data + 4, sizeof(packet_vector));
+
+ if (!original) {
+ memset(data + 4, 0, sizeof(packet_vector));
+ } else {
+ memcpy(data + 4, original->vector, sizeof(original->vector));
+ }
+
+ RS_MD5Init(&ctx);
+ RS_MD5Update(&ctx, data, length);
+ RS_MD5Update(&ctx, (const unsigned char *)original->secret, original->sizeof_secret);
+ RS_MD5Final(calc_digest, &ctx);
+
+ memcpy(data + 4, packet_vector, sizeof(packet_vector));
+
+ if (digest_cmp(calc_digest, packet_vector,
+ sizeof(packet_vector)) != 0) {
+ nr_debug_error("Invalid authentication vector");
+ return -RSE_AUTH_VECTOR_WRONG;
+ }
+
+ return 0;
+}
+
+
+int nr_packet_verify(RADIUS_PACKET *packet, const RADIUS_PACKET *original)
+{
+ int rcode;
+ uint8_t *attr;
+#ifdef PW_MESSAGE_AUTHENTICATOR
+ const uint8_t *end;
+#endif
+
+ if (!packet || !packet->data || !packet->secret) {
+ nr_debug_error("Invalid argument");
+ return -RSE_INVAL;
+ }
+
+ if ((packet->flags & RS_PACKET_VERIFIED) != 0) return 0;
+
+ /*
+ * Packet isn't well formed. Ignore it.
+ */
+ rcode = nr_packet_ok(packet);
+ if (rcode < 0) return rcode;
+
+ /*
+ * Get rid of improper packets as early as possible.
+ */
+ if (original) {
+ uint64_t mask;
+
+ if (original->code > RS_MAX_PACKET_CODE) {
+ nr_debug_error("Invalid original code %u",
+ original->code);
+ return -RSE_INVALID_REQUEST_CODE;
+ }
+
+ if (packet->data[1] != original->id) {
+ nr_debug_error("Ignoring response with wrong ID %u",
+ packet->data[1]);
+ return -RSE_INVALID_RESPONSE_CODE;
+ }
+
+ mask = 1;
+ mask <<= packet->data[0];
+
+ if ((allowed_responses[original->code] & mask) == 0) {
+ nr_debug_error("Ignoring response with wrong code %u",
+ packet->data[0]);
+ return -RSE_INVALID_RESPONSE_CODE;
+ }
+
+ if ((memcmp(&packet->src, &original->dst, sizeof(packet->src)) != 0) &&
+ (evutil_sockaddr_cmp((struct sockaddr *)&packet->src, (struct sockaddr *)&original->dst, 1) != 0)) {
+ nr_debug_error("Ignoring response from wrong IP/port");
+ return -RSE_INVALID_RESPONSE_SRC;
+ }
+
+ } else if (allowed_responses[packet->data[0]] != 0) {
+ nr_debug_error("Ignoring response without original");
+ return -RSE_INVALID_RESPONSE_CODE;
+ }
+
+#ifdef PW_MESSAGE_AUTHENTICATOR
+ end = packet->data + packet->length;
+
+ /*
+ * Note that the packet MUST be well-formed here.
+ */
+ for (attr = packet->data + 20; attr < end; attr += attr[1]) {
+ if (attr[0] == PW_MESSAGE_AUTHENTICATOR) {
+ rcode = msg_auth_ok(original, attr,
+ packet->data, packet->length);
+ if (rcode < 0) return rcode;
+ }
+ }
+#endif
+
+ /*
+ * Verify the packet authenticator.
+ */
+ rcode = packet_auth_ok(original, packet->data, packet->length);
+ if (rcode < 0) return rcode;
+
+ packet->flags |= RS_PACKET_VERIFIED;
+
+ return 0;
+}
+
+
+int nr_packet_decode(RADIUS_PACKET *packet, const RADIUS_PACKET *original)
+{
+ int rcode, num_attributes;
+ uint8_t *data, *attr;
+ const uint8_t *end;
+ VALUE_PAIR **tail, *vp;
+
+ if (!packet) return -RSE_INVAL;
+
+ if ((packet->flags & RS_PACKET_DECODED) != 0) return 0;
+
+ rcode = nr_packet_ok(packet);
+ if (rcode < 0) return rcode;
+
+ data = packet->data;
+ end = data + packet->length;
+ tail = &packet->vps;
+ num_attributes = 0;
+
+ /*
+ * Loop over the packet, converting attrs to VPs.
+ */
+ for (attr = data + 20; attr < end; attr += attr[1]) {
+ rcode = nr_attr2vp(packet, original,
+ attr, end - attr, &vp);
+ if (rcode < 0) {
+ nr_vp_free(&packet->vps);
+ return -rcode;
+ }
+
+ *tail = vp;
+ while (vp) {
+ num_attributes++;
+ tail = &(vp->next);
+ vp = vp->next;
+ }
+
+ if (num_attributes > RS_MAX_ATTRIBUTES) {
+ nr_debug_error("Too many attributes");
+ nr_vp_free(&packet->vps);
+ return -RSE_TOO_MANY_ATTRS;
+ }
+ }
+
+ packet->code = data[0];
+ packet->id = data[1];
+ memcpy(packet->vector, data + 4, sizeof(packet->vector));
+
+ packet->flags |= RS_PACKET_DECODED;
+
+ return 0;
+}
+
+
+int nr_packet_sign(RADIUS_PACKET *packet, const RADIUS_PACKET *original)
+{
+#ifdef PW_MESSAGE_AUTHENTICATOR
+ size_t ma = 0;
+ const uint8_t *attr, *end;
+#endif
+
+ if ((packet->flags & RS_PACKET_SIGNED) != 0) return 0;
+
+ if ((packet->flags & RS_PACKET_ENCODED) == 0) {
+ int rcode;
+
+ rcode = nr_packet_encode(packet, original);
+ if (rcode < 0) return rcode;
+ }
+
+ if ((packet->code == PW_ACCESS_ACCEPT) ||
+ (packet->code == PW_ACCESS_CHALLENGE) ||
+ (packet->code == PW_ACCESS_REJECT)) {
+#ifdef PW_MESSAGE_AUTHENTICATOR
+ if (!original) {
+ nr_debug_error("Original packet is required to create the Message-Authenticator");
+ return -RSE_REQUEST_REQUIRED;
+ }
+#endif
+
+ memcpy(packet->data + 4, original->vector,
+ sizeof(original->vector));
+ } else {
+ memcpy(packet->data + 4, packet->vector,
+ sizeof(packet->vector));
+ }
+
+#ifdef PW_MESSAGE_AUTHENTICATOR
+ end = packet->data + packet->length;
+
+ for (attr = packet->data + 20; attr < end; attr += attr[1]) {
+ if (attr[0] == PW_MESSAGE_AUTHENTICATOR) {
+ ma = (attr - packet->data);
+ break;
+ }
+ }
+
+ /*
+ * Force all Access-Request packets to have a
+ * Message-Authenticator.
+ */
+ if (!ma && ((packet->length + 18) <= packet->sizeof_data) &&
+ ((packet->code == PW_ACCESS_REQUEST) ||
+ (packet->code == PW_STATUS_SERVER))) {
+ ma = packet->length;
+
+ packet->data[ma]= PW_MESSAGE_AUTHENTICATOR;
+ packet->data[ma + 1] = 18;
+ memset(&packet->data[ma + 2], 0, 16);
+ packet->length += 18;
+ }
+
+ /*
+ * Reset the length.
+ */
+ packet->data[2] = (packet->length >> 8) & 0xff;
+ packet->data[3] = packet->length & 0xff;
+
+ /*
+ * Sign the Message-Authenticator && packet.
+ */
+ if (ma) {
+ nr_hmac_md5(packet->data, packet->length,
+ (const uint8_t *) packet->secret, packet->sizeof_secret,
+ packet->data + ma + 2);
+ }
+#endif
+
+ /*
+ * Calculate the signature.
+ */
+ if (!((packet->code == PW_ACCESS_REQUEST) ||
+ (packet->code == PW_STATUS_SERVER))) {
+ RS_MD5_CTX ctx;
+
+ RS_MD5Init(&ctx);
+ RS_MD5Update(&ctx, packet->data, packet->length);
+ RS_MD5Update(&ctx, (const unsigned char *)packet->secret, packet->sizeof_secret);
+ RS_MD5Final(packet->vector, &ctx);
+ }
+
+ memcpy(packet->data + 4, packet->vector, sizeof(packet->vector));
+
+ packet->attempts = 0;
+ packet->flags |= RS_PACKET_SIGNED;
+
+ return 0;
+}
+
+
+static int can_encode_packet(RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original)
+{
+ if ((packet->code == 0) ||
+ (packet->code > RS_MAX_PACKET_CODE) ||
+ (original && (original->code > RS_MAX_PACKET_CODE))) {
+ nr_debug_error("Cannot send unknown packet code");
+ return -RSE_INVALID_REQUEST_CODE;
+ }
+
+ if (!nr_packet_codes[packet->code]) {
+ nr_debug_error("Cannot handle packet code %u",
+ packet->code);
+ return -RSE_INVALID_REQUEST_CODE;
+ }
+
+#ifdef NR_NO_MALLOC
+ if (!packet->data) {
+ nr_debug_error("No place to put packet");
+ return -RSE_NO_PACKET_DATA;
+ }
+#endif
+
+ if (packet->sizeof_data < 20) {
+ nr_debug_error("The buffer is too small to encode the packet");
+ return -RSE_PACKET_TOO_SMALL;
+ }
+
+ /*
+ * Enforce request / response correlation.
+ */
+ if (original) {
+ uint64_t mask;
+
+ mask = 1;
+ mask <<= packet->code;
+
+ if ((allowed_responses[original->code] & mask) == 0) {
+ nr_debug_error("Cannot encode response %u to packet %u",
+ packet->code, original->code);
+ return -RSE_INVALID_RESPONSE_CODE;
+ }
+ packet->id = original->id;
+
+ } else if (allowed_responses[packet->code] == 0) {
+ nr_debug_error("Cannot encode response %u without original",
+ packet->code);
+ return -RSE_REQUEST_REQUIRED;
+ }
+
+ return 0;
+}
+
+static void encode_header(RADIUS_PACKET *packet)
+{
+ if ((packet->flags & RS_PACKET_HEADER) != 0) return;
+
+ memset(packet->data, 0, 20);
+ packet->data[0] = packet->code;
+ packet->data[1] = packet->id;
+ packet->data[2] = 0;
+ packet->data[3] = 20;
+ packet->length = 20;
+
+ /*
+ * Calculate a random authentication vector.
+ */
+ if ((packet->code == PW_ACCESS_REQUEST) ||
+ (packet->code == PW_STATUS_SERVER)) {
+ nr_rand_bytes(packet->vector, sizeof(packet->vector));
+ } else {
+ memset(packet->vector, 0, sizeof(packet->vector));
+ }
+
+ memcpy(packet->data + 4, packet->vector, sizeof(packet->vector));
+
+ packet->flags |= RS_PACKET_HEADER;
+}
+
+int nr_packet_encode(RADIUS_PACKET *packet, const RADIUS_PACKET *original)
+{
+#ifdef PW_MESSAGE_AUTHENTICATOR
+ size_t ma = 0;
+#endif
+ int rcode;
+ ssize_t len;
+ const VALUE_PAIR *vp;
+ uint8_t *data, *end;
+
+ if ((packet->flags & RS_PACKET_ENCODED) != 0) return 0;
+
+ rcode = can_encode_packet(packet, original);
+ if (rcode < 0) return rcode;
+
+ data = packet->data;
+ end = data + packet->sizeof_data;
+
+ encode_header(packet);
+ data += 20;
+
+ /*
+ * Encode each VALUE_PAIR
+ */
+ vp = packet->vps;
+ while (vp) {
+#ifdef PW_MESSAGE_AUTHENTICATOR
+ if (vp->da->attr == PW_MESSAGE_AUTHENTICATOR) {
+ ma = (data - packet->data);
+ }
+#endif
+ len = nr_vp2attr(packet, original, &vp,
+ data, end - data);
+ if (len < 0) return len;
+
+ if (len == 0) break; /* insufficient room to encode it */
+
+ data += data[1];
+ }
+
+#ifdef PW_MESSAGE_AUTHENTICATOR
+ /*
+ * Always send a Message-Authenticator.
+ *
+ * We do *not* recommend removing this code.
+ */
+ if (((packet->code == PW_ACCESS_REQUEST) ||
+ (packet->code == PW_STATUS_SERVER)) &&
+ !ma &&
+ ((data + 18) <= end)) {
+ ma = (data - packet->data);
+ data[0] = PW_MESSAGE_AUTHENTICATOR;
+ data[1] = 18;
+ memset(data + 2, 0, 16);
+ data += data[1];
+ }
+#endif
+
+ packet->length = data - packet->data;
+
+ packet->data[2] = (packet->length >> 8) & 0xff;
+ packet->data[3] = packet->length & 0xff;
+
+ packet->flags |= RS_PACKET_ENCODED;
+
+ return packet->length;
+}
+
+
+/*
+ * Ensure that the nr_data2attr_t structure is filled in
+ * appropriately. This includes filling in a fake DICT_ATTR
+ * structure, if necessary.
+ */
+static int do_callback(void *ctx, nr_packet_walk_func_t callback,
+ int attr, int vendor,
+ const uint8_t *data, size_t sizeof_data)
+
+{
+ int rcode;
+ const DICT_ATTR *da;
+ DICT_ATTR myda;
+ char buffer[64];
+
+ da = nr_dict_attr_byvalue(attr, vendor);
+
+ /*
+ * The attribute is supposed to have a particular length,
+ * but does not. It is therefore malformed.
+ */
+ if (da && (da->flags.length != 0) &&
+ da->flags.length != sizeof_data) {
+ da = NULL;
+ }
+
+ if (!da) {
+ rcode = nr_dict_attr_2struct(&myda, attr, vendor,
+ buffer, sizeof(buffer));
+
+ if (rcode < 0) return rcode;
+ da = &myda;
+ }
+
+ rcode = callback(ctx, da, data, sizeof_data);
+ if (rcode < 0) return rcode;
+
+ return 0;
+}
+
+
+int nr_packet_walk(RADIUS_PACKET *packet, void *ctx,
+ nr_packet_walk_func_t callback)
+{
+ int rcode;
+ uint8_t *attr;
+ const uint8_t *end;
+
+ if (!packet || !callback) return -RSE_INVAL;
+
+ rcode = nr_packet_ok(packet);
+ if (rcode < 0) return rcode;
+
+ end = packet->data + packet->length;
+
+ for (attr = packet->data + 20; attr < end; attr += attr[1]) {
+ int length, value;
+ int dv_type, dv_length;
+ uint32_t vendorpec;
+ const uint8_t *vsa;
+ const DICT_VENDOR *dv = NULL;
+
+ vendorpec = 0;
+ value = attr[0];
+
+ if (value != PW_VENDOR_SPECIFIC) {
+ raw:
+ rcode = do_callback(ctx, callback,
+ attr[0], 0,
+ attr + 2, attr[1] - 2);
+ if (rcode < 0) return rcode;
+ continue;
+ }
+
+ if (attr[1] < 6) goto raw;
+ memcpy(&vendorpec, attr + 2, 4);
+ vendorpec = ntohl(vendorpec);
+
+ if (dv && (dv->vendor != vendorpec)) dv = NULL;
+
+ if (!dv) dv = nr_dict_vendor_byvalue(vendorpec);
+
+ if (dv) {
+ dv_type = dv->type;
+ dv_length = dv->length;
+ } else {
+ dv_type = 1;
+ dv_length = 1;
+ }
+
+ /*
+ * Malformed: it's a raw attribute.
+ */
+ if (nr_tlv_ok(attr + 6, attr[1] - 6, dv_type, dv_length) < 0) {
+ goto raw;
+ }
+
+ for (vsa = attr + 6; vsa < attr + attr[1]; vsa += length) {
+ switch (dv_type) {
+ case 4:
+ value = (vsa[2] << 8) | vsa[3];
+ break;
+
+ case 2:
+ value = (vsa[0] << 8) | vsa[1];
+ break;
+
+ case 1:
+ value = vsa[0];
+ break;
+
+ default:
+ return -RSE_INTERNAL;
+ }
+
+ switch (dv_length) {
+ case 0:
+ length = attr[1] - 6 - dv_type;
+ break;
+
+ case 2:
+ case 1:
+ length = vsa[dv_type + dv_length - 1];
+ break;
+
+ default:
+ return -RSE_INTERNAL;
+ }
+
+ rcode = do_callback(ctx, callback,
+ value, vendorpec,
+ vsa + dv_type + dv_length,
+ length - dv_type - dv_length);
+ if (rcode < 0) return rcode;
+ }
+ }
+
+ return 0;
+}
+
+int nr_packet_init(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
+ const char *secret, int code,
+ void *data, size_t sizeof_data)
+{
+ int rcode;
+
+ if ((code < 0) || (code > RS_MAX_PACKET_CODE)) {
+ return -RSE_INVALID_REQUEST_CODE;
+ }
+
+ if (!data || (sizeof_data < 20)) return -RSE_INVAL;
+
+ memset(packet, 0, sizeof(*packet));
+ packet->secret = secret;
+ packet->sizeof_secret = secret ? strlen(secret) : 0;
+ packet->code = code;
+ packet->id = 0;
+ packet->data = data;
+ packet->sizeof_data = sizeof_data;
+
+ rcode = can_encode_packet(packet, original);
+ if (rcode < 0) return rcode;
+
+ encode_header(packet);
+
+ return 0;
+}
+
+
+static int pack_eap(RADIUS_PACKET *packet,
+ const void *data, size_t data_len)
+{
+ uint8_t *attr, *end;
+ const uint8_t *eap;
+ size_t left;
+
+ eap = data;
+ left = data_len;
+ attr = packet->data + packet->length;
+ end = attr + packet->sizeof_data;
+
+ while (left > 253) {
+ if ((attr + 255) > end) return -RSE_ATTR_OVERFLOW;
+
+ attr[0] = PW_EAP_MESSAGE;
+ attr[1] = 255;
+ memcpy(attr + 2, eap, 253);
+ attr += attr[1];
+ eap += 253;
+ left -= 253;
+ }
+
+ if ((attr + (2 + left)) > end) return -RSE_ATTR_OVERFLOW;
+
+ attr[0] = PW_EAP_MESSAGE;
+ attr[1] = 2 + left;
+ memcpy(attr + 2, eap, left);
+ attr += attr[1];
+ packet->length = attr - packet->data;
+
+ return 0;
+}
+
+ssize_t nr_packet_attr_append(RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const DICT_ATTR *da,
+ const void *data, size_t data_len)
+{
+ ssize_t rcode;
+ uint8_t *attr, *end;
+ VALUE_PAIR my_vp;
+ const VALUE_PAIR *vp;
+
+ if (!packet || !da || !data) {
+ return -RSE_INVAL;
+ }
+
+ if (data_len == 0) {
+ if (da->type != RS_TYPE_STRING) return -RSE_ATTR_TOO_SMALL;
+
+ data_len = strlen(data);
+ }
+
+ /* We're going to mark the whole packet as encoded so we
+ better not have any unencoded value-pairs attached. */
+ if (packet->vps)
+ return -RSE_INVAL;
+ packet->flags |= RS_PACKET_ENCODED;
+
+ attr = packet->data + packet->length;
+ end = attr + packet->sizeof_data;
+
+ if ((attr + 2 + data_len) > end) {
+ return -RSE_ATTR_OVERFLOW;
+ }
+
+ if ((da->flags.length != 0) &&
+ (data_len != da->flags.length)) {
+ return -RSE_ATTR_VALUE_MALFORMED;
+ }
+
+#ifdef PW_EAP_MESSAGE
+ /*
+ * automatically split EAP-Message into multiple
+ * attributes.
+ */
+ if (!da->vendor && (da->attr == PW_EAP_MESSAGE) && (data_len > 253)) {
+ return pack_eap(packet, data, data_len);
+ }
+#endif
+
+ if (data_len > 253) return -RSE_ATTR_TOO_LARGE;
+
+ vp = nr_vp_init(&my_vp, da);
+ rcode = nr_vp_set_data(&my_vp, data, data_len);
+ if (rcode < 0) return rcode;
+
+ /*
+ * Note that this function packs VSAs each into their own
+ * Vendor-Specific attribute. If this isn't what you
+ * want, use the version of the library with full support
+ * for TLVs, WiMAX, and extended attributes.
+ */
+ rcode = nr_vp2attr(packet, original, &vp, attr, end - attr);
+ if (rcode <= 0) return rcode;
+
+ packet->length += rcode;
+
+ return rcode;
+}
diff --git a/radius/share/dictionary.abfab.ietf b/radius/share/dictionary.abfab.ietf
new file mode 100644
index 0000000..b60702c
--- /dev/null
+++ b/radius/share/dictionary.abfab.ietf
@@ -0,0 +1,4 @@
+ATTRIBUTE GSS-Acceptor-Service-Name 164 string
+ATTRIBUTE GSS-Acceptor-Host-Name 165 string
+ATTRIBUTE GSS-Acceptor-Service-Specifics 166 string
+ATTRIBUTE GSS-Acceptor-Realm-Name 167 string
diff --git a/radius/share/dictionary.juniper b/radius/share/dictionary.juniper
new file mode 100644
index 0000000..9aa5df4
--- /dev/null
+++ b/radius/share/dictionary.juniper
@@ -0,0 +1,23 @@
+# -*- text -*-
+#
+# dictionary.juniper
+#
+# As posted to the list by Eric Kilfoil <ekilfoil@uslec.net>
+#
+# Version: $Id$
+#
+
+VENDOR Juniper 2636
+
+BEGIN-VENDOR Juniper
+
+ATTRIBUTE Juniper-Local-User-Name 1 string
+ATTRIBUTE Juniper-Allow-Commands 2 string
+ATTRIBUTE Juniper-Deny-Commands 3 string
+ATTRIBUTE Juniper-Allow-Configuration 4 string
+ATTRIBUTE Juniper-Deny-Configuration 5 string
+ATTRIBUTE Juniper-Interactive-Command 8 string
+ATTRIBUTE Juniper-Configuration-Change 9 string
+ATTRIBUTE Juniper-User-Permissions 10 string
+
+END-VENDOR Juniper
diff --git a/radius/share/dictionary.microsoft b/radius/share/dictionary.microsoft
new file mode 100644
index 0000000..034e5f0
--- /dev/null
+++ b/radius/share/dictionary.microsoft
@@ -0,0 +1,17 @@
+# A minimal dictionary for Microsoft VSAs
+#
+VENDOR Microsoft 311
+
+BEGIN-VENDOR Microsoft
+ATTRIBUTE MS-CHAP-Response 1 octets
+ATTRIBUTE MS-CHAP-Error 2 string
+ATTRIBUTE MS-MPPE-Encryption-Policy 7 octets
+ATTRIBUTE MS-MPPE-Encryption-Types 8 octets
+ATTRIBUTE MS-CHAP-Domain 10 string
+ATTRIBUTE MS-CHAP-Challenge 11 octets
+ATTRIBUTE MS-CHAP-MPPE-Keys 12 octets encrypt=1
+ATTRIBUTE MS-MPPE-Send-Key 16 octets encrypt=2
+ATTRIBUTE MS-MPPE-Recv-Key 17 octets encrypt=2
+ATTRIBUTE MS-CHAP2-Response 25 octets
+ATTRIBUTE MS-CHAP2-Success 26 octets
+END-VENDOR Microsoft
diff --git a/radius/share/dictionary.txt b/radius/share/dictionary.txt
new file mode 100644
index 0000000..e62f8b3
--- /dev/null
+++ b/radius/share/dictionary.txt
@@ -0,0 +1,136 @@
+ATTRIBUTE User-Name 1 string
+ATTRIBUTE User-Password 2 string encrypt=1
+ATTRIBUTE CHAP-Password 3 octets
+ATTRIBUTE NAS-IP-Address 4 ipaddr
+ATTRIBUTE NAS-Port 5 integer
+ATTRIBUTE Service-Type 6 integer
+ATTRIBUTE Framed-Protocol 7 integer
+ATTRIBUTE Framed-IP-Address 8 ipaddr
+ATTRIBUTE Framed-IP-Netmask 9 ipaddr
+ATTRIBUTE Framed-Routing 10 integer
+ATTRIBUTE Filter-Id 11 string
+ATTRIBUTE Framed-MTU 12 integer
+ATTRIBUTE Framed-Compression 13 integer
+ATTRIBUTE Login-IP-Host 14 ipaddr
+ATTRIBUTE Login-Service 15 integer
+ATTRIBUTE Login-TCP-Port 16 integer
+ATTRIBUTE Reply-Message 18 string
+ATTRIBUTE Callback-Number 19 string
+ATTRIBUTE Callback-Id 20 string
+ATTRIBUTE Framed-Route 22 string
+ATTRIBUTE Framed-IPX-Network 23 ipaddr
+ATTRIBUTE State 24 octets
+ATTRIBUTE Class 25 octets
+ATTRIBUTE Vendor-Specific 26 octets
+ATTRIBUTE Session-Timeout 27 integer
+ATTRIBUTE Idle-Timeout 28 integer
+ATTRIBUTE Termination-Action 29 integer
+ATTRIBUTE Called-Station-Id 30 string
+ATTRIBUTE Calling-Station-Id 31 string
+ATTRIBUTE NAS-Identifier 32 string
+ATTRIBUTE Proxy-State 33 octets
+ATTRIBUTE Login-LAT-Service 34 string
+ATTRIBUTE Login-LAT-Node 35 string
+ATTRIBUTE Login-LAT-Group 36 octets
+ATTRIBUTE Framed-AppleTalk-Link 37 integer
+ATTRIBUTE Framed-AppleTalk-Network 38 integer
+ATTRIBUTE Framed-AppleTalk-Zone 39 string
+ATTRIBUTE CHAP-Challenge 60 octets
+ATTRIBUTE NAS-Port-Type 61 integer
+ATTRIBUTE Port-Limit 62 integer
+ATTRIBUTE Login-LAT-Port 63 string
+ATTRIBUTE Acct-Status-Type 40 integer
+ATTRIBUTE Acct-Delay-Time 41 integer
+ATTRIBUTE Acct-Input-Octets 42 integer
+ATTRIBUTE Acct-Output-Octets 43 integer
+ATTRIBUTE Acct-Session-Id 44 string
+ATTRIBUTE Acct-Authentic 45 integer
+ATTRIBUTE Acct-Session-Time 46 integer
+ATTRIBUTE Acct-Input-Packets 47 integer
+ATTRIBUTE Acct-Output-Packets 48 integer
+ATTRIBUTE Acct-Terminate-Cause 49 integer
+ATTRIBUTE Acct-Multi-Session-Id 50 string
+ATTRIBUTE Acct-Link-Count 51 integer
+ATTRIBUTE Acct-Tunnel-Connection 68 string
+ATTRIBUTE Acct-Tunnel-Packets-Lost 86 integer
+ATTRIBUTE Tunnel-Type 64 integer has_tag
+ATTRIBUTE Tunnel-Medium-Type 65 integer has_tag
+ATTRIBUTE Tunnel-Client-Endpoint 66 string has_tag
+ATTRIBUTE Tunnel-Server-Endpoint 67 string has_tag
+ATTRIBUTE Tunnel-Password 69 string has_tag,encrypt=2
+ATTRIBUTE Tunnel-Private-Group-Id 81 string has_tag
+ATTRIBUTE Tunnel-Assignment-Id 82 string has_tag
+ATTRIBUTE Tunnel-Preference 83 integer has_tag
+ATTRIBUTE Tunnel-Client-Auth-Id 90 string has_tag
+ATTRIBUTE Tunnel-Server-Auth-Id 91 string has_tag
+ATTRIBUTE Acct-Input-Gigawords 52 integer
+ATTRIBUTE Acct-Output-Gigawords 53 integer
+ATTRIBUTE Event-Timestamp 55 date
+ATTRIBUTE ARAP-Password 70 octets[16]
+ATTRIBUTE ARAP-Features 71 octets[14]
+ATTRIBUTE ARAP-Zone-Access 72 integer
+ATTRIBUTE ARAP-Security 73 integer
+ATTRIBUTE ARAP-Security-Data 74 string
+ATTRIBUTE Password-Retry 75 integer
+ATTRIBUTE Prompt 76 integer
+ATTRIBUTE Connect-Info 77 string
+ATTRIBUTE Configuration-Token 78 string
+ATTRIBUTE EAP-Message 79 octets
+ATTRIBUTE Message-Authenticator 80 octets
+ATTRIBUTE ARAP-Challenge-Response 84 octets[8]
+ATTRIBUTE Acct-Interim-Interval 85 integer
+ATTRIBUTE NAS-Port-Id 87 string
+ATTRIBUTE Framed-Pool 88 string
+ATTRIBUTE NAS-IPv6-Address 95 ipv6addr
+ATTRIBUTE Framed-Interface-Id 96 ifid
+ATTRIBUTE Framed-IPv6-Prefix 97 ipv6prefix
+ATTRIBUTE Login-IPv6-Host 98 ipv6addr
+ATTRIBUTE Framed-IPv6-Route 99 string
+ATTRIBUTE Framed-IPv6-Pool 100 string
+ATTRIBUTE Error-Cause 101 integer
+ATTRIBUTE EAP-Key-Name 102 string
+ATTRIBUTE Chargeable-User-Identity 89 string
+ATTRIBUTE Egress-VLANID 56 integer
+ATTRIBUTE Ingress-Filters 57 integer
+ATTRIBUTE Egress-VLAN-Name 58 string
+ATTRIBUTE User-Priority-Table 59 octets
+ATTRIBUTE Delegated-IPv6-Prefix 123 ipv6prefix
+ATTRIBUTE NAS-Filter-Rule 92 string
+ATTRIBUTE Digest-Response 103 string
+ATTRIBUTE Digest-Realm 104 string
+ATTRIBUTE Digest-Nonce 105 string
+ATTRIBUTE Digest-Response-Auth 106 string
+ATTRIBUTE Digest-Nextnonce 107 string
+ATTRIBUTE Digest-Method 108 string
+ATTRIBUTE Digest-URI 109 string
+ATTRIBUTE Digest-Qop 110 string
+ATTRIBUTE Digest-Algorithm 111 string
+ATTRIBUTE Digest-Entity-Body-Hash 112 string
+ATTRIBUTE Digest-CNonce 113 string
+ATTRIBUTE Digest-Nonce-Count 114 string
+ATTRIBUTE Digest-Username 115 string
+ATTRIBUTE Digest-Opaque 116 string
+ATTRIBUTE Digest-Auth-Param 117 string
+ATTRIBUTE Digest-AKA-Auts 118 string
+ATTRIBUTE Digest-Domain 119 string
+ATTRIBUTE Digest-Stale 120 string
+ATTRIBUTE Digest-HA1 121 string
+ATTRIBUTE SIP-AOR 122 string
+ATTRIBUTE Operator-Name 126 string
+ATTRIBUTE Location-Information 127 octets
+ATTRIBUTE Location-Data 128 octets
+ATTRIBUTE Basic-Location-Policy-Rules 129 octets
+ATTRIBUTE Extended-Location-Policy-Rules 130 octets
+ATTRIBUTE Location-Capable 131 integer
+ATTRIBUTE Requested-Location-Info 132 integer
+ATTRIBUTE Framed-Management 133 integer
+ATTRIBUTE Management-Transport-Protection 134 integer
+ATTRIBUTE Management-Policy-Id 135 string
+ATTRIBUTE Management-Privilege-Level 136 integer
+ATTRIBUTE PKM-SS-Cert 137 octets
+ATTRIBUTE PKM-CA-Cert 138 octets
+ATTRIBUTE PKM-Config-Settings 139 octets
+ATTRIBUTE PKM-Cryptosuite-List 140 octets
+ATTRIBUTE PKM-SAID 141 short
+ATTRIBUTE PKM-SA-Descriptor 142 octets
+ATTRIBUTE PKM-Auth-Key 143 octets
diff --git a/radius/share/dictionary.ukerna b/radius/share/dictionary.ukerna
new file mode 100644
index 0000000..7d9d22d
--- /dev/null
+++ b/radius/share/dictionary.ukerna
@@ -0,0 +1,20 @@
+# -*- text -*-
+#
+# GSS-EAP VSAs
+#
+# $Id$
+#
+
+VENDOR UKERNA 25622
+
+BEGIN-VENDOR UKERNA
+
+ATTRIBUTE GSS-Acceptor-Service-Name-VS 128 string
+ATTRIBUTE GSS-Acceptor-Host-Name-VS 129 string
+ATTRIBUTE GSS-Acceptor-Service-Specific-VS 130 string
+ATTRIBUTE GSS-Acceptor-Realm-Name-VS 131 string
+ATTRIBUTE SAML-AAA-Assertion 132 string
+ATTRIBUTE MS-Windows-Auth-Data 133 octets
+ATTRIBUTE MS-Windows-Group-Sid 134 string
+
+END-VENDOR UKERNA
diff --git a/radius/static.c b/radius/static.c
new file mode 100644
index 0000000..bd87272
--- /dev/null
+++ b/radius/static.c
@@ -0,0 +1,37 @@
+/*
+Copyright (c) 2011, Network RADIUS SARL
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file static.c
+ * \brief Dummy file to include auto-generating static dictionary mappings.
+ */
+
+#include "client.h"
+
+/*
+ * Include the dynamically generated dictionaries.
+ */
+#include "dictionaries.c"
diff --git a/radius/valuepair.c b/radius/valuepair.c
new file mode 100644
index 0000000..6277f7d
--- /dev/null
+++ b/radius/valuepair.c
@@ -0,0 +1,191 @@
+/*
+Copyright (c) 2011, Network RADIUS SARL
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file valuepair.c
+ * \brief Functions to manipulate C structure versions of RADIUS attributes.
+ */
+
+#include "client.h"
+
+void nr_vp_free(VALUE_PAIR **head)
+{
+ VALUE_PAIR *next, *vp;
+
+ for (vp = *head; vp != NULL; vp = next) {
+ next = vp->next;
+ if (vp->da->flags.encrypt) {
+ memset(vp, 0, sizeof(vp));
+ }
+ free(vp);
+ }
+
+ *head = NULL;
+}
+
+
+VALUE_PAIR *nr_vp_init(VALUE_PAIR *vp, const DICT_ATTR *da)
+{
+ memset(vp, 0, sizeof(*vp));
+
+ vp->da = da;
+ vp->length = da->flags.length;
+
+ return vp;
+}
+
+
+VALUE_PAIR *nr_vp_alloc(const DICT_ATTR *da)
+{
+ VALUE_PAIR *vp = NULL;
+
+ if (!da) {
+ nr_strerror_printf("Unknown attribute");
+ return NULL;
+ }
+
+ vp = malloc(sizeof(*vp));
+ if (!vp) {
+ nr_strerror_printf("Out of memory");
+ return NULL;
+ }
+
+ return nr_vp_init(vp, da);
+}
+
+VALUE_PAIR *nr_vp_alloc_raw(unsigned int attr, unsigned int vendor)
+{
+ VALUE_PAIR *vp = NULL;
+ DICT_ATTR *da;
+
+ vp = malloc(sizeof(*vp) + sizeof(*da) + 64);
+ if (!vp) {
+ nr_strerror_printf("Out of memory");
+ return NULL;
+ }
+ memset(vp, 0, sizeof(*vp));
+
+ da = (DICT_ATTR *) (vp + 1);
+
+ if (nr_dict_attr_2struct(da, attr, vendor, (char *) (da + 1), 64) < 0) {
+ free(vp);
+ return NULL;
+ }
+
+ vp->da = da;
+
+ return vp;
+}
+
+int nr_vp_set_data(VALUE_PAIR *vp, const void *data, size_t sizeof_data)
+{
+ int rcode = 1; /* OK */
+
+ if (!vp || !data || (sizeof_data == 0)) return -RSE_INVAL;
+
+ switch (vp->da->type) {
+ case RS_TYPE_BYTE:
+ vp->vp_integer = *(const uint8_t *) data;
+ break;
+
+ case RS_TYPE_SHORT:
+ vp->vp_integer = *(const uint16_t *) data;
+ break;
+
+ case RS_TYPE_INTEGER:
+ case RS_TYPE_DATE:
+ case RS_TYPE_IPADDR:
+ vp->vp_integer = *(const uint32_t *) data;
+ break;
+
+ case RS_TYPE_STRING:
+ if (sizeof_data >= sizeof(vp->vp_strvalue)) {
+ sizeof_data = sizeof(vp->vp_strvalue) - 1;
+ rcode = 0; /* truncated */
+ }
+
+ memcpy(vp->vp_strvalue, (const char *) data, sizeof_data);
+ vp->vp_strvalue[sizeof_data + 1] = '\0';
+ vp->length = sizeof_data;
+ break;
+
+ case RS_TYPE_OCTETS:
+ if (sizeof_data > sizeof(vp->vp_octets)) {
+ sizeof_data = sizeof(vp->vp_octets);
+ rcode = 0; /* truncated */
+ }
+ memcpy(vp->vp_octets, data, sizeof_data);
+ vp->length = sizeof_data;
+ break;
+
+ default:
+ return -RSE_ATTR_TYPE_UNKNOWN;
+ }
+
+ return rcode;
+}
+
+VALUE_PAIR *nr_vp_create(int attr, int vendor, const void *data, size_t data_len)
+{
+ const DICT_ATTR *da;
+ VALUE_PAIR *vp;
+
+ da = nr_dict_attr_byvalue(attr, vendor);
+ if (!da) return NULL;
+
+ vp = nr_vp_alloc(da);
+ if (!vp) return NULL;
+
+ if (nr_vp_set_data(vp, data, data_len) < 0) {
+ nr_vp_free(&vp);
+ return NULL;
+ }
+
+ return vp;
+}
+
+void nr_vps_append(VALUE_PAIR **head, VALUE_PAIR *tail)
+{
+ if (!tail) return;
+
+ while (*head) {
+ head = &((*head)->next);
+ }
+
+ *head = tail;
+}
+
+VALUE_PAIR *nr_vps_find(VALUE_PAIR *head,
+ unsigned int attr, unsigned int vendor)
+{
+ while (head) {
+ if ((head->da->attr == attr) &&
+ (head->da->vendor == vendor)) return head;
+ head = head->next;
+ }
+
+ return NULL;
+}