This patch merges changes from pppd's radiusclient code to libradiusclient.

Author: Vladislav Bogdanov <slava@nsys.by>

Updates: http://bubble.nsys.by/patches/radiusclient/

diff -urNp radiusclient-0.3.2/COPYRIGHT radiusclient.ppp/COPYRIGHT
--- radiusclient-0.3.2/COPYRIGHT	1998-09-24 22:10:24.000000000 +0300
+++ radiusclient.ppp/COPYRIGHT	2002-01-22 18:03:00.000000000 +0200
@@ -1,6 +1,22 @@
 See the respective source files to find out which copyrights apply.
 
 ------------------------------------------------------------------------------
+Copyright (C) 2002 Roaring Penguin Software Inc.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose and without fee is hereby granted, provided that this
+copyright and permission notice appear on all copies and supporting
+documentation, the name of Roaring Penguin Software Inc. not be used
+in advertising or publicity pertaining to distribution of the program
+without specific prior permission, and notice be given in supporting
+documentation that copying and distribution is by permission of
+Roaring Penguin Software Inc..
+
+Roaring Penguin Software Inc. makes no representations about the
+suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+
+------------------------------------------------------------------------------
 Copyright (C) 1995,1996,1997,1998 Lars Fenneberg <lf@elemental.net>
 
 Permission to use, copy, modify, and distribute this software for any
@@ -51,7 +67,7 @@ University of Michigan and Merit Network
 special, indirect, incidental or consequential damages with respect to any
 claim by Licensee or any third party arising from use of the software.
 ------------------------------------------------------------------------------
-Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. 
+Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991.
 All rights reserved.
 
 License to copy and use this software is granted provided that it
diff -urNp radiusclient-0.3.2/etc/dictionary radiusclient.ppp/etc/dictionary
--- radiusclient-0.3.2/etc/dictionary	1998-01-10 19:44:26.000000000 +0200
+++ radiusclient.ppp/etc/dictionary	2002-10-01 12:51:01.000000000 +0300
@@ -23,6 +23,23 @@
 #	7		= 1	(integer encoding)
 #
 
+# The dictionary format now supports vendor-specific attributes.
+# Vendors are introduced like this:
+#
+#	VENDOR vendor_name vendor_number
+#
+# For example:
+#
+#	VENDOR RoaringPenguin 10055
+#
+# Vendor-specific attributes have a fifth field with the name of the
+# vendor.  For example:
+#
+#       ATTRIBUTE RP-Upstream-Speed-Limit 1 integer RoaringPenguin
+#
+# introduces a Roaring Penguin vendor-specific attribbute with name
+# RP-Upstream-Speed-Limit, number 1, type integer and vendor RoaringPenguin.
+
 #
 #	Following are the proper new names. Use these.
 #
@@ -48,11 +65,13 @@ ATTRIBUTE	Callback-Id		20	string
 ATTRIBUTE	Framed-Route		22	string
 ATTRIBUTE	Framed-IPX-Network	23	ipaddr
 ATTRIBUTE	State			24	string
+ATTRIBUTE	Class			25	string
 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	Acct-Status-Type	40	integer
 ATTRIBUTE	Acct-Delay-Time		41	integer
 ATTRIBUTE	Acct-Input-Octets	42	integer
@@ -60,11 +79,17 @@ 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       Chap-Challenge          60      string
 ATTRIBUTE	NAS-Port-Type		61	integer
 ATTRIBUTE	Port-Limit		62	integer
 ATTRIBUTE	Connect-Info		77	string
 
+# RFC 2869
+ATTRIBUTE	Acct-Interim-Interval	85	integer
+
 #
 #	Experimental Non Protocol Attributes used by Cistron-Radiusd
 #
@@ -94,6 +119,14 @@ ATTRIBUTE	Crypt-Password		1006	string
 ATTRIBUTE	Connect-Rate		1007	integer
 
 #
+#       Experimental, implementation specific attributes
+#
+# Limit session traffic
+ATTRIBUTE	Session-Octets-Limit	227	integer
+# What to assume as limit - 0 in+out, 1 in, 2 out, 3 max(in,out)
+ATTRIBUTE	Octets-Direction	228	integer
+
+#
 #	Integer Translations
 #
 
@@ -210,3 +243,11 @@ VALUE		Add-Port-To-IP-Address	Yes			1
 #VALUE		Server-Config		Password-Expiration	30
 #VALUE		Server-Config		Password-Warning	5
 
+#       Octets-Direction
+VALUE		Octets-Direction        Sum			0
+VALUE		Octets-Direction        Input			1
+VALUE		Octets-Direction        Output			2
+VALUE		Octets-Direction        MaxOveral		3
+VALUE		Octets-Direction        MaxSession		4
+
+INCLUDE /etc/radiusclient/dictionary.microsoft
diff -urNp radiusclient-0.3.2/etc/dictionary.ascend radiusclient.ppp/etc/dictionary.ascend
--- radiusclient-0.3.2/etc/dictionary.ascend	1998-01-10 19:44:26.000000000 +0200
+++ radiusclient.ppp/etc/dictionary.ascend	2002-01-22 18:03:01.000000000 +0200
@@ -1,8 +1,6 @@
 #
 # Ascend dictionary.
 #
-#		Enable by putting the line "$INCLUDE dictionary.ascend" into
-#		the main dictionary file.
 #
 # Version:	1.00  21-Jul-1997  Jens Glaser <jens@regio.net>
 #
diff -urNp radiusclient-0.3.2/etc/dictionary.compat radiusclient.ppp/etc/dictionary.compat
--- radiusclient-0.3.2/etc/dictionary.compat	1998-01-10 19:44:26.000000000 +0200
+++ radiusclient.ppp/etc/dictionary.compat	2002-01-22 18:03:01.000000000 +0200
@@ -1,7 +1,5 @@
 #
 #	Obsolete names for backwards compatibility with older users files.
-#	Move the $INCLUDE in the main dictionary file to the end if you want
-#	these names to be used in the "details" logfile.
 #
 ATTRIBUTE	Client-Id		4	ipaddr
 ATTRIBUTE	Client-Port-Id		5	integer
diff -urNp radiusclient-0.3.2/etc/dictionary.microsoft radiusclient.ppp/etc/dictionary.microsoft
--- radiusclient-0.3.2/etc/dictionary.microsoft	1970-01-01 03:00:00.000000000 +0300
+++ radiusclient.ppp/etc/dictionary.microsoft	2002-03-06 15:23:09.000000000 +0200
@@ -0,0 +1,81 @@
+#
+#	Microsoft's VSA's, from RFC 2548
+#
+#	$Id: dictionary.microsoft,v 1.1 2002/03/06 13:23:09 dfs Exp $
+#
+
+VENDOR		Microsoft	311	Microsoft
+
+ATTRIBUTE	MS-CHAP-Response	1	string	Microsoft
+ATTRIBUTE	MS-CHAP-Error		2	string	Microsoft
+ATTRIBUTE	MS-CHAP-CPW-1		3	string	Microsoft
+ATTRIBUTE	MS-CHAP-CPW-2		4	string	Microsoft
+ATTRIBUTE	MS-CHAP-LM-Enc-PW	5	string	Microsoft
+ATTRIBUTE	MS-CHAP-NT-Enc-PW	6	string	Microsoft
+ATTRIBUTE	MS-MPPE-Encryption-Policy 7	string	Microsoft
+# This is referred to as both singular and plural in the RFC.
+# Plural seems to make more sense.
+ATTRIBUTE	MS-MPPE-Encryption-Type 8	string	Microsoft
+ATTRIBUTE	MS-MPPE-Encryption-Types  8	string	Microsoft
+ATTRIBUTE	MS-RAS-Vendor		9	integer	Microsoft
+ATTRIBUTE	MS-CHAP-Domain		10	string	Microsoft
+ATTRIBUTE	MS-CHAP-Challenge	11	string	Microsoft
+ATTRIBUTE	MS-CHAP-MPPE-Keys	12	string	Microsoft
+ATTRIBUTE	MS-BAP-Usage		13	integer	Microsoft
+ATTRIBUTE	MS-Link-Utilization-Threshold 14 integer	Microsoft
+ATTRIBUTE	MS-Link-Drop-Time-Limit	15	integer	Microsoft
+ATTRIBUTE	MS-MPPE-Send-Key	16	string	Microsoft
+ATTRIBUTE	MS-MPPE-Recv-Key	17	string	Microsoft
+ATTRIBUTE	MS-RAS-Version		18	string	Microsoft
+ATTRIBUTE	MS-Old-ARAP-Password	19	string	Microsoft
+ATTRIBUTE	MS-New-ARAP-Password	20	string	Microsoft
+ATTRIBUTE	MS-ARAP-PW-Change-Reason 21	integer	Microsoft
+
+ATTRIBUTE	MS-Filter		22	string	Microsoft
+ATTRIBUTE	MS-Acct-Auth-Type	23	integer	Microsoft
+ATTRIBUTE	MS-Acct-EAP-Type	24	integer	Microsoft
+
+ATTRIBUTE	MS-CHAP2-Response	25	string	Microsoft
+ATTRIBUTE	MS-CHAP2-Success	26	string	Microsoft
+ATTRIBUTE	MS-CHAP2-CPW		27	string	Microsoft
+
+ATTRIBUTE	MS-Primary-DNS-Server	28	ipaddr	Microsoft
+ATTRIBUTE	MS-Secondary-DNS-Server	29	ipaddr	Microsoft
+ATTRIBUTE	MS-Primary-NBNS-Server	30	ipaddr	Microsoft
+ATTRIBUTE	MS-Secondary-NBNS-Server 31	ipaddr	Microsoft
+
+#ATTRIBUTE	MS-ARAP-Challenge	33	string	Microsoft
+
+
+#
+#	Integer Translations
+#
+
+#	MS-BAP-Usage Values
+
+VALUE		MS-BAP-Usage		Not-Allowed	0
+VALUE		MS-BAP-Usage		Allowed		1
+VALUE		MS-BAP-Usage		Required	2
+
+#	MS-ARAP-Password-Change-Reason Values
+
+VALUE	MS-ARAP-PW-Change-Reason	Just-Change-Password		1
+VALUE	MS-ARAP-PW-Change-Reason	Expired-Password		2
+VALUE	MS-ARAP-PW-Change-Reason	Admin-Requires-Password-Change	3
+VALUE	MS-ARAP-PW-Change-Reason	Password-Too-Short		4
+
+#	MS-Acct-Auth-Type Values
+
+VALUE		MS-Acct-Auth-Type	PAP		1
+VALUE		MS-Acct-Auth-Type	CHAP		2
+VALUE		MS-Acct-Auth-Type	MS-CHAP-1	3
+VALUE		MS-Acct-Auth-Type	MS-CHAP-2	4
+VALUE		MS-Acct-Auth-Type	EAP		5
+
+#	MS-Acct-EAP-Type Values
+
+VALUE		MS-Acct-EAP-Type	MD5		4
+VALUE		MS-Acct-EAP-Type	OTP		5
+VALUE		MS-Acct-EAP-Type	Generic-Token-Card	6
+VALUE		MS-Acct-EAP-Type	TLS		13
+
diff -urNp radiusclient-0.3.2/etc/Makefile.am radiusclient.ppp/etc/Makefile.am
--- radiusclient-0.3.2/etc/Makefile.am	1998-06-28 03:08:16.000000000 +0300
+++ radiusclient.ppp/etc/Makefile.am	2002-10-05 20:49:00.000000000 +0300
@@ -15,20 +15,25 @@ CLEANFILES = *~ radiusclient.conf
 sbindir = @sbindir@
 pkgsysconfdir = @pkgsysconfdir@
 pkgsysconf_DATA = issue port-id-map radiusclient.conf \
