[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Bug-gnu-radius] Sybase and SecurID patch for GNU RADIUS 0.96.2
From: |
Steve Bleazard |
Subject: |
[Bug-gnu-radius] Sybase and SecurID patch for GNU RADIUS 0.96.2 |
Date: |
Mon, 10 Jun 2002 20:47:51 +0100 |
Hi
Attached are the context diffs to add SecurID and Sybase support to GNU
RADIUS 0.96.2. The patch.README file contains the details of the
changes and the patch.sybase is a context diff file
Please let me know if there are any problems and I will try try to
resolve them.
Steve
patch.README
Description: application/unknown-content-type-readme_auto_file
diff -N -r -u gnuradius-0.96.2.orig/README gnuradius-0.96.2/README
--- gnuradius-0.96.2.orig/README Tue Mar 19 22:31:59 2002
+++ gnuradius-0.96.2/README Thu Jun 6 21:51:44 2002
@@ -48,10 +48,88 @@
--enable-pam
Enable PAM support.
+ --enable-securid
+ Enable SecurID support. This option automatically detects libaceclnt.a
+ first and then falls back to sdiclient.a. However, on OS's that
+ require a lib prefix to recognise a library it may be necessary to
+ ln -s sdiclient.a libsdiclient.a before running configure. In
+ addition it may be necessary to set --with-lib-path and
+ --with-include-path to include the directory containing the Ace
+ client libraries.
+
+ SecurID Inc / RSA have a number of versions of the client library:
+ Version prior to 3.x where called sdiclient.a and supported basic
+ synchronous authentication. Version 3.x and 4.x were shipped with
+ both sdiclient.a and an additional libaceclnt.a library that supported
+ asynchronous (multithreaded) operation.
+
+ From 5.x onwards the two libaries were combined into a single
+ libaceclnt.a and (on Solaris and maybe others) a shared version called
+ libaceclnt.so. These versions also supports all version of the
+ Ace/Server from 3.3.1. The 5.x library can be downloaded for free
+ from RSA's web site. However, access to this may require SecurCare
+ Online to have been purchased. For 5.02 of the library the file is
+ called Agentsdk_502.zip
+
+ With the release of the asynchronous library it was possible to pass
+ the client IP address so that authentication proxies (such as RADIUS)
+ could have the Ace/Server perform client authorisation for the
+ original client and not the proxy.
+
+ Unfortunately the asychronous libraries are tricky to work with,
+ requiring threads programming that can be hard to make portable.
+ However, with the introduction of the 5.x client library a new set
+ of sychronous client functions has been added and it is now easy
+ to pass the client ip address to the Ace/Server.
+
+ As a consquence support for passing the client address to the
+ Ace/Server is only available with version 5.x and later of the
+ libraries.
+
+ The code has been tested with 3.3.1 and 5.02 libraries against a
+ 4.1 ACE/Server. However, experience shows that all libraries after
+ 2.3 (and possibly earlier) work with ACE/Server 2.3 onwards. The
+ reverse (where the library is newer than the server) may not be the
+ case except with 5.02 and (presumably) later version.
+
+ --enable-securid-resend-hack
+ Enable code to prevent duplicate request from disabling a users token.
+ SecurID and the RADIUS retry timeouts can interact very badly and cause
+ the users token to be disabled. This code attempts to fix the problem.
+
+ The problem is caused by the SecurID server inserting, by design, a
+ configurable 1 second delay before replying. Unfortunately, this is
+ very similar to a common NAS retry timeout of around 1 second. As a
+ consequence the request is often retried.
+
+ Unfortunately with some NASes the resent packet is different enough to
+ make it difficult to spot that it is infact a resend and the request
+ is passed to the backend authentication code.
+
+ At this point the SecurID server is sent the same passcode again and
+ detects a simultaneous login. After a couple of login attempts the
+ users account is disabled.
+
+ The code added by this option detects these duplicate requests using
+ the username, passcode and NAS ip. Any request that received within
+ auth request-cleanup-delay seconds (see the config file auth statement)
+ are treated as resends and replied to in the same way as previously.
+
+ Note that the ACE/Server delay should be set to 1 second (the default).
+ Any longer and the code is unlikely to work with resend timouts of a
+ second.
+
--enable-dbm[={dbm|ndbm}]
Enable dbm support. If no argument is specified, usual DBM is
assumed. The `ndbm' argument instructs to enable support of NDBM.
+ --enable-nas-ip-hack
+ Enable adding of missing NAS-IP-Address attribute. Some devices do
+ not include the NAS-IP-Address attribute in the request. This can
+ make NAS based access control difficult if not impossibe. Enabling
+ this option includes code to add the NAS-IP-Address attribute with the
+ source address of the request if it's missing
+
--with-sql
Enable MySQL support. Usually this requires adding appropriate
--with-lib-path and --with-include-path options.
@@ -60,6 +138,14 @@
Enable PostgreSQL support. Usually this requires adding appropriate
--with-lib-path and --with-include-path options.
+ --with-sybase
+ Enable Sybase support. Usually this requires adding appropriate
+ --with-lib-path and --with-include-path options. Note that with
+ Sybase the SYBASE environment variable must be set appropriately
+ before running the server. In addition, the name specified in the sql
+ server parameter must have an entry in the interfaces file and the
+ port option is ignored.
+
--with-odbc[={odbc|iodbc}]
Configure to work with ODBC. This is an experimental feature, it
has not been tested thoroughly.
diff -N -r -u gnuradius-0.96.2.orig/acconfig.h gnuradius-0.96.2/acconfig.h
--- gnuradius-0.96.2.orig/acconfig.h Tue Mar 19 22:31:59 2002
+++ gnuradius-0.96.2/acconfig.h Thu Jun 6 14:03:17 2002
@@ -67,12 +67,16 @@
#undef HAVE_LIBPAM
+#undef HAVE_LIBSECURID
+
#undef HAVE_LIBMYSQL
#undef HAVE_LIBPQ
#undef HAVE_LIBODBC
+#undef HAVE_LIBSYBASE
+
/* Define this to disable shadow support */
#undef PWD_SHADOW
@@ -101,6 +105,9 @@
/* Define this to enable ODBC subsystem of SQL support */
#undef USE_SQL_ODBC
+/* Define this to enable Sybase subsystem of SQL support */
+#undef USE_SQL_SYBASE
+
/* Define this to enable Livingston-compatible menus */
#undef USE_LIVINGSTON_MENUS
@@ -110,6 +117,18 @@
/* Define this to enable PAM support */
#undef USE_PAM
+
+/* Define this to enable SecurID support */
+#undef USE_SECURID
+
+/* Define this to enable SecurID legacy function support */
+#undef USE_SECURID_LEGACY
+
+/* Define this to enable SecurID resend detection */
+#undef USE_SECURID_RESEND_HACK
+
+/* Define this to enable NAS IP address adding code */
+#undef USE_NAS_IP_HACK
/* Define this if you wish the DBM support */
#undef USE_DBM
diff -N -r -u gnuradius-0.96.2.orig/aclocal.m4 gnuradius-0.96.2/aclocal.m4
--- gnuradius-0.96.2.orig/aclocal.m4 Wed Mar 20 18:34:16 2002
+++ gnuradius-0.96.2/aclocal.m4 Mon May 27 17:47:39 2002
@@ -4035,7 +4035,7 @@
do
LIBS="$save_LIBS -L$path"
AC_CHECK_LIB($1, $2,
- [rad_cv_lib_$1="$3 -L$path -l$1"
+ [rad_cv_lib_$1="-L$path -l$1 $3"
break],
[rad_cv_lib_$1=no],$3)
done
diff -N -r -u gnuradius-0.96.2.orig/config.h.in gnuradius-0.96.2/config.h.in
--- gnuradius-0.96.2.orig/config.h.in Wed Mar 20 18:20:35 2002
+++ gnuradius-0.96.2/config.h.in Thu Jun 6 14:03:17 2002
@@ -273,12 +273,16 @@
#undef HAVE_LIBPAM
+#undef HAVE_LIBSECURID
+
#undef HAVE_LIBMYSQL
#undef HAVE_LIBPQ
#undef HAVE_LIBODBC
+#undef HAVE_LIBSYBASE
+
/* Define this to disable shadow support */
#undef PWD_SHADOW
@@ -307,6 +311,9 @@
/* Define this to enable ODBC subsystem of SQL support */
#undef USE_SQL_ODBC
+/* Define this to enable Sybase subsystem of SQL support */
+#undef USE_SQL_SYBASE
+
/* Define this to enable Livingston-compatible menus */
#undef USE_LIVINGSTON_MENUS
@@ -316,6 +323,18 @@
/* Define this to enable PAM support */
#undef USE_PAM
+
+/* Define this to enable SecurID support */
+#undef USE_SECURID
+
+/* Define this to enable legacy SecurID support */
+#undef USE_SECURID_LEGACY
+
+/* Define this to enable SecurID resend detection */
+#undef USE_SECURID_RESEND_HACK
+
+/* Define this to enable NAS IP address adding code */
+#undef USE_NAS_IP_HACK
/* Define this if you wish the DBM support */
#undef USE_DBM
diff -N -r -u gnuradius-0.96.2.orig/configure.in gnuradius-0.96.2/configure.in
--- gnuradius-0.96.2.orig/configure.in Tue Mar 19 23:32:38 2002
+++ gnuradius-0.96.2/configure.in Thu Jun 6 14:03:17 2002
@@ -316,6 +316,76 @@
exit 1])
fi
+## **************
+## SecurID support
+## **************
+
+AC_ARG_ENABLE(securid,
+ [ --enable-securid enable securid support],
+ [case $enableval in
+ yes) USE_SECURID=yes; AC_DEFINE(USE_SECURID);;
+ no) ;;
+ *) AC_MSG_ERROR(--enable-securid can't be used
with an argument)
+ exit 1;;
+ esac])
+
+AC_ARG_ENABLE(securid-resend-hack,
+ [ --enable-securid-resend-hack enable securid resend
detection],
+ [case $enableval in
+ yes) USE_SECURID_RESEND_HACK=yes;
+ AC_DEFINE(USE_SECURID_RESEND_HACK);;
+ no) ;;
+ *) AC_MSG_ERROR(--enable-securid-resend-hack can't
be used with an argument)
+ exit 1;;
+ esac])
+
+if test x$USE_SECURID = xyes; then
+ HAVE_ACECLNT=no
+ HAVE_SDICLIENT=no
+ AC_CHECK_LIB(aceclnt, SD_Init,
+ [ AC_DEFINE(HAVE_LIBSECURID)
+ HAVE_ACECLNT=yes
+ HAVE_ACE=yes
+ RADIUSD_LDADD="$RADIUSD_LDADD -laceclnt" ])
+
+ if test x$HAVE_ACECLNT = xno; then
+ save_LIBS=$LIBS
+ LIBS="-lsdiclient $LIBS"
+ AC_TRY_RUN([char configure; tst(){creadcfg();}main(){exit(0);}],
+ [ HAVE_SDICLIENT=yes
+ HAVE_ACE=yes
+ AC_DEFINE(USE_SECURID_LEGACY)
+ RADIUSD_LDADD="$RADIUSD_LDADD -lsdiclient"],
+ [ AC_MSG_ERROR(can't find aceclnt or sdiclient
libraries - have you linked sdiclient.a to libsdiclient.a)],
+ [ HAVE_SDICLIENT=yes
+ AC_DEFINE(USE_SECURID_LEGACY)
+ RADIUSD_LDADD="$RADIUSD_LDADD -lsdiclient"])
+ LIBS=$save_LIBS
+ fi
+ if test x$HAVE_ACECLNT = xyes; then
+ AC_TRY_CPP(acexport.h,,
+ [ AC_MSG_ERROR(can't find header acexport.h)
+ exit 0] )
+ fi
+ if test x$HAVE_SDICLIENT = xyes; then
+ AC_TRY_CPP(sdi_athd.h,,
+ [ AC_MSG_ERROR(can't find header sdi_athd.h)
+ exit 0] )
+ fi
+ if test x$HAVE_ACE = xyes; then
+ if test x$USE_SECURID_RESEND_HACK = xyes; then
+ AC_CHECK_HEADER(ndbm.h,,
+ [ AC_MSG_ERROR(can't find header ndbm.h
- ndbm is required by SecurID)
+ exit 0] )
+ AC_CHECK_FUNC(dbm_open,,
+ AC_CHECK_LIB(ndbm, dbm_open,
+ [ AC_DEFINE(HAVE_LIBNDBM)
+ RADIUSD_LDADD="$RADIUSD_LDADD -lndbm" ],
+ [ AC_MSG_ERROR(-lndbm not found - ndbm is
required by SecurID) ]))
+ fi
+ fi
+fi
+
## **************
## DBM
@@ -395,6 +465,20 @@
no) ;;
esac])
+AC_ARG_WITH(sybase,
+ [ --with-sybase Configure to work with Sybase],
+ [case $withval in
+ yes) rad_CHECK_LIB(ct, ct_init, [-lcs -ltcl -lcomn],
+ [ USE_SQL=1
+ AC_DEFINE(USE_SQL_SYBASE)
+ AC_DEFINE(HAVE_LIBSYBASE)
+ RADIUSD_LDADD="$RADIUSD_LDADD $rad_cv_lib_ct" ],
+ [ AC_MSG_ERROR(-lct not found) ],
+ [/usr/sybase/lib])
+ ;;
+ no) ;;
+ esac])
+
rad_lib_odbc() {
rad_CHECK_LIB(odbc, SQLAllocHandle, [],
[ USE_SQL=1
@@ -483,6 +567,21 @@
;;
no) ;;
*) AC_MSG_ERROR(--enable-snmp can't be used with
an argument)
+ exit 1;;
+ esac])
+
+## **************
+## NAS_IP_HACK
+## **************
+
+AC_ARG_ENABLE(nas-ip-hack,
+ [ --enable-nas-ip-hack enable NAS IP Hack support],
+ [case $enableval in
+ yes) USE_NAS_IP_HACK=yes
+ AC_DEFINE(USE_NAS_IP_HACK)
+ ;;
+ no) ;;
+ *) AC_MSG_ERROR(--enable-nas-ip-hack can't be used
with an argument)
exit 1;;
esac])
diff -N -r -u gnuradius-0.96.2.orig/doc/texinfo/configure.texi
gnuradius-0.96.2/doc/texinfo/configure.texi
--- gnuradius-0.96.2.orig/doc/texinfo/configure.texi Tue Mar 19 22:31:59 2002
+++ gnuradius-0.96.2/doc/texinfo/configure.texi Thu Jun 6 21:56:28 2002
@@ -86,6 +86,7 @@
* acct:: Configure accounting service.
* proxy:: Configure proxy service.
* usedbm:: Enable the DBM feature.
+* aceclientip:: Enable the DBM feature.
* snmp:: Configure SNMP service.
* guile:: Configure Guile interface.
* message:: Configure server reply messages.
@@ -566,6 +567,33 @@
@end table
@comment **L3***************************************************************
address@hidden aceclientip
address@hidden @code{aceclientip} statement
address@hidden Ace: enabling
address@hidden Enabling Ace Client IP
address@hidden aceclientip
+
address@hidden Syntax:
address@hidden
+aceclientip ( yes | no ) ;
address@hidden example
+
address@hidden Usage
+The @code{aceclientip} statement determines whether the the NAS' IP address
+is passed to the Ace/Server or the IP address of the RADIUS server itself.
+
address@hidden @code
address@hidden no
+The IP address of the RADIUS server will be passed to the Ace/Server. As a
+consequence the Ace/Server will see the RADIUS server as the client.
+
address@hidden yes
+The IP address of the original NAS server will be passed to the Ace/Server.
+As a consequence the Ace/Server will see each NAS as a seperate client.
+
address@hidden table
+
address@hidden
**L3***************************************************************
@node snmp
@subsection @code{snmp} statement
@cindex SNMP service parameters
@@ -1555,11 +1583,12 @@
@table @code
@item interface @var{iface-type}
Specifies the @sc{sql} interface to use. Currently supported values
-for @var{iface-type} are @code{mysql} and @code{postgres}. Depending
-on this, the default communication port number is set: it is 3306 for
+for @var{iface-type} are @code{mysql}, @code{sybase} and @code{postgres}.
+Depending on this, the default communication port number is set: it is 3306 for
@code{interface mysql} and 5432 for @code{interface postgres}. Use of
this statement is only meaningful when the package was configured with
-both @option{--with-mysql} and @option{--with-postgres} option.
+a combination of @option{--with-mysql}, @option{--with-sybase} and
address@hidden option.
@item server @var{string}
Specifies the hostname or @IP{} of the @sc{sql} server.
@item port @var{number}
diff -N -r -u gnuradius-0.96.2.orig/include/debugmod.h
gnuradius-0.96.2/include/debugmod.h
--- gnuradius-0.96.2.orig/include/debugmod.h Tue Mar 19 22:32:00 2002
+++ gnuradius-0.96.2/include/debugmod.h Fri May 24 13:17:29 2002
@@ -61,3 +61,6 @@
#ifdef RADIUS_MODULE_GRAM
# define RADIUS_MODULE 5
#endif
+#ifdef RADIUS_MODULE_SECURID_C
+# define RADIUS_MODULE 20
+#endif
diff -N -r -u gnuradius-0.96.2.orig/include/radiusd.h
gnuradius-0.96.2/include/radiusd.h
--- gnuradius-0.96.2.orig/include/radiusd.h Tue Mar 19 22:32:00 2002
+++ gnuradius-0.96.2/include/radiusd.h Tue Jun 4 17:25:20 2002
@@ -238,6 +238,7 @@
extern UINT4 warning_seconds;
extern int radius_pid;
extern int use_dbm;
+extern int ace_client_ip;
extern UINT4 myip;
extern UINT4 warning_seconds;
extern int auth_port;
@@ -319,6 +320,12 @@
#ifdef USE_PAM
int pam_pass(char *name, char *passwd, const char *pamauth, char **reply_msg);
# define PAM_DEFAULT_TYPE "radius"
+#endif
+
+/* securid.c */
+#ifdef USE_SECURID
+int securid_pass(char *name, char *passcode, char **reply_msg,
+ RADIUS_REQ *radreq);
#endif
/* proxy.c */
diff -N -r -u gnuradius-0.96.2.orig/include/radsql.h
gnuradius-0.96.2/include/radsql.h
--- gnuradius-0.96.2.orig/include/radsql.h Tue Mar 19 22:32:00 2002
+++ gnuradius-0.96.2/include/radsql.h Mon May 27 17:18:25 2002
@@ -19,7 +19,8 @@
#define SQLT_MYSQL 1
#define SQLT_POSTGRES 2
#define SQLT_ODBC 3
-#define SQLT_MAX 4
+#define SQLT_SYBASE 4
+#define SQLT_MAX 5
#ifdef USE_SQL
@@ -115,6 +116,11 @@
extern SQL_DISPATCH_TAB odbc_dispatch_tab[];
#else
#define odbc_dispatch_tab NULL
+#endif
+#ifdef USE_SQL_SYBASE
+extern SQL_DISPATCH_TAB sybase_dispatch_tab[];
+#else
+#define sybase_dispatch_tab NULL
#endif
#else
diff -N -r -u gnuradius-0.96.2.orig/m4/lib.m4 gnuradius-0.96.2/m4/lib.m4
--- gnuradius-0.96.2.orig/m4/lib.m4 Tue Mar 19 22:32:00 2002
+++ gnuradius-0.96.2/m4/lib.m4 Fri Jun 7 17:52:30 2002
@@ -14,7 +14,7 @@
do
LIBS="$save_LIBS -L$path"
AC_CHECK_LIB($1, $2,
- [rad_cv_lib_$1="$3 -L$path -l$1"
+ [rad_cv_lib_$1="-L$path -l$1 $3"
break],
[rad_cv_lib_$1=no],$3)
done
diff -N -r -u gnuradius-0.96.2.orig/radiusd/Makefile.am
gnuradius-0.96.2/radiusd/Makefile.am
--- gnuradius-0.96.2.orig/radiusd/Makefile.am Tue Mar 19 22:32:00 2002
+++ gnuradius-0.96.2/radiusd/Makefile.am Thu May 23 15:55:06 2002
@@ -25,6 +25,7 @@
log.c\
menu.c\
pam.c\
+ securid.c\
proxy.c\
radck.c\
radius.c\
@@ -79,7 +80,7 @@
$(LINT.c) -u $(radiusd_LNS) -L../radlib -lrad
SRCS=radiusd.c acct.c auth.c exec.c files.c menu.c sql.c\
- config.y pam.c proxy.c radius.c\
+ config.y pam.c securid.c proxy.c radius.c\
timestr.c version.c log.c stat.c\
snmpserv.c shmem.c radutil.c rewrite.y\
checkrad.c radck.c builddbm.c
diff -N -r -u gnuradius-0.96.2.orig/radiusd/Makefile.in
gnuradius-0.96.2/radiusd/Makefile.in
--- gnuradius-0.96.2.orig/radiusd/Makefile.in Wed Mar 20 19:52:03 2002
+++ gnuradius-0.96.2/radiusd/Makefile.in Thu May 23 15:57:34 2002
@@ -129,7 +129,7 @@
lispdir = @lispdir@
sbin_PROGRAMS = radiusd
-radiusd_SOURCES = acct.c auth.c builddbm.c checkrad.c config.c
config_kw.c config_tok.h debugmod.c exec.c files.c log.c menu.c pam.c
proxy.c radck.c radius.c radiusd.c radutil.c rewrite.c scheme.c shmem.c
snmpserv.c sql.c stat.c timestr.c version.c
+radiusd_SOURCES = acct.c auth.c builddbm.c checkrad.c config.c
config_kw.c config_tok.h debugmod.c exec.c files.c log.c menu.c pam.c
securid.c proxy.c radck.c radius.c radiusd.c radutil.c rewrite.c
scheme.c shmem.c snmpserv.c sql.c stat.c timestr.c version.c
radiusd_LDADD = @LEXLIB@ @SQLLIB@ ../snmplib/libradsnmp.a @RADIUSD_LDADD@
../radlib/librad.la
@@ -148,7 +148,7 @@
@address@hidden = -gezra -DHAVE_CONFIG_H=1 -DMAINTAINER_MODE=1 $(INCLUDES)
@address@hidden = $(radiusd_SOURCES:.c=.ln)
address@hidden@SRCS = radiusd.c acct.c auth.c exec.c files.c menu.c sql.c
config.y pam.c proxy.c radius.c timestr.c version.c log.c stat.c
snmpserv.c shmem.c radutil.c rewrite.y checkrad.c radck.c builddbm.c
address@hidden@SRCS = radiusd.c acct.c auth.c exec.c files.c menu.c sql.c
config.y pam.c securid.c proxy.c radius.c timestr.c version.c log.c
stat.c snmpserv.c shmem.c radutil.c rewrite.y checkrad.c
radck.c builddbm.c
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../config.h
CONFIG_CLEAN_FILES =
@@ -163,7 +163,7 @@
radiusd_OBJECTS = acct.$(OBJEXT) auth.$(OBJEXT) builddbm.$(OBJEXT) \
checkrad.$(OBJEXT) config.$(OBJEXT) config_kw.$(OBJEXT) \
debugmod.$(OBJEXT) exec.$(OBJEXT) files.$(OBJEXT) log.$(OBJEXT) \
-menu.$(OBJEXT) pam.$(OBJEXT) proxy.$(OBJEXT) radck.$(OBJEXT) \
+menu.$(OBJEXT) pam.$(OBJEXT) securid.$(OBJEXT) proxy.$(OBJEXT) radck.$(OBJEXT)
\
radius.$(OBJEXT) radiusd.$(OBJEXT) radutil.$(OBJEXT) rewrite.$(OBJEXT) \
scheme.$(OBJEXT) shmem.$(OBJEXT) snmpserv.$(OBJEXT) sql.$(OBJEXT) \
stat.$(OBJEXT) timestr.$(OBJEXT) version.$(OBJEXT)
@@ -381,6 +381,10 @@
../include/log.h ../include/mem.h ../include/radpaths.h \
../include/radsnmp.h
pam.o: pam.c ../config.h ../include/debugmod.h ../include/radiusd.h \
+ ../include/sysdep.h ../include/radius.h ../include/raddict.h \
+ ../include/log.h ../include/mem.h ../include/radpaths.h \
+ ../include/radsnmp.h
+securid.o: securid.c ../config.h ../include/debugmod.h ../include/radiusd.h \
../include/sysdep.h ../include/radius.h ../include/raddict.h \
../include/log.h ../include/mem.h ../include/radpaths.h \
../include/radsnmp.h
diff -N -r -u gnuradius-0.96.2.orig/radiusd/auth.c
gnuradius-0.96.2/radiusd/auth.c
--- gnuradius-0.96.2.orig/radiusd/auth.c Tue Mar 19 23:10:18 2002
+++ gnuradius-0.96.2/radiusd/auth.c Tue Jun 4 17:24:16 2002
@@ -335,6 +335,19 @@
#endif
break;
+ case DV_AUTH_TYPE_SECURID:
+#ifdef USE_SECURID
+ debug(1, (" auth: SecurID"));
+ if (securid_pass(name, userpass, user_msg, radreq) != 0)
+ result = AUTH_FAIL;
+#else
+ radlog(L_ERR,
+ _("%s: SecurID authentication not available"),
+ name);
+ result = AUTH_NOUSER;
+#endif
+ break;
+
case DV_AUTH_TYPE_CRYPT_LOCAL:
debug(1, (" auth: Crypt"));
if (real_password == NULL) {
diff -N -r -u gnuradius-0.96.2.orig/radiusd/config.kw
gnuradius-0.96.2/radiusd/config.kw
--- gnuradius-0.96.2.orig/radiusd/config.kw Tue Mar 19 22:32:00 2002
+++ gnuradius-0.96.2/radiusd/config.kw Tue Jun 4 01:07:36 2002
@@ -33,6 +33,7 @@
%%
acct, T_ACCT
acct-dir, T_ACCT_DIR
+aceclientip, T_ACECLIENTIP
acl, T_ACL
alert, T_SEVERITY, _Y(L_ALERT)
allow, T_ALLOW,
diff -N -r -u gnuradius-0.96.2.orig/radiusd/config.y
gnuradius-0.96.2/radiusd/config.y
--- gnuradius-0.96.2.orig/radiusd/config.y Tue Mar 19 23:10:18 2002
+++ gnuradius-0.96.2/radiusd/config.y Tue Jun 4 22:50:07 2002
@@ -154,7 +154,7 @@
%token T_USEDBM T_CHECKRAD_ASSUME_LOGGED T_DELAY T_DETAIL T_HOST
%token T_EXEC_PROGRAM_GROUP T_EXEC_PROGRAM_USER T_LOAD T_LOAD_PATH T_LOG_DIR
%token T_MAX_REQUESTS T_MESSAGE T_PORT T_REQUEST_CLEANUP_DELAY T_RETRY T_SPAWN
-%token T_STRIP_NAMES T_TTL T_USERNAME_CHARS T_USR2DELAY
+%token T_STRIP_NAMES T_TTL T_USERNAME_CHARS T_USR2DELAY T_ACECLIENTIP
%token T_SOURCE_IP T_ACCT_DIR T_ACCT T_CNTL T_PROXY T_CHANNEL
%token T_SYSLOG T_NOTIFY T_SNMP T_COMMUNITY T_ACL
@@ -200,6 +200,7 @@
| options_stmt
| notify_stmt
| usedbm_stmt
+ | aceclientip_stmt
| auth_stmt
| acct_stmt
| proxy_stmt
@@ -732,6 +733,30 @@
#endif
}
;
+
+ /* ACE Client IP support */
+
+aceclientip_stmt : T_ACECLIENTIP T_BOOL
+ {
+#ifdef USE_SECURID
+#ifdef USE_SECURID_LEGACY
+ radlog(L_WARN,
+ _("%s:%d: aceclientip statement ignored:
library does not support SD_ClientCheck"),
+ filename, line_num);
+#else
+ ace_client_ip = $2;
+ if (debug_config)
+ radlog(L_DEBUG, _("ace client ip: %d"),
+ ace_client_ip);
+#endif
+#else
+ radlog(L_WARN,
+ _("%s:%d: aceclientip statement ignored:
radiusd compiled without SecurID support"),
+ filename, line_num);
+#endif
+ }
+ ;
+
/* SNMP server parameters */
diff -N -r -u gnuradius-0.96.2.orig/radiusd/radck.c
gnuradius-0.96.2/radiusd/radck.c
--- gnuradius-0.96.2.orig/radiusd/radck.c Tue Mar 19 22:32:00 2002
+++ gnuradius-0.96.2/radiusd/radck.c Thu May 23 20:07:24 2002
@@ -354,10 +354,23 @@
break;
case DV_AUTH_TYPE_SECURID:
+#ifdef USE_SECURID
+ if (password || crypt_password) {
+ radlog(L_WARN,
+ _("%s:%d: Password attribute ignored for this Auth-Type"),
+ filename, line);
+ }
+ if (pass_loc) {
+ radlog(L_WARN,
+ _("%s:%d: Password-Location attribute ignored for this
Auth-Type"),
+ filename, line);
+ }
+#else
radlog(L_ERR,
_("%s:%d: Authentication type not supported"),
filename, line);
errcnt++;
+#endif
break;
case DV_AUTH_TYPE_SQL:
diff -N -r -u gnuradius-0.96.2.orig/radiusd/radius.c
gnuradius-0.96.2/radiusd/radius.c
--- gnuradius-0.96.2.orig/radiusd/radius.c Tue Mar 19 22:32:00 2002
+++ gnuradius-0.96.2/radiusd/radius.c Mon May 27 17:21:42 2002
@@ -345,6 +345,9 @@
VALUE_PAIR *prev;
VALUE_PAIR *pair;
RADIUS_REQ *radreq;
+#ifdef USE_NAS_IP_HACK
+ int has_nas_addr;
+#endif
/*
* Pre-allocate the new request data structure
@@ -384,6 +387,9 @@
length -= AUTH_HDR_LEN;
first_pair = NULL;
prev = NULL;
+#ifdef USE_NAS_IP_HACK
+ has_nas_addr = 0;
+#endif
while (length > 0) {
@@ -412,6 +418,10 @@
length -= 6;
}
}
+#ifdef USE_NAS_IP_HACK
+ else if (attribute == DA_NAS_IP_ADDRESS)
+ has_nas_addr = 1;
+#endif
if ((attr = attr_number_to_dict(attribute)) == NULL) {
debug(1, ("Received unknown attribute %d", attribute));
@@ -474,6 +484,39 @@
ptr += attrlen;
length -= attrlen;
}
+#ifdef USE_NAS_IP_HACK
+ if (!has_nas_addr)
+ {
+ /* Some vendors fail to include the NAS-IP-Address
+ * field in the request. This makes enforcing NAS
+ * specific controls difficult in many cases. The
+ * following adds the source host as the NAS-IP-Address
+ * if it's missing.
+ */
+ if ((attr = attr_number_to_dict(DA_NAS_IP_ADDRESS)) == NULL) {
+ debug(1, ("Failed to find standard attribute %d",
+ DA_NAS_IP_ADDRESS));
+ } else {
+ pair = avp_alloc();
+
+ pair->name = attr->name;
+ pair->attribute = attr->value;
+ pair->type = attr->type;
+ pair->prop = attr->prop;
+ pair->next = NULL;
+ pair->lvalue = host;
+
+ debug(10, ("recv: added: %s", format_pair(pair)));
+
+ if (first_pair == NULL)
+ first_pair = pair;
+ else
+ prev->next = pair;
+
+ prev = pair;
+ }
+ }
+#endif
radreq->request = first_pair;
return(radreq);
}
diff -N -r -u gnuradius-0.96.2.orig/radiusd/radiusd.c
gnuradius-0.96.2/radiusd/radiusd.c
--- gnuradius-0.96.2.orig/radiusd/radiusd.c Tue Mar 19 23:30:53 2002
+++ gnuradius-0.96.2/radiusd/radiusd.c Fri Jun 7 17:19:25 2002
@@ -149,6 +149,7 @@
static int foreground; /* Stay in the foreground */
static int spawn_flag;
int use_dbm = 0;
+int ace_client_ip = 0;
int open_acct = 1;
int auth_detail = 0;
int acct_detail = 1;
diff -N -r -u gnuradius-0.96.2.orig/radiusd/securid.c
gnuradius-0.96.2/radiusd/securid.c
--- gnuradius-0.96.2.orig/radiusd/securid.c Thu Jan 1 07:30:00 1970
+++ gnuradius-0.96.2/radiusd/securid.c Thu Jun 6 20:38:58 2002
@@ -0,0 +1,500 @@
+/* This file is part of GNU RADIUS.
+ Copyright (C) 2001 Sergey Poznyakoff
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#define RADIUS_MODULE_SECURID_C
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef USE_SECURID
+
+/** SecurID interface.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#) $Id: pam.c,v 1.9 2001/11/27 12:13:36 gray Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <time.h>
+#include <ctype.h>
+
+#include <radiusd.h>
+
+#ifdef USE_SECURID_LEGACY
+#include "sdi_athd.h"
+#include "sdi_size.h"
+#include "sdi_type.h"
+#include "sdi_defs.h"
+#include "sdconf.h"
+#include "sdacmvls.h"
+
+unsigned long strtoul ();
+
+union config_record configure;
+#else
+#include "acexport.h"
+#endif
+
+#ifndef SDACE_FILE
+#define SDACE_FILE "/etc/sdace.txt"
+#endif
+
+#ifdef USE_SECURID_LEGACY
+
+/** Fake the new (5.x onward) synchronous functions
+ */
+typedef struct SD_CLIENT *SDI_HANDLE;
+
+int AceInitialize(void)
+{
+ return creadcfg() < 0 ? 0 : 1;
+}
+
+int SD_Init(hdlp)
+ SDI_HANDLE *hdlp;
+{
+ SDI_HANDLE hdl;
+
+ *hdlp = hdl = calloc(1, sizeof(struct SD_CLIENT));
+ if (sd_init(hdl) == 0)
+ return ACM_OK;
+ free(hdl);
+
+ return 1;
+}
+
+int SD_Check(hdl, passcode, name)
+ SDI_HANDLE hdl;
+ char *passcode;
+ char *name;
+{
+ char *spasscode;
+ int ret;
+
+ /* sd_check overwrites the argument, but the 5.x SD_Check does not */
+
+ spasscode = estrdup(passcode);
+ ret = sd_check(spasscode, name, hdl);
+ memset(spasscode, '\0', strlen(spasscode));
+ efree(spasscode);
+
+ return ret;
+}
+
+int SD_ClientCheck(hdl, passcode, name, client)
+ SDI_HANDLE hdl;
+ char *passcode;
+ char *name;
+ unsigned long client;
+{
+ /* not implemented - treat as a normal non-client specific check */
+
+ return SD_Check(hdl, passcode, name);
+}
+
+int SD_Close(hdl)
+ SDI_HANDLE hdl;
+{
+
+ sd_close();
+ free(hdl);
+}
+#endif /* USE_SECURID_LEGACY */
+
+#ifdef USE_SECURID_RESEND_HACK
+
+/** See README for an explanation for this code.
+ */
+
+/** hash_passcode - generate a hash of the passcode using md5crypt so that
+ * PINs (which are the first part of the passcode - except for the soft
+ * token) are not exposed.
+ */
+static char *hash_passcode(passcode, usesalt)
+ char *passcode;
+ char *usesalt;
+{
+ int i;
+ char salt[9];
+ static char *m =
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ static int srand_called = 0;
+
+ if (usesalt == NULL) {
+ strcpy(salt, "$1$");
+ if (!srand_called) {
+ srand(time(NULL));
+ srand_called = 1;
+ }
+ for (i = 0; i < 5; i++)
+ salt[i+3] = m[rand()%64];
+ salt[8] = '\0';
+ usesalt = salt;
+ }
+ return md5crypt(passcode, usesalt);
+}
+
+struct databuf {
+ int len;
+ void *buf;
+};
+
+#define USE_SECURID_NDBM 1
+
+#ifdef USE_SECURID_NDBM
+
+#include <ndbm.h>
+#include <fcntl.h>
+#include <errno.h>
+
+typedef DBM *DBMH;
+
+/** Attempt to avoid multiple db access as this may corrupt the database.
+ * Gives up after 1 sec.
+ */
+static void
+getlock()
+{
+ char *fpath, *flink, ffile[32];
+ int fd, pid, ret, i;
+ struct timeval tm;
+
+ sprintf(ffile, "securid.%d", getpid());
+ fpath = mkfilename(radius_dir, ffile);
+ debug(20, ("file: [%s]\n", fpath));
+
+ if ((fd = open(fpath, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
+ {
+ debug(20, ("lock file <%s> open failed: %d", fpath, errno));
+ efree(fpath);
+ return;
+ }
+ close(fd);
+
+ flink = mkfilename(radius_dir, "securid.lock");
+ debug(20, ("link: [%s]\n", flink));
+
+ for (i = 0; i<20 && (ret=link(fpath, flink))<0 && errno==EEXIST; i++) {
+ tm.tv_sec = 0; tm.tv_usec = 50000;
+ select(1, NULL, NULL, NULL, &tm);
+ }
+
+ if (ret < 0)
+ debug(20, ("failed to link: %d", errno));
+
+ unlink(fpath);
+ efree(fpath);
+ efree(flink);
+}
+
+static void
+releaselock()
+{
+ char *flink = mkfilename(radius_dir, "securid.lock");
+
+ debug(20, ("unlink: [%s]\n", flink));
+ efree(flink);
+ unlink(flink);
+}
+
+static DBMH
+open_securid_db(void)
+{
+ char *path;
+ DBMH dbh;
+
+ path = mkfilename(radius_dir, "securid");
+ getlock();
+ dbh = dbm_open(path, O_RDWR|O_CREAT, 0600);
+ if (dbh == NULL)
+ {
+ releaselock();
+ debug(1, ("Failed to create securid database: %s", path));
+ }
+ efree(path);
+
+ return dbh;
+}
+
+close_securid_db(DBMH dbh)
+{
+ dbm_close(dbh);
+ releaselock();
+}
+
+static void
+putdb(key, data)
+ char *key;
+ struct databuf *data;
+{
+ datum k, d;
+ DBMH dbmfile;
+
+ k.dptr = key;
+ k.dsize = strlen(key);
+ d.dptr = data->buf;
+ d.dsize = data->len;
+
+ if ((dbmfile = open_securid_db()) == NULL)
+ return;
+ dbm_store(dbmfile, k, d, DBM_REPLACE);
+ close_securid_db(dbmfile);
+}
+
+static struct databuf
+getdb(key)
+ char *key;
+{
+ datum k, d;
+ struct databuf b;
+ DBMH dbmfile;
+
+ k.dptr = key;
+ k.dsize = strlen(key);
+ b.len = 0;
+ b.buf = NULL;
+
+ if ((dbmfile = open_securid_db()) == NULL)
+ return b;
+ d = dbm_fetch(dbmfile, k);
+ b.len = d.dsize;
+ if (d.dsize > 0) {
+ b.buf = emalloc(d.dsize);
+ memcpy(b.buf, d.dptr, d.dsize);
+ }
+ else
+ b.buf = NULL;
+ close_securid_db(dbmfile);
+
+ return b;
+}
+
+#endif /* USE_SECURID_NDBM */
+
+/** check_resend - compare the current request name, passcode and ip address
+ * with the last one for the user and assume a resend if all match and the
+ * request is younger that auth.request-cleanup-delay seconds.
+ */
+char check_resend(name, passcode, tm, ipaddr)
+ char *name;
+ char *passcode;
+ time_t tm;
+ UINT4 ipaddr;
+{
+ char *path, *s, *t, *p, *f, *hash, *j;
+ int ret = 0;
+ struct databuf b;
+ time_t lt;
+ char flag;
+ UINT4 sip;
+
+ debug(20, ("check resend: name=%s tm=%ld", name, tm));
+
+ b = getdb(name);
+ if (b.buf == NULL || b.len == 0)
+ {
+ debug(20, ("no data for: %s", name));
+ return '\0';
+ }
+
+ s = (char *)b.buf;
+ t = s + strlen(s) + 1;
+ p = t + strlen(t) + 1;
+ f = p + strlen(p) + 1;
+ if (f - s > b.len)
+ {
+ debug(20, ("malformed data: name=%s len=%d(%d)", name,
+ b.len, f-s));
+ efree(b.buf);
+ return '\0';
+ }
+ flag = *f;
+ debug(20, ("saved: name=%s hash=%s time=%s ip=%s flag=%s", name, s,
+ t, p, f));
+
+ lt = atol(t);
+ sip = strtoul(p, &j, 10);
+
+ if (tm - lt > request_class[R_AUTH].cleanup_delay)
+ {
+ debug(20, ("%d second timeout - not resend: %ld - %ld = %ld",
+ request_class[R_AUTH].cleanup_delay, tm, lt, tm-lt));
+ efree(b.buf);
+ return '\0';
+ }
+
+ if (ipaddr != sip)
+ {
+ debug(20, ("ip addresses differ: %08x != %08x", ipaddr, sip));
+ efree(b.buf);
+ return '\0';
+ }
+
+ hash = hash_passcode(passcode, s);
+ debug(20, ("passcode hash: hash=%s salt=%s", hash, s));
+
+ if (strcmp(hash, s) == 0)
+ {
+ debug(20, ("same passcode, returning flag: %c", flag));
+ efree(b.buf);
+ return flag;
+ }
+ debug(20, ("passcode differ, not resend"));
+
+ efree(b.buf);
+ return '\0';
+
+ return ret;
+}
+
+void save_resend_info(name, passcode, tm, ip, flag)
+ char *name;
+ char *passcode;
+ time_t tm;
+ UINT4 ip;
+ char flag;
+{
+ char stm[20], sip[20];
+ char *data, *s, *hash;
+ int len;
+ struct databuf dat;
+
+ hash = hash_passcode(passcode, NULL);
+ sprintf(stm, "%ld", tm);
+ sprintf(sip, "%lu", ip);
+ debug(20, ("saving: name=%s hash=%s time=%s ip=%s flag=%c",
+ name, hash, stm, sip, flag));
+ len = strlen(hash) + strlen(stm) + strlen(sip) + 1 + 4;
+
+ s = data = emalloc(len);
+ strcpy(s, hash);
+ s += strlen(s);
+ *s++ = '\0';
+
+ strcpy(s, stm);
+ s += strlen(s);
+ *s++ = '\0';
+
+ strcpy(s, sip);
+ s += strlen(s);
+ *s++ = '\0';
+
+ *s++ = flag;
+ *s++ = '\0';
+
+ dat.len = len;
+ dat.buf = data;
+
+ putdb(name, dat);
+ efree(data);
+}
+
+#endif /* USE_SECURID_RESEND_HACK */
+
+int
+securid_pass(name, passcode, reply_msg, radreq)
+ char *name;
+ char *passcode;
+ char **reply_msg;
+ RADIUS_REQ *radreq;
+{
+ char buf[1024];
+ SDI_HANDLE acehdl;
+ int status;
+ time_t t;
+
+ debug(1, ("securid_pass: %s", name));
+
+ time(&t);
+#ifdef USE_SECURID_RESEND_HACK
+ switch (check_resend(name, passcode, t, radreq->ipaddr)) {
+ case '\0':
+ break;
+ case 'n':
+ return 1;
+ case 'y':
+ return 0;
+ }
+#endif /* USE_SECURID_RESEND_HACK */
+
+ *reply_msg = NULL;
+ if (!AceInitialize()) {
+ debug(1, ("AceInitialize failed"));
+ *reply_msg = make_string("internal error: AceInitialize");
+ return 1;
+ }
+
+ if ((status = SD_Init(&acehdl)) != ACM_OK) {
+ debug(1, ("SD_init failed: %d", status));
+ *reply_msg = make_string("internal error: SD_Init");
+ return 1;
+ }
+
+ if (ace_client_ip)
+ status = SD_ClientCheck(acehdl, passcode, name, radreq->ipaddr);
+ else
+ status = SD_Check(acehdl, passcode, name);
+ SD_Close(acehdl);
+
+ switch (status)
+ {
+ case ACM_OK:
+ debug(1, ("%s/%s, access allowed",name,passcode));
+#ifdef USE_SECURID_RESEND_HACK
+ save_resend_info(name, passcode, t, radreq->ipaddr, 'y');
+#endif
+ return 0;
+
+#ifndef USE_SECURID_LEGACY
+ case ACE_UNDEFINED_PASSCODE:
+ case ACE_UNDEFINED_USERNAME:
+ case ACE_ERR_INVALID_HANDLE:
+ debug(1, ("%s/%s, internal error - status: %d",
+ name, passcode, status));
+ *reply_msg = make_string("internal error");
+ break;
+#endif
+ case ACM_ACCESS_DENIED:
+ debug(1, ("%s/%s, access denied",name,passcode));
+ *reply_msg = make_string("access denied");
+ break;
+ case ACM_NEXT_CODE_REQUIRED:
+ debug(1,("%s/%s, next token mode",name,passcode));
+ radlog(L_INFO, _("SecurID token in next token mode: %s"), name);
+ *reply_msg = make_string("next token mode");
+ break;
+ case ACM_NEW_PIN_REQUIRED:
+ debug(1,("%s/%s, new pin mode", name, passcode));
+ radlog(L_INFO, _("SecurID token in new pin mode: %s"), name);
+ *reply_msg = make_string("new pin mode");
+ break;
+ }
+#ifdef USE_SECURID_RESEND_HACK
+ save_resend_info(name, passcode, t, radreq->ipaddr, 'n');
+#endif
+ return 1;
+}
+
+#endif
diff -N -r -u gnuradius-0.96.2.orig/radiusd/version.c
gnuradius-0.96.2/radiusd/version.c
--- gnuradius-0.96.2.orig/radiusd/version.c Tue Mar 19 22:32:00 2002
+++ gnuradius-0.96.2/radiusd/version.c Thu Jun 6 14:03:17 2002
@@ -85,6 +85,18 @@
#if defined(USE_PAM)
"USE_PAM",
#endif
+#if defined(USE_SECURID)
+ "USE_SECURID",
+#endif
+#if defined(USE_SECURID_LEGACY)
+ "USE_SECURID_LEGACY",
+#endif
+#if defined(USE_SECURID_RESEND_HACK)
+ "USE_SECURID_RESEND_HACK",
+#endif
+#if defined(USE_NAS_IP_HACK)
+ "USE_NAS_IP_HACK",
+#endif
#if defined(USE_DBM)
# if USE_DBM == DBM_DBM
"USE_DBM=DBM",
@@ -100,6 +112,9 @@
#endif
#ifdef USE_SQL_ODBC
"USE_SQL_ODBC",
+#endif
+#ifdef USE_SQL_SYBASE
+ "USE_SQL_SYBASE",
#endif
#if defined(USE_SNMP)
"USE_SNMP",
diff -N -r -u gnuradius-0.96.2.orig/sql/Makefile.am
gnuradius-0.96.2/sql/Makefile.am
--- gnuradius-0.96.2.orig/sql/Makefile.am Tue Mar 19 22:32:05 2002
+++ gnuradius-0.96.2/sql/Makefile.am Mon May 27 17:25:33 2002
@@ -14,7 +14,7 @@
EXTRA_LTLIBRARIES=libsql.la
INCLUDES= -I$(top_srcdir)/include @INCLUDEPATH@
-libsql_la_SOURCES=disp.c mysql.c postgres.c odbc.c
+libsql_la_SOURCES=disp.c mysql.c postgres.c odbc.c sybase.c
SUFFIXES=.S .c .ln .o .s
diff -N -r -u gnuradius-0.96.2.orig/sql/Makefile.in
gnuradius-0.96.2/sql/Makefile.in
--- gnuradius-0.96.2.orig/sql/Makefile.in Wed Mar 20 19:52:00 2002
+++ gnuradius-0.96.2/sql/Makefile.in Mon May 27 17:26:06 2002
@@ -133,7 +133,7 @@
EXTRA_LTLIBRARIES = libsql.la
INCLUDES = -I$(top_srcdir)/include @INCLUDEPATH@
-libsql_la_SOURCES = disp.c mysql.c postgres.c odbc.c
+libsql_la_SOURCES = disp.c mysql.c postgres.c odbc.c sybase.c
SUFFIXES = .S .c .ln .o .s
@@ -151,7 +151,7 @@
LIBS = @LIBS@
libsql_la_LDFLAGS =
libsql_la_LIBADD =
-libsql_la_OBJECTS = disp.lo mysql.lo postgres.lo odbc.lo
+libsql_la_OBJECTS = disp.lo mysql.lo postgres.lo odbc.lo sybase.lo
CFLAGS = @CFLAGS@
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS)
$(CFLAGS)
LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS)
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -310,6 +310,9 @@
../include/radius.h ../include/sysdep.h ../include/raddict.h \
../include/log.h ../include/mem.h ../include/radsql.h
postgres.lo postgres.o : postgres.c ../config.h ../include/debugmod.h \
+ ../include/radius.h ../include/sysdep.h ../include/raddict.h \
+ ../include/log.h ../include/mem.h ../include/radsql.h
+sybase.lo sybase.o : sybase.c ../config.h ../include/debugmod.h \
../include/radius.h ../include/sysdep.h ../include/raddict.h \
../include/log.h ../include/mem.h ../include/radsql.h
diff -N -r -u gnuradius-0.96.2.orig/sql/disp.c gnuradius-0.96.2/sql/disp.c
--- gnuradius-0.96.2.orig/sql/disp.c Tue Mar 19 22:32:05 2002
+++ gnuradius-0.96.2/sql/disp.c Thu Jun 6 22:07:01 2002
@@ -23,10 +23,27 @@
#include <radsql.h>
static SQL_DISPATCH_TAB *sql_dispatch_tab[] = {
+#ifdef USE_SQL_MYSQL
+ mysql_dispatch_tab,
+#else
+# ifdef USE_SQL_POSTGRES
+ postgres_dispatch_tab,
+# else
+# ifdef USE_SQL_ODBC
+ odbc_dispatch_tab,
+# else
+# ifdef USE_SQL_SYBASE
+ sybase_dispatch_tab,
+# else
NULL,
+# endif
+# endif
+# endif
+#endif
mysql_dispatch_tab,
postgres_dispatch_tab,
odbc_dispatch_tab,
+ sybase_dispatch_tab,
};
#define NDISP sizeof(sql_dispatch_tab)/sizeof(sql_dispatch_tab[0])
diff -N -r -u gnuradius-0.96.2.orig/sql/sybase.c gnuradius-0.96.2/sql/sybase.c
--- gnuradius-0.96.2.orig/sql/sybase.c Thu Jan 1 07:30:00 1970
+++ gnuradius-0.96.2/sql/sybase.c Fri Jun 7 16:34:19 2002
@@ -0,0 +1,968 @@
+/* This file is part of GNU RADIUS.
+ Copyright (C) 2000,2001 Sergey Poznyakoff
+ Copyright (C) 2002 Steve Bleazard
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/
+
+#define RADIUS_MODULE_SYBASE_C
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Id: sybase.c,v 1.3 2001/08/22 13:18:04 gray Exp $" ;
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <radiusd.h>
+#include <radsql.h>
+
+#ifdef USE_SQL_SYBASE
+
+#include <ctpublic.h>
+
+struct sybase_connection {
+ CS_CONTEXT *context;
+ CS_CONNECTION *connection;
+ CS_COMMAND *cmd;
+};
+
+static int rad_sybase_reconnect(int type, struct sql_connection *conn);
+static void rad_sybase_disconnect(struct sql_connection *conn);
+static int rad_sybase_query(struct sql_connection *conn, char *query, int
*return_count);
+static char *rad_sybase_getpwd(struct sql_connection *conn, char *query);
+static void *rad_sybase_exec(struct sql_connection *conn, char *query);
+static char *rad_sybase_column(void *data, int ncol);
+static int rad_sybase_next_tuple(struct sql_connection *conn, void *data);
+static void rad_sybase_free(struct sql_connection *conn, void *data);
+
+/* a suitable exit macro to handle the closedown and any messages */
+
+#define CLEANUP_ON_FAIL(conn, ret, func, dbg) \
+ if (ret != CS_SUCCEED) { \
+ debug(1, dbg); \
+ radlog(L_ERR, _(func " failed: %d"), ret); \
+ if (conn != NULL) { \
+ rad_sql_need_reconnect(conn->type); \
+ } \
+ }
+
+#define RETURN_ON_FAIL(conn, ret, func, dbg, retval) \
+ if (ret != CS_SUCCEED) { \
+ CLEANUP_ON_FAIL(conn, ret, func, dbg) \
+ return retval; \
+ }
+
+/** Error handler helper functions
+ */
+static void
+force_close_sybase_connection(sconn)
+ struct sybase_connection *sconn;
+{
+ CS_RETCODE ret;
+
+ if (sconn->cmd) {
+ ret = ct_cmd_drop(sconn->cmd);
+ if (ret != CS_SUCCEED)
+ {
+ debug(1, ("ct_cmd_drop failed: %d", ret));
+ radlog(L_ERR, _("ct_cmd_drop failed: %d"), ret);
+ }
+ sconn->cmd = NULL;
+ }
+ if (sconn->connection) {
+ ret = ct_close(sconn->connection, CS_FORCE_CLOSE);
+ if (ret != CS_SUCCEED)
+ {
+ debug(1, ("ct_close failed: %d", ret));
+ radlog(L_ERR, _("ct_close failed: %d"), ret);
+ }
+ ret = ct_con_drop(sconn->connection);
+ if (ret != CS_SUCCEED)
+ {
+ debug(1, ("ct_con_drop failed: %d", ret));
+ radlog(L_ERR, _("ct_con_drop failed: %d"), ret);
+ }
+ sconn->connection = NULL;
+ }
+}
+
+
+/** Error callback functions - just log errors */
+
+CS_RETCODE
+clientmsg_callback(context, conn, emsgp)
+ CS_CONTEXT *context;
+ CS_CONNECTION *conn;
+ CS_CLIENTMSG *emsgp;
+{
+ debug(1, ("sybase client library error: severity(%ld) layer(%ld) "
+ "origin(%ld) number(%ld), %s",
+ (long) CS_SEVERITY(emsgp->severity),
+ (long) CS_LAYER(emsgp->msgnumber),
+ (long) CS_ORIGIN(emsgp->msgnumber),
+ (long) CS_NUMBER(emsgp->msgnumber),
+ emsgp->msgstring));
+
+ radlog(L_ERR,
+ _("sybase error: severity(%ld) layer(%ld) origin(%ld) "
+ "number(%ld), %s"),
+ (long) CS_SEVERITY(emsgp->severity),
+ (long) CS_LAYER(emsgp->msgnumber),
+ (long) CS_ORIGIN(emsgp->msgnumber),
+ (long) CS_NUMBER(emsgp->msgnumber),
+ emsgp->msgstring);
+
+ if (emsgp->osstringlen > 0) {
+ debug(1, ("sybase client library OS error: %ld (%s)",
+ emsgp->osnumber, emsgp->osstring));
+ radlog(L_ERR, _("sybase os error: %ld (%s)"),
+ (long) emsgp->osnumber, emsgp->osstring);
+ }
+
+ return CS_SUCCEED;
+}
+
+CS_RETCODE
+csmsg_callback(context, conn, emsgp)
+ CS_CONTEXT *context;
+ CS_CLIENTMSG *emsgp;
+{
+ debug(1, ("sybase CS library error: severity(%ld) layer(%ld) "
+ "origin(%ld) number(%ld), %s",
+ (long) CS_SEVERITY(emsgp->severity),
+ (long) CS_LAYER(emsgp->msgnumber),
+ (long) CS_ORIGIN(emsgp->msgnumber),
+ (long) CS_NUMBER(emsgp->msgnumber),
+ emsgp->msgstring));
+
+ radlog(L_ERR,
+ _("sybase error: severity(%ld) layer(%ld) origin(%ld) "
+ "number(%ld), %s"),
+ (long) CS_SEVERITY(emsgp->severity),
+ (long) CS_LAYER(emsgp->msgnumber),
+ (long) CS_ORIGIN(emsgp->msgnumber),
+ (long) CS_NUMBER(emsgp->msgnumber),
+ emsgp->msgstring);
+
+ if (emsgp->osstringlen > 0) {
+ debug(1, ("sybase CS library OS error: %ld (%s)",
+ (long)emsgp->osnumber, emsgp->osstring));
+ radlog(L_ERR, _("sybase os error: %ld (%s)"),
+ (long) emsgp->osnumber, emsgp->osstring);
+ }
+
+ return CS_SUCCEED;
+}
+
+CS_RETCODE
+servermsg_callback(context, conn, smsgp)
+ CS_CONTEXT *context;
+ CS_CONNECTION *conn;
+ CS_SERVERMSG *smsgp;
+{
+ char *s, *p, *sf, *pf;
+
+ s = p = sf = pf = "";
+ if (smsgp->svrnlen > 0) {
+ s = smsgp->svrname;
+ sf = ", server: ";
+ }
+ if (smsgp->proclen > 0) {
+ s = smsgp->proc;
+ sf = ", proc: ";
+ }
+
+ debug(1, ("sybase server message: number(%ld) severity(%ld) "
+ "state(%ld) line(%ld)%s%s%s%s, %s",
+ smsgp->msgnumber, smsgp->severity, smsgp->state,
+ smsgp->line, sf, s, pf, p, smsgp->text));
+
+ radlog(L_ERR, _("sybase server message: number(%ld) severity(%ld) "
+ "state(%ld) line(%ld)%s%s%s%s, %s"),
+ smsgp->msgnumber, smsgp->severity, smsgp->state,
+ smsgp->line, sf, s, pf, p, smsgp->text);
+
+ return CS_SUCCEED;
+
+
+}
+
+/** Helper functions */
+/* TODO */
+
+static CS_COMMAND *
+sybase_alloc_cmd(sybcon, conn)
+ struct sybase_connection *sybcon;
+ struct sql_connection *conn;
+{
+ CS_RETCODE ret;
+ CS_COMMAND *cmd;
+
+ ret = ct_cmd_alloc(sybcon->connection, &cmd);
+ RETURN_ON_FAIL(conn, ret, "ct_cmd_alloc",
+ ("ct_cmnd_alloc failed: %d", ret), NULL);
+
+ return cmd;
+}
+
+static int
+sybase_db_use(sybcon, database, conn)
+ struct sybase_connection *sybcon;
+ char *database;
+ struct sql_connection *conn;
+{
+ CS_COMMAND *cmd = sybase_alloc_cmd(sybcon, conn);
+ CS_RETCODE ret;
+ CS_INT restype;
+ char statement[255];
+
+ if(!cmd)
+ return -1;
+
+ sprintf(statement, "use %s", database);
+ ret = ct_command(cmd, CS_LANG_CMD, statement, CS_NULLTERM, CS_UNUSED);
+ RETURN_ON_FAIL(conn, ret, "ct_command",
+ ("ct_command failed: %d", ret), -1);
+
+ ret = ct_send(cmd);
+ RETURN_ON_FAIL(conn, ret, "ct_send",
+ ("ct_send failed: %d", ret), -1);
+
+ while ((ret = ct_results(cmd, &restype)) == CS_SUCCEED) {
+ if (restype == CS_CMD_FAIL)
+ radlog(L_ERR, _("'%s' failed: %d"), statement, ret);
+ }
+ ret = ct_cmd_drop(cmd);
+ RETURN_ON_FAIL(conn, ret, "ct_cmd_drop",
+ ("ct_cmd_drop failed: %d", ret), -1);
+
+ return 0;
+}
+
+
+/* ************************************************************************* */
+/* Interface routines */
+int
+rad_sybase_reconnect(type, conn)
+ int type;
+ struct sql_connection *conn;
+{
+ struct sybase_connection *sybcon;
+ char *dbname;
+ CS_RETCODE ret;
+#define XRETURN_ON_FAIL(ret, func, dbg) \
+ if (ret != CS_SUCCEED) { \
+ debug(1, dbg); \
+ radlog(L_ERR, _(func " failed: %d"), ret); \
+ force_close_sybase_connection(sybcon); \
+ if (sybcon->context != NULL) { \
+ ct_exit(sybcon->context, CS_FORCE_EXIT); \
+ cs_ctx_drop(sybcon->context); \
+ sybcon->context = NULL; \
+ } \
+ conn->data = NULL; \
+ conn->connected = 0; \
+ efree(sybcon); \
+ return -1; \
+ }
+
+ switch (type) {
+ case SQL_AUTH:
+ dbname = sql_cfg.auth_db;
+ break;
+ case SQL_ACCT:
+ dbname = sql_cfg.acct_db;
+ break;
+ }
+
+ /* Create a context and initialise */
+
+ conn->data = sybcon = emalloc(sizeof *sybcon);
+ conn->connected = 0;
+ sybcon->context = NULL;
+
+ debug(10, ("Initialising sybase cs/ct library"));
+ ret = cs_ctx_alloc(CS_VERSION_100, &sybcon->context);
+ XRETURN_ON_FAIL(ret,"cs_ctx_alloc",("cs_ctx_alloc failed: %d",ret));
+
+ ret = ct_init(sybcon->context, CS_VERSION_100);
+ XRETURN_ON_FAIL(ret, "ct_init", ("ct_init failed: %d", ret));
+
+ /* install callbacks */
+
+ debug(10, ("Installing callbacks"));
+ ret = cs_config(sybcon->context, CS_SET, CS_MESSAGE_CB,
+ (CS_VOID *)csmsg_callback, CS_UNUSED, NULL);
+ XRETURN_ON_FAIL(ret, "cs_config",
+ ("cs_config failed installing cs callback: %d", ret));
+
+ ret = ct_callback(sybcon->context, NULL, CS_SET, CS_CLIENTMSG_CB,
+ (CS_VOID *)clientmsg_callback);
+ XRETURN_ON_FAIL(ret, "ct_callback",
+ ("ct_callback failed installing client callback: %d", ret));
+
+ ret = ct_callback(sybcon->context, NULL, CS_SET, CS_SERVERMSG_CB,
+ (CS_VOID *)servermsg_callback);
+ XRETURN_ON_FAIL(ret, "ct_callback",
+ ("ct_callback failed installing server callback: %d", ret));
+
+ /* Connect to the server, first alloc a connection structure and
+ * set the username and password.
+ */
+
+ debug(10, ("connecting to server '%s' with username/pw: %s/%s",
+ sql_cfg.server, sql_cfg.login, sql_cfg.password));
+ ret = ct_con_alloc(sybcon->context, &sybcon->connection);
+ XRETURN_ON_FAIL(ret,"ct_con_alloc",("ct_con_alloc failed: %d", ret));
+
+ ret = ct_con_props(sybcon->connection, CS_SET, CS_USERNAME,
+ sql_cfg.login, CS_NULLTERM, NULL);
+ XRETURN_ON_FAIL(ret, "ct_con_props",
+ ("ct_con_props(username) failed: %d", ret));
+
+ ret = ct_con_props(sybcon->connection, CS_SET, CS_PASSWORD,
+ sql_cfg.password, CS_NULLTERM, NULL);
+ XRETURN_ON_FAIL(ret, "ct_con_props",
+ ("ct_con_props(password) failed: %d", ret));
+
+ /** Now connect to the server. Note that the server connection
+ * details (ipaddress, port etc) are contained in the Sybase
+ * "interfaces" file and the server name is simply a reference into
+ * this file.
+ */
+
+ ret = ct_connect(sybcon->connection, sql_cfg.server, CS_NULLTERM);
+ XRETURN_ON_FAIL(ret, "ct_connect", ("ct_connect failed: %d", ret));
+
+ /* connection complete - mark the connection connected */
+
+ debug(10, ("connected to database"));
+ conn->connected = 1;
+
+ /* force the correct database */
+
+ if (sybase_db_use(sybcon, dbname, conn) < 0)
+ {
+ conn->data = NULL;
+ conn->connected = 0;
+ efree(sybcon);
+ return -1;
+ }
+
+ return 0;
+
+#undef XRETURN_ON_FAIL
+}
+
+void
+rad_sybase_disconnect(conn)
+ struct sql_connection *conn;
+{
+ struct sybase_connection *sybcon;
+ CS_RETCODE ret;
+
+ conn->connected = 0;
+ if (!conn->data)
+ return;
+ sybcon = conn->data;
+ conn->data = NULL;
+
+ if (sybcon->context != NULL) {
+ force_close_sybase_connection(sybcon);
+
+ ret = ct_exit(sybcon->context, CS_FORCE_EXIT);
+ if (ret != CS_SUCCEED)
+ {
+ debug(1, ("ct_exit failed: %d", ret));
+ radlog(L_ERR, _("ct_exit failed: %d"), ret);
+ }
+
+ cs_ctx_drop(sybcon->context);
+ if (ret != CS_SUCCEED)
+ {
+ debug(1, ("cs_ctx_drop failed: %d", ret));
+ radlog(L_ERR, _("cs_ctx_drop failed: %d"), ret);
+ }
+ sybcon->context = NULL;
+ }
+
+ efree(sybcon);
+}
+
+static int
+sybase_do_query(conn, query)
+ struct sql_connection *conn;
+ char *query;
+{
+ struct sybase_connection *sybcon;
+ CS_RETCODE ret;
+
+ sybcon = conn->data;
+ if (!conn->connected || sybcon == NULL || sybcon->context == NULL)
+ {
+ if (rad_sybase_reconnect(conn->type, conn) < 0)
+ return -1;
+ sybcon = conn->data;
+ }
+
+ if ((sybcon->cmd = sybase_alloc_cmd(sybcon, conn)) == NULL)
+ return -1;
+
+ ret = ct_command(sybcon->cmd,CS_LANG_CMD,query,CS_NULLTERM,CS_UNUSED);
+ RETURN_ON_FAIL(conn, ret, "ct_command",
+ ("ct_command failed: %d", ret), -1);
+
+ ret = ct_send(sybcon->cmd);
+ RETURN_ON_FAIL(conn, ret, "ct_send", ("ct_send failed: %d", ret), -1);
+
+ return 0;
+}
+
+/** rad_sybase_query - action a query without returning data. This is usually
+ * used for insert queries. Return the number of rows effected.
+ */
+int
+rad_sybase_query(conn, query, return_count)
+ struct sql_connection *conn;
+ char *query;
+ int *return_count;
+{
+ struct sybase_connection *sybcon;
+ CS_RETCODE ret, res_ret;
+ CS_INT result_type;
+ CS_INT count, ocnt, fcnt;
+
+ if (!conn)
+ return -1;
+ debug(2, ("query: %s", query));
+
+ if (sybase_do_query(conn, query) < 0)
+ return -1;
+
+ sybcon = conn->data;
+ count = -1;
+
+ /* run through the rows until complete */
+
+ while ((res_ret = ct_results(sybcon->cmd, &result_type))==CS_SUCCEED) {
+ switch (result_type) {
+ case CS_ROW_RESULT:
+ case CS_PARAM_RESULT:
+ case CS_STATUS_RESULT:
+ case CS_CURSOR_RESULT:
+ case CS_COMPUTE_RESULT:
+ debug(1, ("results return in rad_sybase_query"));
+ while ((ret = ct_fetch(sybcon->cmd, CS_UNUSED,
+ CS_UNUSED, CS_UNUSED,
+ &fcnt)) == CS_SUCCEED ||
+ ret == CS_ROW_FAIL) {
+
+ /* report any row errors */
+ if (ret == CS_ROW_FAIL) {
+ debug(1, ("ct_fetch row error", ret));
+ radlog(L_ERR, _("ct_fetch row error"));
+ }
+ }
+ if (ret != CS_END_DATA)
+ {
+ RETURN_ON_FAIL(conn, ret, "ct_fetch",
+ ("ct_fetch failed: %d", ret), -1);
+ }
+ break;
+ case CS_CMD_SUCCEED:
+ case CS_CMD_DONE:
+ debug(1, ("ct_results cmd success"));
+ ret = ct_res_info(sybcon->cmd, CS_ROW_COUNT, &count,
+ CS_UNUSED, &ocnt);
+ RETURN_ON_FAIL(conn, ret, "ct_res_info",
+ ("ct_res_info failed: %d", ret), -1);
+ break;
+ case CS_CMD_FAIL:
+ debug(1, ("ct_results cmd fail"));
+ break;
+ default:
+ RETURN_ON_FAIL(conn, CS_FAIL, "ct_results",
+ ("ct_results failed: %d", res_ret),-1);
+
+ }
+ }
+
+ if (res_ret == CS_END_RESULTS) {
+ if (count == -1 &&
+ (result_type==CS_CMD_SUCCEED || result_type==CS_CMD_DONE)) {
+ ret = ct_res_info(sybcon->cmd, CS_ROW_COUNT, &count,
+ CS_UNUSED, &ocnt);
+ RETURN_ON_FAIL(conn, ret, "ct_res_info",
+ ("ct_res_info failed: %d", ret), -1);
+ }
+ } else {
+ RETURN_ON_FAIL(conn, res_ret, "ct_results",
+ ("ct_results failed: %d", res_ret), -1);
+ }
+
+ if (count == -1)
+ count = 0;
+
+ ret = ct_cmd_drop(sybcon->cmd);
+ sybcon->cmd = NULL;
+ RETURN_ON_FAIL(conn, ret, "ct_cmd_drop",
+ ("ct_cmd_drop failed: %d", ret), -1);
+
+ debug(2, ("query effected %d row(s)", count));
+ if (return_count)
+ *return_count = count;
+
+ return 0;
+}
+
+char *
+rad_sybase_getpwd(conn, query)
+ struct sql_connection *conn;
+ char *query;
+{
+ struct sybase_connection *sybcon;
+ CS_RETCODE ret, res_ret;
+ CS_INT result_type;
+ CS_INT fcnt;
+ CS_DATAFMT passwd_data;
+ CS_SMALLINT indicator;
+ char passwd[512+1];
+ char *return_passwd = NULL;
+
+ if (!conn)
+ return NULL;
+
+ debug(1, ("query: %s", query));
+
+ if (sybase_do_query(conn, query) < 0)
+ return NULL;
+
+ sybcon = conn->data;
+
+ /* run through the rows getting the first row data */
+
+ while ((res_ret = ct_results(sybcon->cmd, &result_type))==CS_SUCCEED) {
+ switch (result_type) {
+ case CS_ROW_RESULT:
+ case CS_PARAM_RESULT:
+ case CS_STATUS_RESULT:
+ case CS_CURSOR_RESULT:
+ case CS_COMPUTE_RESULT:
+ /* Bind the first column to the password buffer */
+
+ passwd_data.datatype = CS_CHAR_TYPE;
+ passwd_data.format = CS_FMT_NULLTERM;
+ passwd_data.maxlength = sizeof passwd - 1;
+ passwd_data.count = 1;
+ passwd_data.locale = NULL;
+ ret = ct_bind(sybcon->cmd, 1, &passwd_data, passwd,
+ NULL, &indicator);
+ RETURN_ON_FAIL(conn, ret, "cs_bind",
+ ("ct_bind failed: %d", ret), NULL);
+
+ while ((ret = ct_fetch(sybcon->cmd, CS_UNUSED,
+ CS_UNUSED, CS_UNUSED,
+ &fcnt)) == CS_SUCCEED ||
+ ret == CS_ROW_FAIL) {
+
+ /* report any row errors */
+ if (ret == CS_ROW_FAIL) {
+ debug(1, ("ct_fetch row error", ret));
+ radlog(L_ERR, _("ct_fetch row error"));
+ }
+ if (return_passwd == NULL && indicator >= 0)
+ return_passwd = estrdup(passwd);
+ }
+ if (ret != CS_END_DATA) {
+ RETURN_ON_FAIL(conn, ret, "ct_fetch",
+ ("ct_fetch failed: %d", ret), NULL);
+ }
+ break;
+ case CS_CMD_SUCCEED:
+ case CS_CMD_DONE:
+ case CS_CMD_FAIL:
+ break;
+ default:
+ RETURN_ON_FAIL(conn, CS_FAIL, "ct_results",
+ ("ct_results failed: %d",res_ret),NULL);
+
+ }
+ }
+
+ ret = ct_cmd_drop(sybcon->cmd);
+ sybcon->cmd = NULL;
+ RETURN_ON_FAIL(conn, ret, "ct_cmd_drop",
+ ("ct_cmd_drop failed: %d", ret), NULL);
+
+ debug(2, ("password %sfound", return_passwd ? "" : "not "));
+ debug(3, ("returning password:[%s]", return_passwd?return_passwd:""));
+
+ return return_passwd;
+}
+
+#define SYBASE_EXEC_STATE_START 0
+#define SYBASE_EXEC_STATE_RESULTS 1
+#define SYBASE_EXEC_STATE_FETCH 2
+#define SYBASE_EXEC_STATE_END 3
+#define SYBASE_EXEC_STATE_ERROR 4
+
+struct colinfo {
+ CS_SMALLINT indicator;
+ char *data;
+ struct colinfo *next;
+};
+
+struct sybase_exec_data {
+ int state;
+ CS_RETCODE results_ret;
+ CS_INT result_type;
+ CS_RETCODE fetch_ret;
+ struct colinfo *coldata;
+ CS_COMMAND *cmd;
+};
+
+void *
+rad_sybase_exec(conn, query)
+ struct sql_connection *conn;
+ char *query;
+{
+ struct sybase_connection *sybcon;
+ struct sybase_exec_data *sinfo;
+
+ if (!conn)
+ return NULL;
+ debug(2, ("query: %s", query));
+
+ if (sybase_do_query(conn, query) < 0)
+ return NULL;
+
+ sybcon = conn->data;
+ sinfo = emalloc(sizeof *sinfo);
+ sinfo->state = SYBASE_EXEC_STATE_START;
+ sinfo->cmd = sybcon->cmd;
+ sinfo->results_ret = CS_SUCCEED;
+ sinfo->result_type = CS_CMD_SUCCEED;
+ sinfo->fetch_ret = CS_SUCCEED;
+ sinfo->coldata = NULL;
+ sybcon->cmd = NULL;
+
+ return (void*)sinfo;
+}
+
+char *
+rad_sybase_column(data, ncol)
+ void *data;
+ int ncol;
+{
+ struct sybase_exec_data *sinfo;
+ struct colinfo *cp;
+ int i;
+
+ if (!data)
+ return NULL;
+
+ sinfo = (struct sybase_exec_data *)data;
+ for (i=0, cp=sinfo->coldata; i<ncol && cp!=NULL; cp=cp->next, i++)
+ ;
+
+ if (cp == NULL) {
+ radlog(L_ERR,
+ _("too few columns returned (%d req'd)"), ncol);
+ return NULL;
+ }
+
+ debug(10, ("col %d:[%s]", ncol, cp->data ? cp->data : ""));
+ return cp->data;
+}
+
+#define MIN(a, b) (a < b ? a : b)
+#define MAX(a, b) (a > b ? a : b)
+#define MAX_CHAR_BUF 1024
+
+static CS_INT
+data_len(column)
+CS_DATAFMT *column;
+{
+ CS_INT len;
+
+ switch ((int) column->datatype) {
+ case CS_CHAR_TYPE:
+ case CS_VARCHAR_TYPE:
+ case CS_TEXT_TYPE:
+ case CS_IMAGE_TYPE:
+ len = MIN(column->maxlength, MAX_CHAR_BUF);
+ break;
+ case CS_BINARY_TYPE:
+ case CS_VARBINARY_TYPE:
+ len = MIN((2 * column->maxlength) + 2, MAX_CHAR_BUF);
+ break;
+ case CS_BIT_TYPE:
+ case CS_TINYINT_TYPE:
+ len = 3;
+ break;
+ case CS_SMALLINT_TYPE:
+ len = 6;
+ break;
+ case CS_INT_TYPE:
+ len = 11;
+ break;
+ case CS_REAL_TYPE:
+ case CS_FLOAT_TYPE:
+ len = 20;
+ break;
+ case CS_MONEY_TYPE:
+ case CS_MONEY4_TYPE:
+ len = 24;
+ break;
+ case CS_DATETIME_TYPE:
+ case CS_DATETIME4_TYPE:
+ len = 30;
+ break;
+ case CS_NUMERIC_TYPE:
+ case CS_DECIMAL_TYPE:
+ len = (CS_MAX_PREC + 2);
+ break;
+ default:
+ len = column->maxlength;
+ break;
+ }
+
+ return MAX(strlen(column->name) + 1, len);
+}
+
+static struct colinfo *
+describe(cmd)
+ CS_COMMAND *cmd;
+{
+
+ CS_RETCODE ret;
+ CS_INT num_cols, i;
+ CS_DATAFMT datafmt;
+ struct colinfo start, *curr;
+
+ ret = ct_res_info(cmd, CS_NUMDATA, &num_cols, CS_UNUSED, NULL);
+ if (ret != CS_SUCCEED)
+ {
+ debug(1, ("ct_res_info failed: %d", ret));
+ radlog(L_ERR, _("ct_res_info failed: %d"), ret);
+ return NULL;
+ }
+ if (num_cols <= 0)
+ {
+ debug(1, ("num_cols <= 0: %d", num_cols));
+ radlog(L_ERR, _("num_cols <= 0: %d"), num_cols);
+ return NULL;
+ }
+
+ debug(10, ("num_cols: %d", num_cols));
+ for (curr = &start, i = 0; i < num_cols; i++)
+ {
+ if((ret = ct_describe(cmd, (i+1), &datafmt)) != CS_SUCCEED)
+ {
+ debug(1, ("ct_describe failed: %d", ret));
+ radlog(L_ERR, _("ct_describe failed: %d"), ret);
+ break;
+ }
+ datafmt.maxlength = data_len(&datafmt) + 1;
+ datafmt.datatype = CS_CHAR_TYPE;
+ datafmt.format = CS_FMT_NULLTERM;
+ debug(10, ("col %d len: %d", i, datafmt.maxlength));
+
+ curr->next = emalloc(sizeof(struct colinfo));
+ curr = curr->next;
+ curr->data = emalloc(datafmt.maxlength);
+
+ if ((ret = ct_bind(cmd, (i+1), &datafmt, curr->data, NULL,
+ &curr->indicator)) != CS_SUCCEED)
+ {
+ debug(1, ("ct_bind failed: %d", ret));
+ radlog(L_ERR, _("ct_bind failed: %d"), ret);
+ break;
+ }
+ }
+
+ curr->next = NULL;
+ return start.next;
+}
+
+static void
+free_coldata(data)
+ struct colinfo *data;
+{
+ struct colinfo *curr, *junk;
+
+ for (curr = data; curr != NULL; ) {
+ if (curr->data != NULL)
+ efree(curr->data);
+ junk = curr;
+ curr = curr->next;
+ efree(junk);
+ }
+}
+
+/*ARGSUSED*/
+int
+rad_sybase_next_tuple(conn, data)
+ struct sql_connection *conn;
+ void *data;
+{
+ struct sybase_connection *sybcon;
+ struct sybase_exec_data *sinfo;
+ CS_INT fcnt;
+ int loop = 1;
+
+ if (!conn || !data)
+ return -1;
+
+ sybcon = conn->data;
+ sinfo = (struct sybase_exec_data *)data;
+
+ while (loop) {
+ debug(10, ("state = %d", sinfo->state));
+ switch (sinfo->state) {
+ case SYBASE_EXEC_STATE_START:
+ case SYBASE_EXEC_STATE_RESULTS:
+ sinfo->state = SYBASE_EXEC_STATE_RESULTS;
+ sinfo->results_ret =
+ ct_results(sinfo->cmd, &sinfo->result_type);
+ switch (sinfo->results_ret) {
+ case CS_SUCCEED:
+ switch (sinfo->result_type)
+ {
+ case CS_ROW_RESULT:
+ case CS_PARAM_RESULT:
+ case CS_STATUS_RESULT:
+ case CS_CURSOR_RESULT:
+ case CS_COMPUTE_RESULT:
+ /* Setup the column bindings */
+ if (sinfo->coldata != NULL)
+ free_coldata(sinfo->coldata);
+ sinfo->coldata = describe(sinfo->cmd);
+ sinfo->state = SYBASE_EXEC_STATE_FETCH;
+ break;
+ case CS_CMD_SUCCEED:
+ case CS_CMD_DONE:
+ break;
+ case CS_CMD_FAIL:
+ /* error reported via callback */
+ break;
+ default:
+ debug(2, ("ct_results err: %d",
+ sinfo->result_type));
+ break;
+ }
+ break;
+ case CS_END_RESULTS:
+ sinfo->state = SYBASE_EXEC_STATE_END;
+ break;
+ default:
+ sinfo->state = SYBASE_EXEC_STATE_ERROR;
+ RETURN_ON_FAIL(conn, sinfo->results_ret,
+ "ct_results", ("ct_results failed: %d",
+ sinfo->results_ret), -1);
+ loop = 0;
+ return -1;
+ }
+ break;
+ case SYBASE_EXEC_STATE_FETCH:
+ loop = 0;
+ sinfo->fetch_ret = ct_fetch(sinfo->cmd, CS_UNUSED,
+ CS_UNUSED, CS_UNUSED,&fcnt);
+ switch (sinfo->fetch_ret) {
+ case CS_SUCCEED:
+ break;
+ case CS_ROW_FAIL:
+ debug(2, ("ct_fetch row fail: %d",
+ sinfo->fetch_ret));
+ break;
+ case CS_END_DATA:
+ sinfo->state = SYBASE_EXEC_STATE_RESULTS;
+ loop = 1;
+ break;
+ default:
+ debug(2,("ct_fetch fail: %d",sinfo->fetch_ret));
+ sinfo->state = SYBASE_EXEC_STATE_ERROR;
+ loop = 1;
+ break;
+ }
+ break;
+ case SYBASE_EXEC_STATE_END:
+ loop = 0;
+ return 1;
+ break;
+ case SYBASE_EXEC_STATE_ERROR:
+ loop = 0;
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*ARGSUSED*/
+void
+rad_sybase_free(conn, data)
+ struct sql_connection *conn;
+ void *data;
+{
+ struct sybase_connection *sybcon;
+ struct sybase_exec_data *sinfo;
+ CS_RETCODE ret;
+
+ if (!data)
+ return;
+
+ debug(20, ("freeing command data"));
+ sinfo = (struct sybase_exec_data *)data;
+
+ if (conn && conn->data)
+ {
+ if (sinfo->state != SYBASE_EXEC_STATE_END) {
+ debug(20, ("cancelling pending command"));
+ ret = ct_cancel(NULL, sinfo->cmd, CS_CANCEL_ALL);
+ debug(20, ("cancelled pending command"));
+ }
+ ret = ct_cmd_drop(sinfo->cmd);
+ }
+
+ if (sinfo->coldata)
+ free_coldata(sinfo->coldata);
+
+ debug(20, ("data freed"));
+
+ efree(sinfo);
+}
+
+SQL_DISPATCH_TAB sybase_dispatch_tab[] = {
+ "sybase",
+ 3000,
+ rad_sybase_reconnect,
+ rad_sybase_disconnect,
+ rad_sybase_query,
+ rad_sybase_getpwd,
+ rad_sybase_exec,
+ rad_sybase_column,
+ rad_sybase_next_tuple,
+ rad_sybase_free
+};
+
+#endif
+
- [Bug-gnu-radius] Sybase and SecurID patch for GNU RADIUS 0.96.2,
Steve Bleazard <=