-	dictionary dictionary.ascend dictionary.compat dictionary.merit
+	dictionary dictionary.ascend dictionary.compat dictionary.merit \
+	dictionary.microsoft
 
 EXTRA_DIST = issue port-id-map dictionary dictionary.ascend \
-	dictionary.compat dictionary.merit servers radiusclient.conf.in
+	dictionary.compat dictionary.merit dictionary.microsoft \
+	realms servers radiusclient.conf.in
 
 radiusclient.conf: radiusclient.conf.in
 	sed -e 's|@sbin''dir@|$(sbindir)|g' \
 	    -e 's|@pkgsysconf''dir@|$(pkgsysconfdir)|g' \
 	    <$(srcdir)/radiusclient.conf.in >radiusclient.conf
 
-install-data-local: servers
+install-data-local: realms servers
 	$(mkinstalldirs) $(pkgsysconfdir); \
+        echo " $(INSTALL) -m600 $(srcdir)/realms $(pkgsysconfdir)/realms"; \
+        $(INSTALL) -m600 $(srcdir)/realms $(pkgsysconfdir)/realms; \
         echo " $(INSTALL) -m600 $(srcdir)/servers $(pkgsysconfdir)/servers"; \
         $(INSTALL) -m600 $(srcdir)/servers $(pkgsysconfdir)/servers
 
 uninstall-local:
+	rm -f $(pkgsysconfdir)/realms
 	rm -f $(pkgsysconfdir)/servers
diff -urNp radiusclient-0.3.2/etc/radiusclient.conf.in radiusclient.ppp/etc/radiusclient.conf.in
--- radiusclient-0.3.2/etc/radiusclient.conf.in	1998-03-06 23:15:27.000000000 +0200
+++ radiusclient.ppp/etc/radiusclient.conf.in	2002-10-01 12:51:01.000000000 +0300
@@ -5,23 +5,23 @@
 # if you specify "radius,local" then the RADIUS server is asked
 # first then the local one. if only one keyword is specified only
 # this server is asked.
-auth_order	radius,local
+auth_order	radius
 
-# maximum login tries a user has
+# maximum login tries a user has (default 4)
 login_tries	4
 
-# timeout for all login tries
-# if this time is exceeded the user is kicked out
+# timeout for all login tries (default 60)
+# if this time is exceeded the user is kicked out 
 login_timeout	60
 
 # name of the nologin file which when it exists disables logins.
 # it may be extended by the ttyname which will result in
 # a terminal specific lock (e.g. /etc/nologin.ttyS2 will disable
-# logins on /dev/ttyS2)
+# logins on /dev/ttyS2)   (default /etc/nologin)
 nologin /etc/nologin
 
 # name of the issue file. it's only display when no username is passed
-# on the radlogin command line
+# on the radlogin command line  (default /etc/radiusclient/issue)
 issue	@pkgsysconfdir@/issue
 
 # RADIUS settings
@@ -34,12 +34,12 @@ issue	@pkgsysconfdir@/issue
 # RADIUS listens separated by a colon from the hostname. if
 # no port is specified /etc/services is consulted of the radius
 # service. if this fails also a compiled in default is used.
-authserver 	localhost
+authserver 	localhost:1812
 
 # RADIUS server to use for accouting requests. All that I
 # said for authserver applies, too. 
 #
-acctserver 	localhost
+acctserver 	localhost:1813
 
 # file holding shared secrets used for the communication
 # between the RADIUS client and server
@@ -49,7 +49,8 @@ servers		@pkgsysconfdir@/servers
 # just like in the normal RADIUS distributions
 dictionary 	@pkgsysconfdir@/dictionary
 
-# program to call for a RADIUS authenticated login
+# program to call for a RADIUS authenticated login 
+# (default /usr/sbin/login.radius)
 login_radius	@sbindir@/login.radius
 
 # file which holds sequence number for communication with the
@@ -71,6 +72,18 @@ radius_timeout	10
 # resend request this many times before trying the next server
 radius_retries	3
 
+# NAS-Identifier
+#
+# If supplied, this option will cause the client to send the given string
+# as the contents of the NAS-Identifier attribute in RADIUS requests.  No
+# NAS-IP-Address attribute will be sent in this case.
+#
+# The default behavior is to send a NAS-IP-Address option and not send
+# a NAS-Identifier.  The value of the NAS-IP-Address option is chosen
+# by resolving the system hostname.
+
+# nas_identifier MyUniqueNASName
+
 # LOCAL settings
 
 # program to execute for local login
diff -urNp radiusclient-0.3.2/etc/realms radiusclient.ppp/etc/realms
--- radiusclient-0.3.2/etc/realms	1970-01-01 03:00:00.000000000 +0300
+++ radiusclient.ppp/etc/realms	2002-10-05 07:35:24.000000000 +0300
@@ -0,0 +1,22 @@
+# /etc/radiusclient/realms
+#
+# Handle realm @netservers.co.uk on an internal RADIUS server
+# (note the server must be told to strip the realm)
+
+#authserver netservers.co.uk 192.168.1.1:1812
+#acctserver netservers.co.uk 192.168.1.1:1813
+
+# users in realm @example.com are handled by separate servers
+
+#authserver example.com 10.0.0.1:1812
+#acctserver example.com 10.0.0.2:1813
+
+# the DEFAULT realm matches users that do not supply a realm
+
+#authserver DEFAULT 192.168.1.1:1812
+#acctserver DEFAULT 192.168.1.1:1813
+
+# Any realms that do not match in the realms file automatically fall 
+# through to the standard radius plugin which uses the servers in the 
+# radiusclient.conf file.  Note that this is different than the
+# DEFAULT realm match, above.
diff -urNp radiusclient-0.3.2/include/radiusclient.h radiusclient.ppp/include/radiusclient.h
--- radiusclient-0.3.2/include/radiusclient.h	1999-01-07 01:53:04.000000000 +0200
+++ radiusclient.ppp/include/radiusclient.h	2002-11-26 11:44:01.000000000 +0200
@@ -38,8 +38,15 @@
 # define __P(protos) ()
 #endif
 
+#ifndef _UINT4_T
+#ifdef _LP64
+typedef unsigned int UINT4;
+typedef int          INT4;
+#else
 typedef unsigned long UINT4;
-typedef long 	      INT4;
+typedef long          INT4;
+#endif
+#endif
 
 #define AUTH_VECTOR_LEN		16
 #define AUTH_PASS_LEN		(3 * 16) /* multiple of 16 */
@@ -67,7 +74,7 @@ typedef long 	      INT4;
 typedef struct server {
 	int max;
 	char *name[SERVER_MAX];
-	unsigned short port[SERVER_MAX];	
+	unsigned short port[SERVER_MAX];
 } SERVER;
 
 typedef struct pw_auth_hdr
@@ -83,8 +90,8 @@ typedef struct pw_auth_hdr
 #define MAX_SECRET_LENGTH		(3 * 16) /* MUST be multiple of 16 */
 #define CHAP_VALUE_LENGTH		16
 
-#define PW_AUTH_UDP_PORT		1645
-#define PW_ACCT_UDP_PORT		1646
+#define PW_AUTH_UDP_PORT		1812
+#define PW_ACCT_UDP_PORT		1813
 
 #define PW_TYPE_STRING			0
 #define PW_TYPE_INTEGER			1
@@ -154,6 +161,18 @@ typedef struct pw_auth_hdr
 #define	PW_PORT_LIMIT                   62      /* integer */
 #define PW_LOGIN_LAT_PORT               63      /* string */
 
+/* Vendor RADIUS attribute-value pairs */
+#define PW_MS_CHAP_CHALLENGE		11	/* string */
+#define PW_MS_CHAP_RESPONSE		1	/* string */
+#define PW_MS_CHAP2_RESPONSE		25	/* string */
+#define PW_MS_CHAP2_SUCCESS		26	/* string */
+#define PW_MS_MPPE_ENCRYPTION_POLICY	7	/* string */
+#define PW_MS_MPPE_ENCRYPTION_TYPE	8	/* string */
+#define PW_MS_MPPE_ENCRYPTION_TYPES PW_MS_MPPE_ENCRYPTION_TYPE
+#define PW_MS_CHAP_MPPE_KEYS		12	/* string */
+#define PW_MS_MPPE_SEND_KEY		16	/* string */
+#define PW_MS_MPPE_RECV_KEY		17	/* string */
+
 /*	Accounting */
 
 #define	PW_ACCT_STATUS_TYPE		40	/* integer */
@@ -169,11 +188,19 @@ typedef struct pw_auth_hdr
 #define PW_ACCT_MULTI_SESSION_ID	50	/* string */
 #define PW_ACCT_LINK_COUNT		51	/* integer */
 
+/* From RFC 2869 */
+#define PW_ACCT_INTERIM_INTERVAL        85	/* integer */
+
 /*	Merit Experimental Extensions */
 
 #define PW_USER_ID                      222     /* string */
 #define PW_USER_REALM                   223     /* string */
 
+
+/*      Session limits */
+#define PW_SESSION_OCTETS_LIMIT		227    /* integer */
+#define PW_OCTETS_DIRECTION		228    /* integer */
+
 /*	Integer Translations */
 
 /*	SERVICE TYPES	*/
@@ -260,7 +287,7 @@ typedef struct pw_auth_hdr
 #define PW_CALLBACK             16
 #define PW_USER_ERROR           17
 #define PW_HOST_REQUEST         18
- 
+
 /*     NAS PORT TYPES    */
 
 #define PW_ASYNC		0
@@ -275,6 +302,17 @@ typedef struct pw_auth_hdr
 #define PW_LOCAL	2
 #define PW_REMOTE	3
 
+/*    Session-Octets-Limit    */
+#define PW_OCTETS_DIRECTION_SUM	0
+#define PW_OCTETS_DIRECTION_IN	1
+#define PW_OCTETS_DIRECTION_OUT	2
+#define PW_OCTETS_DIRECTION_MAX	3
+
+
+/* Vendor codes */
+#define VENDOR_NONE     (-1)
+#define VENDOR_MICROSOFT	311
+
 /* Server data structures */
 
 typedef struct dict_attr
@@ -282,6 +320,7 @@ typedef struct dict_attr
 	char              name[NAME_LENGTH + 1];	/* attribute name */
 	int               value;			/* attribute index */
 	int               type;				/* string, int, etc. */
+	int               vendorcode;                   /* vendor code */
 	struct dict_attr *next;
 } DICT_ATTR;
 
@@ -293,20 +332,29 @@ typedef struct dict_value
 	struct dict_value *next;
 } DICT_VALUE;
 
+typedef struct vendor_dict
+{
+    char vendorname[NAME_LENGTH + 1];
+    int vendorcode;
+    DICT_ATTR *attributes;
+    struct vendor_dict *next;
+} VENDOR_DICT;
+
 typedef struct value_pair
 {
 	char               name[NAME_LENGTH + 1];
 	int                attribute;
+	int                vendorcode;
 	int                type;
 	UINT4              lvalue;
-	char               strvalue[AUTH_STRING_LEN + 1];
+	u_char             strvalue[AUTH_STRING_LEN + 1];
 	struct value_pair *next;
 } VALUE_PAIR;
 
 /* don't change this, as it has to be the same as in the Merit radiusd code */
 #define MGMT_POLL_SECRET	"Hardlyasecret"
 
-/* 	Define return codes from "SendServer" utility */
+/*	Define return codes from "SendServer" utility */
 
 #define BADRESP_RC	-2
 #define ERROR_RC	-1
@@ -325,6 +373,12 @@ typedef struct send_data /* Used to pass
 	VALUE_PAIR     *receive_pairs;  /* Where to place received a/v pairs */
 } SEND_DATA;
 
+typedef struct request_info
+{
+	char		secret[MAX_SECRET_LENGTH + 1];
+	u_char		request_vector[AUTH_VECTOR_LEN];
+} REQUEST_INFO;
+
 #ifndef MIN
 #define MIN(a, b)     ((a) < (b) ? (a) : (b))
 #endif
@@ -350,11 +404,12 @@ __BEGIN_DECLS
 
 /*	avpair.c		*/
 
-VALUE_PAIR *rc_avpair_add __P((VALUE_PAIR **, int, void *, int));
+VALUE_PAIR *rc_avpair_add __P((VALUE_PAIR **, int, void *, int, int));
 int rc_avpair_assign __P((VALUE_PAIR *, void *, int));
-VALUE_PAIR *rc_avpair_new __P((int, void *, int));
+VALUE_PAIR *rc_avpair_new __P((int, void *, int, int));
 VALUE_PAIR *rc_avpair_gen __P((AUTH_HDR *));
 VALUE_PAIR *rc_avpair_get __P((VALUE_PAIR *, UINT4));
+VALUE_PAIR *rc_avpair_copy __P((VALUE_PAIR *));
 void rc_avpair_insert __P((VALUE_PAIR **, VALUE_PAIR *, VALUE_PAIR *));
 void rc_avpair_free __P((VALUE_PAIR *));
 int rc_avpair_parse __P((char *, VALUE_PAIR **));
@@ -365,9 +420,12 @@ VALUE_PAIR *rc_avpair_readin __P((FILE *
 
 void rc_buildreq __P((SEND_DATA *, int, char *, unsigned short, int, int));
 unsigned char rc_get_seqnbr __P((void));
-int rc_auth __P((UINT4, VALUE_PAIR *, VALUE_PAIR **, char *));
+int rc_auth __P((UINT4, VALUE_PAIR *, VALUE_PAIR **, char *, REQUEST_INFO *));
+int rc_auth_using_server __P((SERVER *, UINT4, VALUE_PAIR *, VALUE_PAIR **,
+			      char *, REQUEST_INFO *));
 int rc_auth_proxy __P((VALUE_PAIR *, VALUE_PAIR **, char *));
 int rc_acct __P((UINT4, VALUE_PAIR *));
+int rc_acct_using_server __P((SERVER *, UINT4, VALUE_PAIR *));
 int rc_acct_proxy __P((VALUE_PAIR *));
 int rc_check __P((char *, unsigned short, char *));
 
@@ -387,10 +445,12 @@ int rc_find_server __P((char *, UINT4 *,
 /*	dict.c			*/
 
 int rc_read_dictionary __P((char *));
-DICT_ATTR *rc_dict_getattr __P((int));
+DICT_ATTR *rc_dict_getattr __P((int, int));
 DICT_ATTR *rc_dict_findattr __P((char *));
 DICT_VALUE *rc_dict_findval __P((char *));
 DICT_VALUE * rc_dict_getval __P((UINT4, char *));
+VENDOR_DICT * rc_dict_findvendor __P((char *));
+VENDOR_DICT * rc_dict_getvendor __P((int));
 
 /*	ip_util.c		*/
 
@@ -409,7 +469,7 @@ void rc_log __P((int, const char *, ...)
 
 /*	sendserver.c		*/
 
-int rc_send_server __P((SEND_DATA *, char *));
+int rc_send_server __P((SEND_DATA *, char *, REQUEST_INFO *));
 
 /*	util.c			*/
 
diff -urNp radiusclient-0.3.2/lib/avpair.c radiusclient.ppp/lib/avpair.c
--- radiusclient-0.3.2/lib/avpair.c	1997-12-26 01:28:08.000000000 +0200
+++ radiusclient.ppp/lib/avpair.c	2003-04-19 21:12:53.000000000 +0300
@@ -18,6 +18,9 @@
 #include <includes.h>
 #include <radiusclient.h>
 
+static void rc_extract_vendor_specific_attributes(int attrlen,
+						  unsigned char *ptr,
+						  VALUE_PAIR **vp);
 /*
  * Function: rc_avpair_add
  *
@@ -29,11 +32,12 @@
  *
  */
 
-VALUE_PAIR *rc_avpair_add (VALUE_PAIR **list, int attrid, void *pval, int len)
+VALUE_PAIR *rc_avpair_add (VALUE_PAIR **list, int attrid, void *pval, int len,
+			   int vendorcode)
 {
 	VALUE_PAIR     *vp;
 
-	vp = rc_avpair_new (attrid, pval, len);
+	vp = rc_avpair_new (attrid, pval, len, vendorcode);
 
 	if (vp != (VALUE_PAIR *) NULL)
 	{
@@ -104,12 +108,12 @@ int rc_avpair_assign (VALUE_PAIR *vp, vo
  *
  */
 
-VALUE_PAIR *rc_avpair_new (int attrid, void *pval, int len)
+VALUE_PAIR *rc_avpair_new (int attrid, void *pval, int len, int vendorcode)
 {
 	VALUE_PAIR     *vp = (VALUE_PAIR *) NULL;
 	DICT_ATTR      *pda;
 
-	if ((pda = rc_dict_getattr (attrid)) == (DICT_ATTR *) NULL)
+	if ((pda = rc_dict_getattr (attrid, vendorcode)) == (DICT_ATTR *) NULL)
 	{
 		rc_log(LOG_ERR,"rc_avpair_new: unknown attribute %d", attrid);
 	}
@@ -120,6 +124,7 @@ VALUE_PAIR *rc_avpair_new (int attrid, v
 		{
 			strncpy (vp->name, pda->name, sizeof (vp->name));
 			vp->attribute = attrid;
+			vp->vendorcode = vendorcode;
 			vp->next = (VALUE_PAIR *) NULL;
 			vp->type = pda->type;
 			if (rc_avpair_assign (vp, pval, len) == 0)
@@ -159,8 +164,8 @@ VALUE_PAIR *rc_avpair_gen (AUTH_HDR *aut
 	DICT_ATTR      *attr;
 	VALUE_PAIR     *vp;
 	VALUE_PAIR     *pair;
-	unsigned char          hex[3];		/* For hex string conversion. */
-	char            buffer[256];
+	unsigned char   hex[3];		/* For hex string conversion. */
+	char            buffer[512];
 
 	/*
 	 * Extract attribute-value pairs
@@ -180,7 +185,14 @@ VALUE_PAIR *rc_avpair_gen (AUTH_HDR *aut
 			break;
 		}
 
-		if ((attr = rc_dict_getattr (attribute)) == (DICT_ATTR *) NULL)
+		/* Handle vendor-specific specially */
+		if (attribute == PW_VENDOR_SPECIFIC) {
+		    rc_extract_vendor_specific_attributes(attrlen, ptr, &vp);
+		    ptr += attrlen;
+		    length -= (attrlen + 2);
+		    continue;
+		}
+		if ((attr = rc_dict_getattr (attribute, VENDOR_NONE)) == (DICT_ATTR *) NULL)
 		{
 			*buffer= '\0';	/* Initial length. */
 			for (x_ptr = ptr, x_len = attrlen ;
@@ -205,6 +217,7 @@ VALUE_PAIR *rc_avpair_gen (AUTH_HDR *aut
 			}
 			strcpy (pair->name, attr->name);
 			pair->attribute = attr->value;
+			pair->vendorcode = VENDOR_NONE;
 			pair->type = attr->type;
 			pair->next = (VALUE_PAIR *) NULL;
 
@@ -240,6 +253,96 @@ VALUE_PAIR *rc_avpair_gen (AUTH_HDR *aut
 }
 
 /*
+ * Function: rc_extract_vendor_specific_attributes
+ *
+ * Purpose: Extracts vendor-specific attributes, assuming they are in
+ *          the "SHOULD" format recommended by RCF 2138.
+ *
+ * Returns: found value_pair
+ *
+ */
+static void rc_extract_vendor_specific_attributes(int attrlen,
+						  unsigned char *ptr,
+						  VALUE_PAIR **vp)
+{
+    int vendor_id;
+    int vtype;
+    int vlen;
+    UINT4 lvalue;
+    DICT_ATTR *attr;
+    VALUE_PAIR *pair;
+
+    /* ptr is sitting at vendor-ID */
+    if (attrlen < 8) {
+	/* Nothing to see here... */
+	return;
+    }
+
+    /* High-order octet of Vendor-Id must be zero (RFC2138) */
+    if (*ptr) {
+	return;
+    }
+
+    /* Extract vendor_id */
+    vendor_id = (int) (
+	((unsigned int) ptr[1]) * 256 * 256 +
+	((unsigned int) ptr[2]) * 256 +
+	((unsigned int) ptr[3]));
+    /* Bump ptr up to contents */
+    ptr += 4;
+
+    /* Set attrlen to length of data */
+    attrlen -= 4;
+    for (; attrlen; attrlen -= vlen+2, ptr += vlen) {
+	vtype = *ptr++;
+	vlen = *ptr++;
+	vlen -= 2;
+	if (vlen < 0 || vlen > attrlen - 2) {
+	    /* Do not log an error.  We are supposed to be able to cope with
+	       arbitrary vendor-specific gunk */
+	    return;
+	}
+	/* Looks plausible... */
+	if ((attr = rc_dict_getattr(vtype, vendor_id)) == NULL) {
+	    continue;
+	}
+
+	/* TODO: Check that length matches data size!!!!! */
+	pair = (VALUE_PAIR *) malloc(sizeof(VALUE_PAIR));
+	if (!pair) {
+	    rc_log(LOG_CRIT, "rc_avpair_gen: out of memory");
+	    return;
+	}
+	strcpy(pair->name, attr->name);
+	pair->attribute = attr->value;
+	pair->vendorcode = vendor_id;
+	pair->type = attr->type;
+	pair->next = NULL;
+	switch (attr->type) {
+	case PW_TYPE_STRING:
+	    memcpy (pair->strvalue, (char *) ptr, (size_t) vlen);
+	    pair->strvalue[vlen] = '\0';
+	    pair->lvalue = vlen;
+	    rc_avpair_insert (vp, (VALUE_PAIR *) NULL, pair);
+	    break;
+
+	case PW_TYPE_INTEGER:
+	case PW_TYPE_IPADDR:
+	    memcpy ((char *) &lvalue, (char *) ptr,
+		    sizeof (UINT4));
+	    pair->lvalue = ntohl (lvalue);
+	    rc_avpair_insert (vp, (VALUE_PAIR *) NULL, pair);
+	    break;
+
+	default:
+	    rc_log(LOG_WARNING, "rc_avpair_gen: %s has unknown type", attr->name);
+	    free (pair);
+	    break;
+	}
+    }
+}
+
+/*
  * Function: rc_avpair_get
  *
  * Purpose: Find the first attribute value-pair (which matches the given
@@ -256,15 +359,43 @@ VALUE_PAIR *rc_avpair_get (VALUE_PAIR *v
 		continue;
 	}
 	return (vp);
-} 
+}
+
+/*
+ * Function: rc_avpair_copy
+ *
+ * Purpose: Return a copy of the existing list "p" ala strdup().
+ *
+ */
+VALUE_PAIR *rc_avpair_copy(VALUE_PAIR *p)
+{
+	VALUE_PAIR *vp, *fp = NULL, *lp = NULL;
+
+	while (p) {
+		vp = malloc(sizeof(VALUE_PAIR));
+		if (!vp) {
+		    rc_log(LOG_CRIT, "rc_avpair_copy: out of memory");
+		    return NULL; /* leaks a little but so what */
+		}
+		*vp = *p;
+		if (!fp)
+			fp = vp;
+		if (lp)
+			lp->next = vp;
+		lp = vp;
+		p = p->next;
+	}
+
+	return fp;
+}
 
 /*
  * Function: rc_avpair_insert
  *
  * Purpose: Given the address of an existing list "a" and a pointer
- *	    to an entry "p" in that list, add the value pair "b" to
+ *	    to an entry "p" in that list, add the list "b" to
  *	    the "a" list after the "p" entry.  If "p" is NULL, add
- *	    the value pair "b" to the end of "a".
+ *	    the list "b" to the end of "a".
  *
  */
 
@@ -273,18 +404,15 @@ void rc_avpair_insert (VALUE_PAIR **a, V
 	VALUE_PAIR     *this_node = NULL;
 	VALUE_PAIR     *vp;
 
-	if (b->next != (VALUE_PAIR *) NULL)
-	{
-		rc_log(LOG_CRIT, "rc_avpair_insert: value pair (0x%p) next ptr. (0x%p) not NULL", b, b->next);
-		abort ();
-	}
-
 	if (*a == (VALUE_PAIR *) NULL)
 	{
 		*a = b;
 		return;
 	}
 
+	if (!b)
+		return;
+
 	vp = *a;
 
 	if ( p == (VALUE_PAIR *) NULL) /* run to end of "a" list */
@@ -295,7 +423,7 @@ void rc_avpair_insert (VALUE_PAIR **a, V
 			vp = vp->next;
 		}
 	}
-	else /* look for the "p" entry in the "a" list */
+	else /* look for the "p" entry in the "a" list (or run to end) */
 	{
 		this_node = *a;
 		while (this_node != (VALUE_PAIR *) NULL)
@@ -308,9 +436,15 @@ void rc_avpair_insert (VALUE_PAIR **a, V
 		}
 	}
 
-	b->next = this_node->next;
+	/* add "b" at this_node */
+	vp = this_node->next;
 	this_node->next = b;
 
+	/* run to end of "b" and connect the rest of "a" */
+	while (b->next)
+		b = b->next;
+	b->next = vp;
+
 	return;
 }
 
@@ -331,7 +465,7 @@ void rc_avpair_free (VALUE_PAIR *pair)
 		free (pair);
 		pair = next;
 	}
-} 
+}
 
 /*
  * Function: rc_fieldcpy
@@ -340,7 +474,7 @@ void rc_avpair_free (VALUE_PAIR *pair)
  *          past the data field.
  *
  */
- 
+
 static void rc_fieldcpy (char *string, char **uptr)
 {
 	char           *ptr;
@@ -460,6 +594,7 @@ int rc_avpair_parse (char *buffer, VALUE
 			strcpy (pair->name, attr->name);
 			pair->attribute = attr->value;
 			pair->type = attr->type;
+			pair->vendorcode = attr->vendorcode;
 
 			switch (pair->type)
 			{
@@ -495,7 +630,7 @@ int rc_avpair_parse (char *buffer, VALUE
 				break;
 
 			    case PW_TYPE_IPADDR:
-                                pair->lvalue = rc_get_ipaddr(valstr);
+				pair->lvalue = rc_get_ipaddr(valstr);
 				break;
 
 			    case PW_TYPE_DATE:
@@ -567,7 +702,7 @@ int rc_avpair_tostr (VALUE_PAIR *pair, c
 	*name = *value = '\0';
 
 	if (!pair || pair->name[0] == '\0') {
-		rc_log(LOG_ERR, "rc_avpair_tostr: pair is NULL or empty");		
+		rc_log(LOG_ERR, "rc_avpair_tostr: pair is NULL or empty");
 		return (-1);
 	}
 
@@ -576,7 +711,7 @@ int rc_avpair_tostr (VALUE_PAIR *pair, c
 	switch (pair->type)
 	{
 	    case PW_TYPE_STRING:
-	    	lv--;
+		lv--;
 		ptr = (unsigned char *) pair->strvalue;
 		while (*ptr != '\0')
 		{
@@ -626,7 +761,7 @@ int rc_avpair_tostr (VALUE_PAIR *pair, c
 		return (-1);
 		break;
 	}
-	
+
 	return 0;
 }
 
@@ -646,18 +781,18 @@ VALUE_PAIR *rc_avpair_readin(FILE *input
 	while (fgets(buffer, sizeof(buffer), input) != NULL)
 	{
 		q = buffer;
-		
+
 		while(*q && isspace(*q)) q++;
-	
+
 		if ((*q == '\n') || (*q == '#') || (*q == '\0'))
 			continue;
-	
+
 		if (rc_avpair_parse(q, &vp) < 0) {
 			rc_log(LOG_ERR, "rc_avpair_readin: malformed attribute: %s", buffer);
 			rc_avpair_free(vp);
 			return NULL;
 		}
 	}
-	
+
 	return vp;
 }
diff -urNp radiusclient-0.3.2/lib/buildreq.c radiusclient.ppp/lib/buildreq.c
--- radiusclient-0.3.2/lib/buildreq.c	1998-12-11 13:24:28.000000000 +0200
+++ radiusclient.ppp/lib/buildreq.c	2003-05-02 00:39:30.000000000 +0300
@@ -16,10 +16,48 @@
 unsigned char rc_get_seqnbr(void);
 
 /*
+ * Function: rc_get_nas_id
+ *
+ * Purpose: fills in NAS-Identifier or NAS-IP-Address in request
+ *
+ */
+
+int rc_get_nas_id(VALUE_PAIR **sendpairs)
+{
+	UINT4		client_id;
+	char *nasid;
+
+	nasid = rc_conf_str("nas_identifier");
+	if (strlen(nasid)) {
+		/*
+		 * Fill in NAS-Identifier
+		 */
+		if (rc_avpair_add(sendpairs, PW_NAS_IDENTIFIER, nasid, 0,
+				  VENDOR_NONE) == NULL)
+			return (ERROR_RC);
+
+		return (OK_RC);
+	  
+	} else {
+		/*
+		 * Fill in NAS-IP-Address
+		 */
+		if ((client_id = rc_own_ipaddress()) == 0)
+			return (ERROR_RC);
+
+		if (rc_avpair_add(sendpairs, PW_NAS_IP_ADDRESS, &client_id,
+				  0, VENDOR_NONE) == NULL)
+			return (ERROR_RC);
+	}
+
+	return (OK_RC);
+}
+
+/*
  * Function: rc_buildreq
  *
  * Purpose: builds a skeleton RADIUS request using information from the
- * 	    config file.
+ *	    config file.
  *
  */
 
@@ -58,48 +96,52 @@ unsigned char rc_get_seqnbr(void)
 {
 	FILE *sf;
 	int tries = 1;
-	int seq_nbr;
+	int seq_nbr, pos;
 	char *seqfile = rc_conf_str("seqfile");
-	
+
 	if ((sf = fopen(seqfile, "a+")) == NULL)
 	{
-		rc_log(LOG_ERR,"rc_get_seqnbr: couldn't open sequence file %s: %s", seqfile, strerror(errno)); 
+		rc_log(LOG_ERR,"rc_get_seqnbr: couldn't open sequence file %s: %s", seqfile, strerror(errno));
 		/* well, so guess a sequence number */
-		return rc_guess_seqnbr(); 
-	}	
+		return rc_guess_seqnbr();
+	}
 
 	while (do_lock_exclusive(fileno(sf))!= 0)
 	{
 		if (errno != EWOULDBLOCK) {
 			rc_log(LOG_ERR, "rc_get_seqnbr: flock failure: %s: %s", seqfile, strerror(errno));
-			fclose(sf);	
+			fclose(sf);
 			return rc_guess_seqnbr();
 		}
 		tries++;
-		if (tries <= 10) 
-			rc_mdelay(500); 
-		else 
+		if (tries <= 10)
+			rc_mdelay(500);
+		else
 			break;
 	}
-	
+
 	if (tries > 10) {
 		rc_log(LOG_ERR,"rc_get_seqnbr: couldn't get lock after %d tries: %s", tries-1, seqfile);
- 		fclose(sf);
+		fclose(sf);
 		return rc_guess_seqnbr();
 	}
-	
+
+	pos = ftell(sf);
 	rewind(sf);
 	if (fscanf(sf, "%d", &seq_nbr) != 1) {
-		rc_log(LOG_ERR,"rc_get_seqnbr: fscanf failure: %s", seqfile);
+		if (pos != ftell(sf)) {
+			/* file was not empty */
+			rc_log(LOG_ERR,"rc_get_seqnbr: fscanf failure: %s", seqfile);
+		}
 		seq_nbr = rc_guess_seqnbr();
 	}
-	
+
 	rewind(sf);
 	ftruncate(fileno(sf),0);
 	fprintf(sf,"%d\n", (seq_nbr+1) & UCHAR_MAX);
-	
+
 	fflush(sf); /* fflush because a process may read it between the do_unlock and fclose */
-	
+
 	if (do_unlock(fileno(sf)) != 0)
 		rc_log(LOG_ERR, "rc_get_seqnbr: couldn't release lock on %s: %s", seqfile, strerror(errno));
 
@@ -119,35 +161,57 @@ unsigned char rc_get_seqnbr(void)
  *
  */
 
-int rc_auth(UINT4 client_port, VALUE_PAIR *send, VALUE_PAIR **received, 
-	    char *msg)
+int rc_auth(UINT4 client_port, VALUE_PAIR *send, VALUE_PAIR **received,
+	    char *msg, REQUEST_INFO *info)
+{
+    SERVER *authserver = rc_conf_srv("authserver");
+
+    if (!authserver) {
+	return (ERROR_RC);
+    }
+    return rc_auth_using_server(authserver, client_port, send, received,
+				msg, info);
+}
+
+/*
+ * Function: rc_auth_using_server
+ *
+ * Purpose: Builds an authentication request for port id client_port
+ *	    with the value_pairs send and submits it to a server.  You
+ *          explicitly supply a server list.
+ *
+ * Returns: received value_pairs in received, messages from the server in msg
+ *	    and 0 on success, negative on failure as return value
+ *
+ */
+
+int rc_auth_using_server(SERVER *authserver,
+			 UINT4 client_port,
+			 VALUE_PAIR *send,
+			 VALUE_PAIR **received,
+			 char *msg, REQUEST_INFO *info)
 {
 	SEND_DATA       data;
-	UINT4		client_id;
 	int		result;
 	int		i;
-	SERVER		*authserver = rc_conf_srv("authserver");
 	int		timeout = rc_conf_int("radius_timeout");
-	int		retries = rc_conf_int("radius_retries");	
+	int		retries = rc_conf_int("radius_retries");
 
 	data.send_pairs = send;
 	data.receive_pairs = NULL;
 
 	/*
-	 * Fill in NAS-IP-Address
+	 * Fill in NAS-IP-Address or NAS-Identifier
 	 */
-	 
-	if ((client_id = rc_own_ipaddress()) == 0)
-		return (ERROR_RC);
- 
-	if (rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL)
-		return (ERROR_RC);
+
+	if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
+	    return (ERROR_RC);
 
 	/*
 	 * Fill in NAS-Port
 	 */
-	
-	if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0) == NULL)
+
+	if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
 		return (ERROR_RC);
 
 	result = ERROR_RC;
@@ -158,10 +222,10 @@ int rc_auth(UINT4 client_port, VALUE_PAI
 			rc_avpair_free(data.receive_pairs);
 			data.receive_pairs = NULL;
 		}
-		rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i], 
+		rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
 			    authserver->port[i], timeout, retries);
-			    
-		result = rc_send_server (&data, msg);
+
+		result = rc_send_server (&data, msg, info);
 	}
 
 	*received = data.receive_pairs;
@@ -202,10 +266,10 @@ int rc_auth_proxy(VALUE_PAIR *send, VALU
 			rc_avpair_free(data.receive_pairs);
 			data.receive_pairs = NULL;
 		}
-		rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i], 
+		rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
 			    authserver->port[i], timeout, retries);
-			    
-		result = rc_send_server (&data, msg);
+
+		result = rc_send_server (&data, msg, NULL);
 	}
 
 	*received = data.receive_pairs;
@@ -215,57 +279,54 @@ int rc_auth_proxy(VALUE_PAIR *send, VALU
 
 
 /*
- * Function: rc_acct
+ * Function: rc_acct_using_server
  *
  * Purpose: Builds an accounting request for port id client_port
- *	    with the value_pairs send
+ *	    with the value_pairs send.  You explicitly supply server list.
  *
- * Remarks: NAS-IP-Address, NAS-Port and Acct-Delay-Time get filled
- *	    in by this function, the rest has to be supplied.
+ * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get
+ *	    filled in by this function, the rest has to be supplied.
  */
 
-int rc_acct(UINT4 client_port, VALUE_PAIR *send)
+int rc_acct_using_server(SERVER *acctserver,
+			 UINT4 client_port,
+			 VALUE_PAIR *send)
 {
 	SEND_DATA       data;
 	VALUE_PAIR	*adt_vp;
-	UINT4		client_id;
 	int		result;
 	time_t		start_time, dtime;
 	char		msg[4096];
 	int		i;
-	SERVER		*acctserver = rc_conf_srv("acctserver");
 	int		timeout = rc_conf_int("radius_timeout");
 	int		retries = rc_conf_int("radius_retries");
-	
+
 	data.send_pairs = send;
 	data.receive_pairs = NULL;
 
 	/*
-	 * Fill in NAS-IP-Address
+	 * Fill in NAS-IP-Address or NAS-Identifier
 	 */
-	 
-	if ((client_id = rc_own_ipaddress()) == 0)
-		return (ERROR_RC);
- 
-	if (rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL)
-		return (ERROR_RC);
+
+	if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
+	    return (ERROR_RC);
 
 	/*
 	 * Fill in NAS-Port
 	 */
-			  
-	if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0) == NULL)
+
+	if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
 		return (ERROR_RC);
 
 	/*
 	 * Fill in Acct-Delay-Time
 	 */
-	
+
 	dtime = 0;
-	if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime, 0)) == NULL)
+	if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime, 0, VENDOR_NONE)) == NULL)
 		return (ERROR_RC);
 
-	start_time = time(NULL); 
+	start_time = time(NULL);
 	result = ERROR_RC;
 	for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
 		; i++)
@@ -274,21 +335,39 @@ int rc_acct(UINT4 client_port, VALUE_PAI
 			rc_avpair_free(data.receive_pairs);
 			data.receive_pairs = NULL;
 		}
-		rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i], 
+		rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
 			    acctserver->port[i], timeout, retries);
 
 		dtime = time(NULL) - start_time;
 		rc_avpair_assign(adt_vp, &dtime, 0);
-		
-		result = rc_send_server (&data, msg);
+
+		result = rc_send_server (&data, msg, NULL);
 	}
 
 	rc_avpair_free(data.receive_pairs);
-	
+
 	return result;
 }
 
 /*
+ * Function: rc_acct
+ *
+ * Purpose: Builds an accounting request for port id client_port
+ *	    with the value_pairs send
+ *
+ * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get
+ *	    filled in by this function, the rest has to be supplied.
+ */
+
+int rc_acct(UINT4 client_port, VALUE_PAIR *send)
+{
+    SERVER *acctserver = rc_conf_srv("acctserver");
+    if (!acctserver) return (ERROR_RC);
+
+    return rc_acct_using_server(acctserver, client_port, send);
+}
+
+/*
  * Function: rc_acct_proxy
  *
  * Purpose: Builds an accounting request with the value_pairs send
@@ -316,14 +395,14 @@ int rc_acct_proxy(VALUE_PAIR *send)
 			rc_avpair_free(data.receive_pairs);
 			data.receive_pairs = NULL;
 		}
-		rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i], 
+		rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
 			    acctserver->port[i], timeout, retries);
 
-		result = rc_send_server (&data, msg);
+		result = rc_send_server (&data, msg, NULL);
 	}
 
 	rc_avpair_free(data.receive_pairs);
-	
+
 	return result;
 }
 
@@ -339,32 +418,31 @@ int rc_check(char *host, unsigned short 
 {
 	SEND_DATA       data;
 	int		result;
-	UINT4		client_id, service_type;
+	UINT4		service_type;
 	int		timeout = rc_conf_int("radius_timeout");
 	int		retries = rc_conf_int("radius_retries");
-	
+
 	data.send_pairs = data.receive_pairs = NULL;
 
 	/*
-	 * Fill in NAS-IP-Address, although it isn't neccessary
+	 * Fill in NAS-IP-Address or NAS-Identifier,
+         * although it isn't neccessary
 	 */
-	 
-	if ((client_id = rc_own_ipaddress()) == 0)
-		return (ERROR_RC);
- 
-	rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0); 	
+
+	if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
+	    return (ERROR_RC);
 
 	/*
 	 * Fill in Service-Type
 	 */
-	
+
 	service_type = PW_ADMINISTRATIVE;
-	rc_avpair_add(&(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0); 	
+	rc_avpair_add(&(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, VENDOR_NONE);
 
 	rc_buildreq(&data, PW_STATUS_SERVER, host, port, timeout, retries);
-	result = rc_send_server (&data, msg);
+	result = rc_send_server (&data, msg, NULL);
 
 	rc_avpair_free(data.receive_pairs);
-	
+
 	return result;
 }
diff -urNp radiusclient-0.3.2/lib/config.c radiusclient.ppp/lib/config.c
--- radiusclient-0.3.2/lib/config.c	1998-02-10 15:29:57.000000000 +0200
+++ radiusclient.ppp/lib/config.c	2002-10-01 12:51:01.000000000 +0300
@@ -478,9 +478,8 @@ int rc_find_server (char *server_name, U
 		rc_log(LOG_ERR, "rc_find_server: couldn't open file: %s: %s", strerror(errno), rc_conf_str("servers"));
 		return (-1);
 	}
-	
-	if ((myipaddr = rc_own_ipaddress()) == 0)
-		return (-1);
+
+	myipaddr = rc_own_ipaddress();
 
 	result = 0;
 	while (fgets (buffer, sizeof (buffer), clientfd) != (char *) NULL)
diff -urNp radiusclient-0.3.2/lib/dict.c radiusclient.ppp/lib/dict.c
--- radiusclient-0.3.2/lib/dict.c	1997-12-26 01:28:10.000000000 +0200
+++ radiusclient.ppp/lib/dict.c	2002-03-05 17:14:06.000000000 +0200
@@ -18,15 +20,17 @@
 #include <includes.h>
 #include <radiusclient.h>
 
-static DICT_ATTR *dictionary_attributes;
-static DICT_VALUE *dictionary_values;
+static DICT_ATTR *dictionary_attributes = NULL;
+static DICT_VALUE *dictionary_values = NULL;
+static VENDOR_DICT *vendor_dictionaries = NULL;
 
 /*
  * Function: rc_read_dictionary
  *
  * Purpose: Initialize the dictionary.  Read all ATTRIBUTES into
  *	    the dictionary_attributes list.  Read all VALUES into
- *	    the dictionary_values list.
+ *	    the dictionary_values list.  Construct VENDOR dictionaries
+ *          as required.
  *
  */
 
@@ -38,21 +42,25 @@ int rc_read_dictionary (char *filename)
 	char            valstr[AUTH_ID_LEN];
 	char            attrstr[AUTH_ID_LEN];
 	char            typestr[AUTH_ID_LEN];
+	char            vendorstr[AUTH_ID_LEN];
 	int             line_no;
 	DICT_ATTR      *attr;
 	DICT_VALUE     *dval;
+	VENDOR_DICT    *vdict;
 	char            buffer[256];
 	int             value;
 	int             type;
-
+	int             n;
+	int             retcode;
 	if ((dictfd = fopen (filename, "r")) == (FILE *) NULL)
 	{
-		rc_log(LOG_ERR, "rc_read_dictionary: couldn't open dictionary %s: %s", 
+		rc_log(LOG_ERR, "rc_read_dictionary: couldn't open dictionary %s: %s",
 				filename, strerror(errno));
 		return (-1);
 	}
 
 	line_no = 0;
+	retcode = 0;
 	while (fgets (buffer, sizeof (buffer), dictfd) != (char *) NULL)
 	{
 		line_no++;
@@ -63,16 +71,48 @@ int rc_read_dictionary (char *filename)
 			continue;
 		}
 
-		if (strncmp (buffer, "ATTRIBUTE", 9) == 0)
+		if (strncmp (buffer, "VENDOR", 6) == 0) {
+		    /* Read the VENDOR line */
+		    if (sscanf(buffer, "%s%s%d", dummystr, namestr, &value) != 3) {
+			rc_log(LOG_ERR, "rc_read_dictionary: invalid vendor on line %d of dictionary %s",
+			       line_no, filename);
+			retcode = -1;
+			break;
+		    }
+		    /* Validate entry */
+		    if (strlen (namestr) > NAME_LENGTH) {
+			rc_log(LOG_ERR, "rc_read_dictionary: invalid name length on line %d of dictionary %s",
+			       line_no, filename);
+			retcode = -1;
+			break;
+		    }
+		    /* Create new vendor entry */
+		    vdict = (VENDOR_DICT *) malloc (sizeof (VENDOR_DICT));
+		    if (!vdict) {
+			rc_log(LOG_CRIT, "rc_read_dictionary: out of memory");
+			retcode = -1;
+			break;
+		    }
+		    strcpy(vdict->vendorname, namestr);
+		    vdict->vendorcode = value;
+		    vdict->attributes = NULL;
+		    vdict->next = vendor_dictionaries;
+		    vendor_dictionaries = vdict;
+		}
+		else if (strncmp (buffer, "ATTRIBUTE", 9) == 0)
 		{
 
-			/* Read the ATTRIBUTE line */
-			if (sscanf (buffer, "%s%s%s%s", dummystr, namestr,
-				    valstr, typestr) != 4)
+			/* Read the ATTRIBUTE line.  It is one of:
+			 * ATTRIBUTE attr_name attr_val type         OR
+			 * ATTRIBUTE attr_name attr_val type vendor  */
+			vendorstr[0] = 0;
+			n = sscanf(buffer, "%s%s%s%s%s", dummystr, namestr, valstr, typestr, vendorstr);
+			if (n != 4 && n != 5)
 			{
 				rc_log(LOG_ERR, "rc_read_dictionary: invalid attribute on line %d of dictionary %s",
 					 line_no, filename);
-				return (-1);
+				retcode = -1;
+				break;
 			}
 
 			/*
@@ -82,7 +122,16 @@ int rc_read_dictionary (char *filename)
 			{
 				rc_log(LOG_ERR, "rc_read_dictionary: invalid name length on line %d of dictionary %s",
 					 line_no, filename);
-				return (-1);
+				retcode = -1;
+				break;
+			}
+
+			if (strlen (vendorstr) > NAME_LENGTH)
+			{
+				rc_log(LOG_ERR, "rc_read_dictionary: invalid name length on line %d of dictionary %s",
+					 line_no, filename);
+				retcode = -1;
+				break;
 			}
 
 			if (!isdigit (*valstr))
@@ -90,7 +139,8 @@ int rc_read_dictionary (char *filename)
 				rc_log(LOG_ERR,
 				 "rc_read_dictionary: invalid value on line %d of dictionary %s",
 					 line_no, filename);
-				return (-1);
+				retcode = -1;
+				break;
 			}
 			value = atoi (valstr);
 
@@ -115,24 +165,49 @@ int rc_read_dictionary (char *filename)
 				rc_log(LOG_ERR,
 				  "rc_read_dictionary: invalid type on line %d of dictionary %s",
 					 line_no, filename);
-				return (-1);
+				retcode = -1;
+				break;
 			}
 
+			/* Search for vendor if supplied */
+			if (*vendorstr) {
+			    vdict = rc_dict_findvendor(vendorstr);
+			    if (!vdict) {
+				rc_log(LOG_ERR,
+				       "rc_read_dictionary: unknown vendor on line %d of dictionary %s",
+				       line_no, filename);
+				retcode = -1;
+				break;
+			    }
+			} else {
+			    vdict = NULL;
+			}
 			/* Create a new attribute for the list */
 			if ((attr =
 				(DICT_ATTR *) malloc (sizeof (DICT_ATTR)))
 							== (DICT_ATTR *) NULL)
 			{
 				rc_log(LOG_CRIT, "rc_read_dictionary: out of memory");
-				return (-1);
+				retcode = -1;
+				break;
 			}
 			strcpy (attr->name, namestr);
+			if (vdict) {
+			    attr->vendorcode = vdict->vendorcode;
+			} else {
+			    attr->vendorcode = VENDOR_NONE;
+			}
 			attr->value = value;
 			attr->type = type;
 
 			/* Insert it into the list */
-			attr->next = dictionary_attributes;
-			dictionary_attributes = attr;
+			if (vdict) {
+			    attr->next = vdict->attributes;
+			    vdict->attributes = attr;
+			} else {
+			    attr->next = dictionary_attributes;
+			    dictionary_attributes = attr;
+			}
 		}
 		else if (strncmp (buffer, "VALUE", 5) == 0)
 		{
@@ -143,7 +218,8 @@ int rc_read_dictionary (char *filename)
 				rc_log(LOG_ERR,
 			   "rc_read_dictionary: invalid value entry on line %d of dictionary %s",
 					 line_no, filename);
-				return (-1);
+				retcode = -1;
+				break;
 			}
 
 			/*
@@ -154,7 +230,8 @@ int rc_read_dictionary (char *filename)
 				rc_log(LOG_ERR,
 		      "rc_read_dictionary: invalid attribute length on line %d of dictionary %s",
 					 line_no, filename);
-				return (-1);
+				retcode = -1;
+				break;
 			}
 
 			if (strlen (namestr) > NAME_LENGTH)
@@ -162,7 +239,8 @@ int rc_read_dictionary (char *filename)
 				rc_log(LOG_ERR,
 			   "rc_read_dictionary: invalid name length on line %d of dictionary %s",
 					 line_no, filename);
-				return (-1);
+				retcode = -1;
+				break;
 			}
 
 			if (!isdigit (*valstr))
@@ -170,7 +248,8 @@ int rc_read_dictionary (char *filename)
 				rc_log(LOG_ERR,
 				 "rc_read_dictionary: invalid value on line %d of dictionary %s",
 					 line_no, filename);
-				return (-1);
+				retcode = -1;
+				break;
 			}
 			value = atoi (valstr);
 
@@ -180,7 +259,8 @@ int rc_read_dictionary (char *filename)
 							== (DICT_VALUE *) NULL)
 			{
 				rc_log(LOG_CRIT, "rc_read_dictionary: out of memory");
-				return (-1);
+				retcode = -1;
+				break;
 			}
 			strcpy (dval->attrname, attrstr);
 			strcpy (dval->name, namestr);
@@ -190,34 +270,65 @@ int rc_read_dictionary (char *filename)
 			dval->next = dictionary_values;
 			dictionary_values = dval;
 		}
+		else if (strncmp (buffer, "INCLUDE", 7) == 0)
+		{
+			/* Read the INCLUDE line */
+			if (sscanf (buffer, "%s%s", dummystr, namestr) != 2)
+			{
+				rc_log(LOG_ERR,
+			   "rc_read_dictionary: invalid include entry on line %d of dictionary %s",
+					 line_no, filename);
+				retcode = -1;
+				break;
+			}
+			if (rc_read_dictionary(namestr) == -1)
+			{
+				retcode = -1;
+				break;
+			}
+		}
 	}
 	fclose (dictfd);
-	return (0);
-} 
+	return retcode;
+}
 
 /*
  * Function: rc_dict_getattr
  *
  * Purpose: Return the full attribute structure based on the
- *	    attribute id number.
+ *	    attribute id number and vendor code.  If vendor code is VENDOR_NONE,
+ *          non-vendor-specific attributes are used
  *
  */
- 
-DICT_ATTR *rc_dict_getattr (int attribute)
+
+DICT_ATTR *rc_dict_getattr (int attribute, int vendor)
 {
 	DICT_ATTR      *attr;
+	VENDOR_DICT    *dict;
 
-	attr = dictionary_attributes;
-	while (attr != (DICT_ATTR *) NULL)
-	{
-		if (attr->value == attribute)
-		{
-			return (attr);
+	if (vendor == VENDOR_NONE) {
+	    attr = dictionary_attributes;
+	    while (attr != (DICT_ATTR *) NULL) {
+		if (attr->value == attribute) {
+		    return (attr);
 		}
 		attr = attr->next;
+	    }
+	} else {
+	    dict = rc_dict_getvendor(vendor);
+	    if (!dict) {
+		return NULL;
+	    }
+	    attr = dict->attributes;
+	    while (attr) {
+		if (attr->value == attribute) {
+		    return attr;
+		}
+		attr = attr->next;
+	    }
 	}
-	return ((DICT_ATTR *) NULL);
-} 
+	return NULL;
+}
 
 /*
  * Function: rc_dict_findattr
@@ -230,6 +341,7 @@ DICT_ATTR *rc_dict_getattr (int attribut
 DICT_ATTR *rc_dict_findattr (char *attrname)
 {
 	DICT_ATTR      *attr;
+	VENDOR_DICT    *dict;
 
 	attr = dictionary_attributes;
 	while (attr != (DICT_ATTR *) NULL)
@@ -240,8 +352,21 @@ DICT_ATTR *rc_dict_findattr (char *attrn
 		}
 		attr = attr->next;
 	}
+
+	/* Search vendor-specific dictionaries */
+	dict = vendor_dictionaries;
+	while (dict) {
+	    attr = dict->attributes;
+	    while (attr) {
+		if (strcasecmp (attr->name, attrname) == 0) {
+		    return (attr);
+		}
+		attr = attr->next;
+	    }
+	    dict = dict->next;
+	}
 	return ((DICT_ATTR *) NULL);
-} 
+}
 
 
 /*
@@ -291,4 +416,44 @@ DICT_VALUE * rc_dict_getval (UINT4 value
 		val = val->next;
 	}
 	return ((DICT_VALUE *) NULL);
-} 
+}
+
+/*
+ * Function: rc_dict_findvendor
+ *
+ * Purpose: Return the vendor's dictionary given the vendor name.
+ *
+ */
+VENDOR_DICT * rc_dict_findvendor (char *vendorname)
+{
+    VENDOR_DICT *dict;
+
+    dict = vendor_dictionaries;
+    while (dict) {
+	if (!strcmp(vendorname, dict->vendorname)) {
+	    return dict;
+	}
+	dict = dict->next;
+    }
+    return NULL;
+}
+
+/*
+ * Function: rc_dict_getvendor
+ *
+ * Purpose: Return the vendor's dictionary given the vendor ID
+ *
+ */
+VENDOR_DICT * rc_dict_getvendor (int id)
+{
+    VENDOR_DICT *dict;
+
+    dict = vendor_dictionaries;
+    while (dict) {
+	if (id == dict->vendorcode) {
+	    return dict;
+	}
+	dict = dict->next;
+    }
+    return NULL;
+}
diff -urNp radiusclient-0.3.2/lib/options.h radiusclient.ppp/lib/options.h
--- radiusclient-0.3.2/lib/options.h	1998-06-28 03:08:17.000000000 +0300
+++ radiusclient.ppp/lib/options.h	2002-10-01 12:51:01.000000000 +0300
@@ -31,26 +31,30 @@ typedef struct _option {
 static SERVER acctserver = {0};
 static SERVER authserver = {0};
 
+int default_tries = 4;
+int default_timeout = 60;
+
 static OPTION config_options[] = {
 /* internally used options */
 {"config_file",		OT_STR, ST_UNDEF, NULL},
 /* General options */
 {"auth_order",	 	OT_AUO, ST_UNDEF, NULL},
-{"login_tries",	 	OT_INT, ST_UNDEF, NULL},
-{"login_timeout",	OT_INT, ST_UNDEF, NULL},
-{"nologin",		OT_STR, ST_UNDEF, NULL},
-{"issue",		OT_STR, ST_UNDEF, NULL},
+{"login_tries",	 	OT_INT, ST_UNDEF, &default_tries},
+{"login_timeout",	OT_INT, ST_UNDEF, &default_timeout},
+{"nologin",		OT_STR, ST_UNDEF, "/etc/nologin"},
+{"issue",		OT_STR, ST_UNDEF, "/etc/radiusclient/issue"},
 /* RADIUS specific options */
 {"authserver",		OT_SRV, ST_UNDEF, &authserver},
 {"acctserver",		OT_SRV, ST_UNDEF, &acctserver},
 {"servers",		OT_STR, ST_UNDEF, NULL},
 {"dictionary",		OT_STR, ST_UNDEF, NULL},
-{"login_radius",	OT_STR, ST_UNDEF, NULL},
+{"login_radius",	OT_STR, ST_UNDEF, "/usr/sbin/login.radius"},
 {"seqfile",		OT_STR, ST_UNDEF, NULL},
 {"mapfile",		OT_STR, ST_UNDEF, NULL},
 {"default_realm",	OT_STR, ST_UNDEF, NULL},
 {"radius_timeout",	OT_INT, ST_UNDEF, NULL},
 {"radius_retries",	OT_INT,	ST_UNDEF, NULL},
+{"nas_identifier",      OT_STR, ST_UNDEF, ""},
 /* local options */
 {"login_local",		OT_STR, ST_UNDEF, NULL},
 };
diff -urNp radiusclient-0.3.2/lib/sendserver.c radiusclient.ppp/lib/sendserver.c
--- radiusclient-0.3.2/lib/sendserver.c	2002-02-03 15:51:41.000000000 +0200
+++ radiusclient.ppp/lib/sendserver.c	2002-04-02 17:09:35.000000000 +0300
@@ -33,96 +33,128 @@ static int rc_check_reply (AUTH_HDR *, i
 
 static int rc_pack_list (VALUE_PAIR *vp, char *secret, AUTH_HDR *auth)
 {
-	int             length, i, pc, secretlen, padded_length;
-	int             total_length = 0;
-	UINT4           lvalue;
-	unsigned char   passbuf[MAX(AUTH_PASS_LEN, CHAP_VALUE_LENGTH)];
-	unsigned char   md5buf[256];
-	unsigned char   *buf, *vector;
-	
-	buf = auth->data;
+    int             length, i, pc, secretlen, padded_length;
+    int             total_length = 0;
+    UINT4           lvalue;
+    unsigned char   passbuf[MAX(AUTH_PASS_LEN, CHAP_VALUE_LENGTH)];
+    unsigned char   md5buf[256];
+    unsigned char   *buf, *vector, *lenptr;
 
-	while (vp != (VALUE_PAIR *) NULL)
+    buf = auth->data;
+
+    while (vp != (VALUE_PAIR *) NULL)
 	{
+
+	    if (vp->vendorcode != VENDOR_NONE) {
+		*buf++ = PW_VENDOR_SPECIFIC;
+
+		/* Place-holder for where to put length */
+		lenptr = buf++;
+
+		/* Insert vendor code */
+		*buf++ = 0;
+		*buf++ = (((unsigned int) vp->vendorcode) >> 16) & 255;
+		*buf++ = (((unsigned int) vp->vendorcode) >> 8) & 255;
+		*buf++ = ((unsigned int) vp->vendorcode) & 255;
+
+		/* Insert vendor-type */
 		*buf++ = vp->attribute;
 
-		switch (vp->attribute)
-		{
-		 case PW_USER_PASSWORD:
+		/* Insert value */
+		switch(vp->type) {
+		case PW_TYPE_STRING:
+		    length = vp->lvalue;
+		    *lenptr = length + 8;
+		    *buf++ = length+2;
+		    memcpy(buf, vp->strvalue, (size_t) length);
+		    buf += length;
+		    total_length += length+8;
+		    break;
+		case PW_TYPE_INTEGER:
+		case PW_TYPE_IPADDR:
+		    length = sizeof(UINT4);
+		    *lenptr = length + 8;
+		    *buf++ = length+2;
+		    lvalue = htonl(vp->lvalue);
+		    memcpy(buf, (char *) &lvalue, sizeof(UINT4));
+		    buf += length;
+		    total_length += length+8;
+		    break;
+		default:
+		    break;
+		}
+	    } else {
+		*buf++ = vp->attribute;
+		switch (vp->attribute) {
+		case PW_USER_PASSWORD:
+
+		    /* Encrypt the password */
+
+		    /* Chop off password at AUTH_PASS_LEN */
+		    length = vp->lvalue;
+		    if (length > AUTH_PASS_LEN) length = AUTH_PASS_LEN;
+
+		    /* Calculate the padded length */
+		    padded_length = (length+(AUTH_VECTOR_LEN-1)) & ~(AUTH_VECTOR_LEN-1);
+
+		    /* Record the attribute length */
+		    *buf++ = padded_length + 2;
+
+		    /* Pad the password with zeros */
+		    memset ((char *) passbuf, '\0', AUTH_PASS_LEN);
+		    memcpy ((char *) passbuf, vp->strvalue, (size_t) length);
+
+		    secretlen = strlen (secret);
+		    vector = (char *)auth->vector;
+		    for(i = 0; i < padded_length; i += AUTH_VECTOR_LEN) {
+			/* Calculate the MD5 digest*/
+			strcpy ((char *) md5buf, secret);
+			memcpy ((char *) md5buf + secretlen, vector,
+				AUTH_VECTOR_LEN);
+			rc_md5_calc (buf, md5buf, secretlen + AUTH_VECTOR_LEN);
+
+			/* Remeber the start of the digest */
+			vector = buf;
 
-		  /* Encrypt the password */
-	
-		  /* Chop off password at AUTH_PASS_LEN */
-		  length = vp->lvalue;
-		  if (length > AUTH_PASS_LEN)
-			length = AUTH_PASS_LEN;
-
-		  /* Calculate the padded length */
-		  padded_length = (length+(AUTH_VECTOR_LEN-1)) & ~(AUTH_VECTOR_LEN-1);
-
-		  /* Record the attribute length */		
-		  *buf++ = padded_length + 2;
-		  
-		  /* Pad the password with zeros */
-		  memset ((char *) passbuf, '\0', AUTH_PASS_LEN);
-		  memcpy ((char *) passbuf, vp->strvalue, (size_t) length);
-
-		  secretlen = strlen (secret);
-		  vector = (char *)auth->vector;
-		  for(i = 0; i < padded_length; i += AUTH_VECTOR_LEN)
-		  {
-		  	/* Calculate the MD5 digest*/
-		  	strcpy ((char *) md5buf, secret);
-		  	memcpy ((char *) md5buf + secretlen, vector,
-		  		  AUTH_VECTOR_LEN);
-		  	rc_md5_calc (buf, md5buf, secretlen + AUTH_VECTOR_LEN);
-		  
-		        /* Remeber the start of the digest */
-		  	vector = buf;
-		  	
 			/* Xor the password into the MD5 digest */
-			for (pc = i; pc < (i + AUTH_VECTOR_LEN); pc++)
-		  	{
-				*buf++ ^= passbuf[pc];
-		  	}
-		  }
-
-		  total_length += padded_length + 2;
-		  
-		  break;
-#if 0		
-		 case PW_CHAP_PASSWORD:
-
-		  *buf++ = CHAP_VALUE_LENGTH + 2;
-
-		  /* Encrypt the Password */
-		  length = vp->lvalue;
-		  if (length > CHAP_VALUE_LENGTH)
-		  {
+			for (pc = i; pc < (i + AUTH_VECTOR_LEN); pc++) {
+			    *buf++ ^= passbuf[pc];
+			}
+		    }
+
+		    total_length += padded_length + 2;
+
+		    break;
+#if 0
+		case PW_CHAP_PASSWORD:
+
+		    *buf++ = CHAP_VALUE_LENGTH + 2;
+
+		    /* Encrypt the Password */
+		    length = vp->lvalue;
+		    if (length > CHAP_VALUE_LENGTH) {
 			length = CHAP_VALUE_LENGTH;
-		  }
-		  memset ((char *) passbuf, '\0', CHAP_VALUE_LENGTH);
-		  memcpy ((char *) passbuf, vp->strvalue, (size_t) length);
-
-		  /* Calculate the MD5 Digest */
-		  secretlen = strlen (secret);
-		  strcpy ((char *) md5buf, secret);
-		  memcpy ((char *) md5buf + secretlen, (char *) auth->vector,
-		  	  AUTH_VECTOR_LEN);
-		  rc_md5_calc (buf, md5buf, secretlen + AUTH_VECTOR_LEN);
-
-		  /* Xor the password into the MD5 digest */
-		  for (i = 0; i < CHAP_VALUE_LENGTH; i++)
-		  {
+		    }
+		    memset ((char *) passbuf, '\0', CHAP_VALUE_LENGTH);
+		    memcpy ((char *) passbuf, vp->strvalue, (size_t) length);
+
+		    /* Calculate the MD5 Digest */
+		    secretlen = strlen (secret);
+		    strcpy ((char *) md5buf, secret);
+		    memcpy ((char *) md5buf + secretlen, (char *) auth->vector,
+			    AUTH_VECTOR_LEN);
+		    rc_md5_calc (buf, md5buf, secretlen + AUTH_VECTOR_LEN);
+
+		    /* Xor the password into the MD5 digest */
+		    for (i = 0; i < CHAP_VALUE_LENGTH; i++) {
 			*buf++ ^= passbuf[i];
-		  }
-		  total_length += CHAP_VALUE_LENGTH + 2;
-		 
-		  break;
+		    }
+		    total_length += CHAP_VALUE_LENGTH + 2;
+
+		    break;
 #endif
-		 default:
-		  switch (vp->type)
-		  {
+		default:
+		    switch (vp->type) {
 		    case PW_TYPE_STRING:
 			length = vp->lvalue;
 			*buf++ = length + 2;
@@ -142,12 +174,13 @@ static int rc_pack_list (VALUE_PAIR *vp,
 
 		    default:
 			break;
-		  }
-		  break;
+		    }
+		    break;
 		}
-		vp = vp->next;
+	    }
+	    vp = vp->next;
 	}
-	return total_length;
+    return total_length;
 }
 
 /*
@@ -157,7 +190,7 @@ static int rc_pack_list (VALUE_PAIR *vp,
  *
  */
 
-int rc_send_server (SEND_DATA *data, char *msg)
+int rc_send_server (SEND_DATA *data, char *msg, REQUEST_INFO *info)
 {
 	int             sockfd;
 	struct sockaddr salocal;
@@ -246,7 +279,7 @@ int rc_send_server (SEND_DATA *data, cha
 	else
 	{
 		rc_random_vector (vector);
-		memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);
+		memcpy (auth->vector, vector, AUTH_VECTOR_LEN);
 
 		total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN;
 
@@ -307,18 +340,24 @@ int rc_send_server (SEND_DATA *data, cha
 		memset (secret, '\0', sizeof (secret));
 		return (ERROR_RC);
 	}
-	
+
 	recv_auth = (AUTH_HDR *)recv_buffer;
-	
+
 	result = rc_check_reply (recv_auth, BUFFER_LEN, secret, vector, data->seq_nbr);
 
 	data->receive_pairs = rc_avpair_gen(recv_auth);
 
 	close (sockfd);
+	if (info)
+	{
+		memcpy(info->secret, secret, sizeof(info->secret));
+		memcpy(info->request_vector, vector,
+		       sizeof(info->request_vector));
+	}
 	memset (secret, '\0', sizeof (secret));
 
 	if (result != OK_RC) return (result);
-	
+
 	*msg = '\0';
 	vp = data->receive_pairs;
 	while (vp)
@@ -355,8 +394,8 @@ int rc_send_server (SEND_DATA *data, cha
  *
  */
 
-static int rc_check_reply (AUTH_HDR *auth, int bufferlen, char *secret, unsigned char *vector,\
-			   unsigned char seq_nbr)
+static int rc_check_reply (AUTH_HDR *auth, int bufferlen, char *secret,
+			   unsigned char *vector, unsigned char seq_nbr)
 {
 	int             secretlen;
 	int             totallen;
diff -urNp radiusclient-0.3.2/src/radexample.c radiusclient.ppp/src/radexample.c
--- radiusclient-0.3.2/src/radexample.c	1999-02-09 16:59:14.000000000 +0200
+++ radiusclient.ppp/src/radexample.c	2002-04-02 17:09:35.000000000 +0300
@@ -26,23 +26,32 @@ main (int argc, char **argv)
 	int             result;
 	char		username[128];
 	char            passwd[AUTH_PASS_LEN + 1];
-	VALUE_PAIR 	*send, *received;
+	VALUE_PAIR	*send, *received;
 	UINT4		service;
-	char 		msg[4096], username_realm[256];
+	char		msg[4096], username_realm[256];
 	char		*default_realm = rc_conf_str("default_realm");
+	char name[2048];
+	char value[2048]; /* more than enough */
+	char *cfile;
 
 	pname = (pname = strrchr(argv[0],'/'))?pname+1:argv[0];
 
 	rc_openlog(pname);
 
-	if (rc_read_config(RC_CONFIG_FILE) != 0)
+
+	if (argc >= 2) {
+	    cfile = argv[1];
+	} else {
+	    cfile = RC_CONFIG_FILE;
+	}
+	if (rc_read_config(cfile) != 0)
 		return(ERROR_RC);
-	
+
 	if (rc_read_dictionary(rc_conf_str("dictionary")) != 0)
 		return(ERROR_RC);
 
 	strncpy(username, rc_getstr ("login: ",1), sizeof(username));
-	strncpy (passwd, rc_getstr("Password: ",0), sizeof (passwd));		
+	strncpy (passwd, rc_getstr("Password: ",0), sizeof (passwd));
 
 	send = NULL;
 
@@ -58,28 +67,28 @@ main (int argc, char **argv)
 	{
 		strncat(username_realm, "@", sizeof(username_realm));
 		strncat(username_realm, default_realm, sizeof(username_realm));
-	} 
+	}
 
-	if (rc_avpair_add(&send, PW_USER_NAME, username_realm, 0) == NULL)
+	if (rc_avpair_add(&send, PW_USER_NAME, username_realm, 0, VENDOR_NONE) == NULL)
 		return(ERROR_RC);
-	
+
 	/*
 	 * Fill in User-Password
 	 */
-	 
-	if (rc_avpair_add(&send, PW_USER_PASSWORD, passwd, 0) == NULL)
+
+	if (rc_avpair_add(&send, PW_USER_PASSWORD, passwd, 0, VENDOR_NONE) == NULL)
 		return (ERROR_RC);
 
 	/*
 	 * Fill in Service-Type
 	 */
-	
+
 	service = PW_AUTHENTICATE_ONLY;
-	if (rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0) == NULL)
-		return (ERROR_RC);	
-	
-	result = rc_auth(0, send, &received, msg);
-	
+	if (rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0, VENDOR_NONE) == NULL)
+		return (ERROR_RC);
+
+	result = rc_auth(0, send, &received, msg, NULL);
+
 	if (result == OK_RC)
 	{
 		fprintf(stderr, "\"%s\" RADIUS Authentication OK\n", username);
@@ -88,6 +97,16 @@ main (int argc, char **argv)
 	{
 		fprintf(stderr, "\"%s\" RADIUS Authentication failure (RC=%i)\n", username, result);
 	}
-	
+
+	/* Print returned attributes */
+	for( ; received ; received = received->next) {
+	    if (rc_avpair_tostr(received, name, sizeof(name), value,
+				sizeof(value)) < 0) {
+		continue;
+	    }
+	    printf("Attr '%s' ==> Val '%s'\n",
+		   name, value);
+	}
+
 	return result;
 }
diff -urNp radiusclient-0.3.2/src/radexample-debug radiusclient.ppp/src/radexample-debug
--- radiusclient-0.3.2/src/radexample-debug	1970-01-01 03:00:00.000000000 +0300
+++ radiusclient.ppp/src/radexample-debug	2002-01-22 18:03:04.000000000 +0200
@@ -0,0 +1,61 @@
+#! /bin/sh
+
+# radexample - temporary wrapper script for .libs/radexample
+# Generated by ltmain.sh - GNU libtool 1.0
+#
+# The radexample program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of `/home/dfs/Servpoet/radiusclient-0.3.1/src'.
+# If it is, it will not operate correctly.
+
+# This environment variable determines our operation mode.
+if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
+  # install mode needs the following variables:
+  link_against_libtool_libs=' ../lib/libradiusclient.la'
+  finalize_command='gcc -g -O2 -o .libs/radexampleT radexample.o -Wl,-rpath -Wl,/usr/lib -L/usr/lib -lradiusclient -lcrypt -lnsl'
+else
+  # Find the directory that this script lives in.
+  thisdir=`echo $0 | sed 's%/[^/]*$%%'`
+  test "x$thisdir" = "x$0" && thisdir=.
+
+  # Try to get the absolute directory name.
+  absdir=`cd "$thisdir" && pwd`
+  test -n "$absdir" && thisdir="$absdir"
+
+  progdir="$thisdir/.libs"
+  program="radexample"
+
+  if test -f "$progdir/$program"; then
+    # Run the actual program with our arguments.
+    args=
+    for arg
+    do
+      # Quote arguments (to preserve shell metacharacters).
+      args="$args '$arg'"
+    done
+
+    # Export the path to the program.
+    PATH="$progdir:$PATH"
+    export PATH
+
+    # Add our own library path to LD_LIBRARY_PATH
+    LD_LIBRARY_PATH="$thisdir/../lib/.libs:$LD_LIBRARY_PATH"
+
+    # Some systems cannot cope with colon-terminated LD_LIBRARY_PATH
+    LD_LIBRARY_PATH=`echo $LD_LIBRARY_PATH | sed -e 's/:*$//'`
+
+    export LD_LIBRARY_PATH
+
+    eval "exec ddd ./.libs/$program $args"
+
+    echo "$0: cannot exec $program $args"
+    exit 1
+  else
+    # The program doesn't exist.
+    echo "$0: error: $progdir/$program does not exist" 1>&2
+    echo "This script is just a wrapper for $program." 1>&2
+    echo "See the libtool documentation for more information." 1>&2
+    exit 1
+  fi
+fi
diff -urNp radiusclient-0.3.2/src/radius.c radiusclient.ppp/src/radius.c
--- radiusclient-0.3.2/src/radius.c	1997-12-26 01:28:55.000000000 +0200
+++ radiusclient.ppp/src/radius.c	2002-04-02 17:09:35.000000000 +0300
@@ -67,30 +67,30 @@ LFUNC auth_radius(UINT4 client_port, cha
 				break;
 	}
 #else
-	service = PW_LOGIN;	
+	service = PW_LOGIN;
 	ftype = 0;
 	ctype = 0;
 #endif
 
-	if (rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0) == NULL)
+	if (rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0, VENDOR_NONE) == NULL)
 		return (LFUNC) NULL;
 
 	/* Fill in Framed-Protocol, if neccessary */
-	
+
 	if (ftype != 0)
 	{
-		if (rc_avpair_add(&send, PW_FRAMED_PROTOCOL, &ftype, 0) == NULL)
-			return (LFUNC) NULL;	
-	} 
+		if (rc_avpair_add(&send, PW_FRAMED_PROTOCOL, &ftype, 0, VENDOR_NONE) == NULL)
+			return (LFUNC) NULL;
+	}
 
 	/* Fill in Framed-Compression, if neccessary */
 
 	if (ctype != 0)
 	{
-		if (rc_avpair_add(&send, PW_FRAMED_COMPRESSION, &ctype, 0) == NULL)
+		if (rc_avpair_add(&send, PW_FRAMED_COMPRESSION, &ctype, 0, VENDOR_NONE) == NULL)
 			return (LFUNC) NULL;
-	} 
-	 
+	}
+
 	/*
 	 * Fill in User-Name
 	 */
@@ -105,50 +105,50 @@ LFUNC auth_radius(UINT4 client_port, cha
 	 {
 		strncat(username_realm, "@", sizeof(username_realm));
 		strncat(username_realm, default_realm, sizeof(username_realm));
-	 } 
+	 }
 
-	if (rc_avpair_add(&send, PW_USER_NAME, username_realm, 0) == NULL)
+	if (rc_avpair_add(&send, PW_USER_NAME, username_realm, 0, VENDOR_NONE) == NULL)
 		return (LFUNC) NULL;
-	
+
 	/*
 	 * Fill in User-Password
 	 */
-	 
-	if (rc_avpair_add(&send, PW_USER_PASSWORD, passwd, 0) == NULL) 	  
+
+	if (rc_avpair_add(&send, PW_USER_PASSWORD, passwd, 0, VENDOR_NONE) == NULL)
 		return (LFUNC) NULL;
-	
-	result = rc_auth(client_port, send, &received, msg);
+
+	result = rc_auth(client_port, send, &received, msg, NULL);
 
 	if (result == OK_RC)
 	{
 		/* Set up a running count of attributes saved. */
 		int acount[256], attr;
-		
+
 		memset(acount, 0, sizeof(acount));
 
 		rc_add_env(env, "RADIUS_USER_NAME", username);
-		
+
 		vp = received;
 
 		/* map-- keep track of the attributes so that we know
 		   when to add the delimiters. Note that we can only
 		   handle attributes < 256, which is the standard anyway. */
-		
+
 		while (vp)
 		{
 			strcpy(name, "RADIUS_");
 			if (rc_avpair_tostr(vp, name+7, sizeof(name)-7, value, sizeof(value)) < 0) {
 				rc_avpair_free(send);
 				rc_avpair_free(received);
-				return (LFUNC) NULL;			
+				return (LFUNC) NULL;
 			}
-			
+
 			/* Translate "-" => "_" and uppercase*/
 			for(p = name; *p; p++) {
 				*p = toupper(*p);
 				if (*p == '-') *p = '_';
 			}
-		
+
 			/* Add to the attribute count and append the var
 			   if necessary. */
 			if ((attr = vp->attribute) < 256)
diff -urNp radiusclient-0.3.2/src/radstatus.c radiusclient.ppp/src/radstatus.c
--- radiusclient-0.3.2/src/radstatus.c	1999-01-07 01:50:54.000000000 +0200
+++ radiusclient.ppp/src/radstatus.c	2002-01-22 18:03:05.000000000 +0200
@@ -110,4 +110,5 @@ void main (int argc, char **argv)
 			fputs(msg, stdout);
 		}
 	}
+	return 0;
 }
