diff -c -N radiusd//Makefile ascendd//Makefile
*** radiusd//Makefile	Tue Dec 27 09:32:28 1994
--- ascendd//Makefile	Wed Dec 20 13:14:02 1995
***************
*** 2,39 ****
  #	Makefile for RADIUS - 
  #		Remote Authentication Dial In User Service
  #
  #
- # Add -DNOSHADOW to CFLAGS if you don't have Shadow Passwords
  #
! # aix:	add -Daix to CFLAGS
! # SCO:	add LIBS= -lsocket
! # Solaris:
! #	CFLAGS= -O -Dsys5
! #	CC=	gcc -traditional
! #	LIBS= -lnsl -lsocket
! # unixware: add -Dunixware to CFLAGS, use LIBS= -lucb -lnsl -lsocket
  #
  SRCDIR=.
! CFLAGS= -O -DNOSHADOW
! LDFLAGS=
! CC=	cc
! LIBS=
! SERVER_OBJS=radiusd.o dict.o users.o util.o md5.o attrprint.o acct.o version.o
! SERVERDBM_OBJS=radiusd.o dict.o usersdbm.o util.o md5.o attrprint.o acct.o versiondbm.o
! SERVER_SRCS=radiusd.c dict.c users.c util.c md5.c attrprint.c acct.c version.c
! INCLUDES=$(SRCDIR)/radius.h $(SRCDIR)/conf.h
  
! ALL:	radiusd radpass
  
  dbm:	radiusd.dbm builddbm
  
  radiusd: $(SERVER_OBJS)
  	$(CC) $(CFLAGS) -o radiusd $(SERVER_OBJS) $(LIBS)
  
  radiusd.dbm: $(SERVERDBM_OBJS)
! 	$(CC) $(CFLAGS) -o radiusd.dbm $(SERVERDBM_OBJS) -ldbm $(LIBS)
  
! radiusd.o: $(SRCDIR)/radiusd.c $(INCLUDES)
  	$(CC) $(CFLAGS) -c $(SRCDIR)/radiusd.c
  
  acct.o: $(SRCDIR)/acct.c $(INCLUDES)
--- 2,165 ----
  #	Makefile for RADIUS - 
  #		Remote Authentication Dial In User Service
  #
+ # ASCEND: @(#)Makefile	1.3 (95/07/25 00:55:22)
  #
  #
! # Add -DNOSHADOW to CFLAGS if you don't have Shadow Passwords.  As is,
! # the Makefile compiles a RADIUS daemon with Ascend extensions on a SunOs
! # box using GCC.
  #
+ #
+ #Host OS:
+ # aix:
+ #	add -Daix to CFLAGS
+ #
+ # HP-UX:
+ #	CFLAGS=
+ #	CC= gcc -traditional
+ #
+ # SCO:
+ #	add LIBS= -lsocket
+ #
+ # SunOs:
+ #	CFLAGS= -DOSUN
+ #	CC= gcc -traditional
+ #
+ # Solaris with gcc:
+ #	CFLAGS= -O -Dsys5 -DSOLARIS
+ #	CC= gcc -ansi
+ #	add LIBS= -lnsl -lsocket
+ #
+ # Solaris with cc:
+ #	CFLAGS= -O -Dsys5 -DSOLARIS
+ #	CC= cc
+ #	add LIBS= -lnsl -lsocket
+ #
+ # unixware:
+ #	add -Dunixware to CFLAGS
+ #	add LIBS= -lucb -lnsl -lsocket
+ #
+ # BSDI:
+ #	CC= gcc		# Note: cannot use -ansi on some versions
+ #
+ # Linux:
+ #	add -Dsys5 to CFLAGS
+ #
+ #
+ #External Authentication Servers:
+ # Security Dynamics (ACE):
+ #	add -DACE to AUTH_SERVERS
+ #	add SD_INCLUDES to AUTH_INCLUDES
+ #	add -lsdiclient to AUTH_LIBS
+ # Enigma Logic (SAFEWORD):
+ #	add -DSAFEWORD to AUTH_SERVERS
+ #	add SW_INCLUDES to AUTH_INCLUDES
+ #	add -lidp to AUTH_LIBS
+ #
+ 
  SRCDIR=.
! 
! # Pick the combination of external authentication servers to use.  Requires
! # the authentication source and libraries provided by the server vendors.
! #
! AUTH_SERVERS=
! #AUTH_SERVERS= -DACE
! #AUTH_SERVERS= -DSAFEWORD
! #AUTH_SERVERS= -DACE -DSAFEWORD
! 
! # List of extra files for external authentication servers
! #  SD_INCLUDES          Source files provided by Security Dynamics (ACE)
! #  SW_INCLUDES          Source files provided by Enigma Logic (SafeWord)
! #
! SD_INCLUDES= $(SRCDIR)/sdi_athd.h $(SRCDIR)/sdi_size.h $(SRCDIR)/sdi_type.h \
! 		$(SRCDIR)/sdacmvls.h $(SRCDIR)/sdconf.h
! SW_INCLUDES= $(SRCDIR)/custpb.h $(SRCDIR)/custfail.h
! 
! # Specify the authentication server include list to use
! #
! AUTH_INCLUDES=
! #AUTH_INCLUDES= $(SD_INCLUDES)
! #AUTH_INCLUDES= $(SW_INCLUDES)
! #AUTH_INCLUDES= $(SW_INCLUDES) $(SD_INCLUDES)
! 
! # List of external authentication libraries
! #  -lidpb               For Enigma Logic (SafeWord)
! #  -lsdiclient          For Security Dynamics (ACE)
! #
! AUTH_LIBS=
! #AUTH_LIBS= -L. -lsdiclient
! #AUTH_LIBS= -L. -lidpb
! #AUTH_LIBS= -L. -lsdiclient -lidpb
! 
! # Pick your compiler
! #
! #CC=	gcc -ansi -Wall	# set the GCC compiler to ANSI mode and picky
! CC=	gcc -ansi	# set the GCC compiler to ANSI mode
! #CC=	gcc		# set the GCC compiler for BSDI and friends
! #CC=	cc -Xc -v -fd	# set the SUN compiler to full-whine ANSI mode
! #CC=	cc -Xc -v	# set the SUN compiler to partial-whine ANSI mode
! #CC=	cc -Xc		# set the SUN compiler to ANSI mode
! #CC=	cc
! 
! # Pick your compiler flags
! #  -Dsys5               System V
! #  -DSOLARIS            Solaris (use sys5 also)
! #  -DBINARY_FILTERS     Ascend specific feature to store filters in RADIUS
! #  -DASCEND_SECRET	Ascend specific feature to send secrets from RADIUS
! #  -DASCEND_LOGOUT      Ascend specific feature to handle logout notification
! #  -DOSUN               SunOS 4.1.x
! #  -DNOSHADOW           No shadow password file support
! #  $(AUTH_SERVERS)      See above
! #
! 
! #	use this for BSDI
! #CFLAGS= -O -DNOSHADOW -DBSDI -DBINARY_FILTERS -DASCEND_SECRET -DASCEND_LOGOUT $(AUTH_SERVERS)
! #	use this for SunOS
! CFLAGS= -O -DNOSHADOW -DOSUN -DBINARY_FILTERS -DASCEND_SECRET -DASCEND_LOGOUT $(AUTH_SERVERS)
! #	use this for Solaris 2.x
! #CFLAGS= -O -Dsys5 -DSOLARIS -DBINARY_FILTERS -DASCEND_SECRET -DASCEND_LOGOUT $(AUTH_SERVERS)
! #	use this for Linux
! #CFLAGS= -O -Dsys5 -DNOSHADOW -DBINARY_FILTERS -DASCEND_SECRET -DASCEND_LOGOUT $(AUTH_SERVERS)
! 
! # Pick any load options and the load libraries.  The AUTH_LIBS
! # are selected above
! #
! LDFLAGS= 
! 
! # See above for the things you may need to add here
! #
! #LIBS= $(AUTH_LIBS)			# use this for Linux, BSDI and friends
! LIBS= -lnsl $(AUTH_LIBS)		# use this for SunOS
! #LIBS= -lnsl -lsocket $(AUTH_LIBS)	# use this for Solaris 2.x
! 
! #       use this for SunOs. Linux, BSDI
! DBMLIBS= -ldbm
! #       use this for Solaris
! #DBMLIBS=
! 
! CMN_OBJS=radiusd.o dict.o util.o md5.o attrprint.o acct.o filters.o usr_read.o cache.o
! SERVER_OBJS=$(CMN_OBJS) users.o version.o
! SERVERDBM_OBJS=$(CMN_OBJS) usersdbm.o versiondbm.o
! 
! SERVER_SRCS=$(SERVER_OBJS:%.o:%.c)
! SRVR_SOURCES=$(SERVER_OBJS:.o=.c)
! SOURCES=$(SRVR_SOURCES) $(SRCDIR)/radpass.c $(SRCDIR)/md5.c $(SRCDIR)/util.c
! 
! INCLUDES=$(SRCDIR)/radius.h $(SRCDIR)/conf.h $(SRCDIR)/protos.h $(SRCDIR)/cache.h
! ALL_INCLUDES=$(INCLUDES) $(SRCDIR)/md5.h
  
! all:	radiusd
  
  dbm:	radiusd.dbm builddbm
  
  radiusd: $(SERVER_OBJS)
  	$(CC) $(CFLAGS) -o radiusd $(SERVER_OBJS) $(LIBS)
+ #	chmod 4111 radiusd
  
  radiusd.dbm: $(SERVERDBM_OBJS)
! 	$(CC) $(CFLAGS) -o radiusd.dbm $(SERVERDBM_OBJS) $(DBMLIBS) $(LIBS)
  
! radiusd.o: $(SRCDIR)/radiusd.c $(INCLUDES) $(AUTH_INCLUDES)
  	$(CC) $(CFLAGS) -c $(SRCDIR)/radiusd.c
  
  acct.o: $(SRCDIR)/acct.c $(INCLUDES)
***************
*** 49,55 ****
  	$(CC) $(CFLAGS) -c $(SRCDIR)/users.c
  
  usersdbm.o: $(SRCDIR)/users.c $(INCLUDES)
! 	$(CC) $(CFLAGS) -DDBM -o usersdbm.o -c $(SRCDIR)/users.c
  
  util.o: $(SRCDIR)/util.c $(INCLUDES)
  	$(CC) $(CFLAGS) -c $(SRCDIR)/util.c
--- 175,181 ----
  	$(CC) $(CFLAGS) -c $(SRCDIR)/users.c
  
  usersdbm.o: $(SRCDIR)/users.c $(INCLUDES)
! 	$(CC) $(CFLAGS) -DDBM_MODE -o usersdbm.o -c $(SRCDIR)/users.c
  
  util.o: $(SRCDIR)/util.c $(INCLUDES)
  	$(CC) $(CFLAGS) -c $(SRCDIR)/util.c
***************
*** 58,64 ****
  	$(CC) $(CFLAGS) -o version.o -c $(SRCDIR)/version.c
  
  versiondbm.o: $(SRCDIR)/version.c $(INCLUDES)
! 	$(CC) $(CFLAGS) -DDBM -o versiondbm.o -c $(SRCDIR)/version.c
  
  radpass: radpass.o md5.o util.o
  	$(CC) $(CFLAGS) -o radpass radpass.o md5.o util.o $(LIBS)
--- 184,190 ----
  	$(CC) $(CFLAGS) -o version.o -c $(SRCDIR)/version.c
  
  versiondbm.o: $(SRCDIR)/version.c $(INCLUDES)
! 	$(CC) $(CFLAGS) -DDBM_MODE -o versiondbm.o -c $(SRCDIR)/version.c
  
  radpass: radpass.o md5.o util.o
  	$(CC) $(CFLAGS) -o radpass radpass.o md5.o util.o $(LIBS)
***************
*** 69,83 ****
  md5.o: $(SRCDIR)/md5.c $(SRCDIR)/md5.h
  	$(CC) $(CFLAGS) -c $(SRCDIR)/md5.c
  
! builddbm: builddbm.o
! 	$(CC) $(CFLAGS) -o builddbm builddbm.o -ldbm $(LIBS)
  
  builddbm.o: $(SRCDIR)/builddbm.c
  	$(CC) $(CFLAGS) -c $(SRCDIR)/builddbm.c
  
  lint:
! 	-lint -hbacvx -DLINT $(SERVER_SRCS)
! 	-lint -hbacvx -DLINT ../radpass.c ../md5.c ../util.c
  
  clean:
! 	rm -f *.o radiusd radpass builddbm radiusd.dbm
--- 195,225 ----
  md5.o: $(SRCDIR)/md5.c $(SRCDIR)/md5.h
  	$(CC) $(CFLAGS) -c $(SRCDIR)/md5.c
  
! usr_read.o: $(SRCDIR)/usr_read.c $(INCLUDES)
! 	$(CC) $(CFLAGS) -c $(SRCDIR)/usr_read.c
  
+ builddbm: builddbm.o usr_read.o
+ 	$(CC) $(CFLAGS) -o builddbm builddbm.o usr_read.o $(DBMLIBS) $(LIBS)
+ 
  builddbm.o: $(SRCDIR)/builddbm.c
  	$(CC) $(CFLAGS) -c $(SRCDIR)/builddbm.c
  
+ filters.o: $(SRCDIR)/filters.c $(SRCDIR)/radius.h
+ 	$(CC) $(CFLAGS) -c $(SRCDIR)/filters.c
+ 
+ cache.o: $(SRCDIR)/cache.c $(SRCDIR)/cache.h
+ 	$(CC) $(CFLAGS) -c $(SRCDIR)/cache.c
+ 
+ cache: $(SRCDIR)/cache.c $(SRCDIR)/cache.h
+ 	$(CC) $(CFLAGS) -DAUTOTEST -o ./cache $(SRCDIR)/cache.c
+ 
  lint:
! 	-lint -hbacvx -DLINT $(SOURCES)
  
  clean:
! 	rm -f *.o radiusd radpass builddbm radiusd.dbm cache
! 
! tar:
! 	@-rm radius.tar
! 	tar cvf radius.tar Makefile *h *c
! 
diff -c -N radiusd//acct.c ascendd//acct.c
*** radiusd//acct.c	Tue Dec 27 09:32:29 1994
--- ascendd//acct.c	Wed Dec 20 09:39:04 1995
***************
*** 3,9 ****
--- 3,11 ----
   *	RADIUS Accounting
   *	Remote Authentication Dial In User Service
   *
+  * ASCEND: @(#)acct.c	1.2 (95/07/25 00:55:24)
   *
+  *
   *	Livingston Enterprises, Inc.
   *	6920 Koll Center Parkway
   *	Pleasanton, CA   94566
***************
*** 43,50 ****
--- 45,54 ----
  #include	<signal.h>
  #include	<errno.h>
  #include	<sys/wait.h>
+ #include	<sys/stat.h>
  
  #include	"radius.h"
+ #include	"protos.h"
  
  extern char		recv_buffer[4096];
  extern char		send_buffer[4096];
***************
*** 56,69 ****
  extern UINT4		warning_seconds;
  extern int		errno;
  
! UINT4			calctime();
! 
  rad_accounting(authreq, activefd)
  AUTH_REQ	*authreq;
  int		activefd;
  {
  	FILE		*outfd;
- 	char		*ip_hostname();
  	char		clientname[128];
  	char		buffer[512];
  	VALUE_PAIR	*pair;
--- 60,71 ----
  extern UINT4		warning_seconds;
  extern int		errno;
  
! void
  rad_accounting(authreq, activefd)
  AUTH_REQ	*authreq;
  int		activefd;
  {
  	FILE		*outfd;
  	char		clientname[128];
  	char		buffer[512];
  	VALUE_PAIR	*pair;
***************
*** 123,128 ****
--- 125,131 ----
   *
   *************************************************************************/
  
+ void
  send_acct_reply(authreq, reply, msg, activefd)
  AUTH_REQ	*authreq;
  VALUE_PAIR	*reply;
***************
*** 138,144 ****
  	UINT4			lvalue;
  	u_char			digest[16];
  	int			secretlen;
- 	char			*ip_hostname();
  
  	auth = (AUTH_HDR *)send_buffer;
  
--- 141,146 ----
***************
*** 163,169 ****
  		case PW_TYPE_STRING:
  			len = strlen(reply->strvalue);
  			*ptr++ = len + 2;
! 			strcpy(ptr, reply->strvalue);
  			ptr += len;
  			total_length += len + 2;
  			break;
--- 165,171 ----
  		case PW_TYPE_STRING:
  			len = strlen(reply->strvalue);
  			*ptr++ = len + 2;
! 			strcpy((char *)ptr, reply->strvalue);
  			ptr += len;
  			total_length += len + 2;
  			break;
***************
*** 199,207 ****
  	auth->length = htons(total_length);
  
  	/* Calculate the response digest */
! 	secretlen = strlen(authreq->secret);
  	memcpy(send_buffer + total_length, authreq->secret, secretlen);
! 	md5_calc(digest, (char *)auth, total_length + secretlen);
  	memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
  	memset(send_buffer + total_length, 0, secretlen);
  
--- 201,209 ----
  	auth->length = htons(total_length);
  
  	/* Calculate the response digest */
! 	secretlen = strlen((char *)authreq->secret);
  	memcpy(send_buffer + total_length, authreq->secret, secretlen);
! 	md5_calc(digest, (u_char *)auth, total_length + secretlen);
  	memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
  	memset(send_buffer + total_length, 0, secretlen);
  
diff -c -N radiusd//attrprint.c ascendd//attrprint.c
*** radiusd//attrprint.c	Tue Dec 27 09:32:29 1994
--- ascendd//attrprint.c	Wed Dec 20 09:39:04 1995
***************
*** 3,9 ****
--- 3,11 ----
   *	RADIUS
   *	Remote Authentication Dial In User Service
   *
+  * ASCEND: @(#)attrprint.c	1.2 (95/07/25 00:55:25)
   *
+  *
   *	Livingston Enterprises, Inc.
   *	6920 Koll Center Parkway
   *	Pleasanton, CA   94566
***************
*** 40,45 ****
--- 42,48 ----
  #include	<ctype.h>
  
  #include	"radius.h"
+ #include	"protos.h"
  
  /*************************************************************************
   *
***************
*** 50,60 ****
   *
   *************************************************************************/
  
  fprint_attr_val(fd, pair)
  FILE		*fd;
  VALUE_PAIR	*pair;
  {
- 	DICT_VALUE	*dict_valget();
  	DICT_VALUE	*dval;
  	char		buffer[32];
  	u_char		*ptr;
--- 53,63 ----
   *
   *************************************************************************/
  
+ void
  fprint_attr_val(fd, pair)
  FILE		*fd;
  VALUE_PAIR	*pair;
  {
  	DICT_VALUE	*dval;
  	char		buffer[32];
  	u_char		*ptr;
***************
*** 96,101 ****
--- 99,118 ----
  					gmtime((time_t *)&pair->lvalue));
  		fprintf(fd, "%s = \"%s\"", pair->name, buffer);
  		break;
+ 
+ #if defined( BINARY_FILTERS )
+ 	case PW_TYPE_FILTER_BINARY:
+ 		{
+ 		    int		ix;
+ 
+ 		    fprintf( fd, "%s =", pair->name );
+ 		    for ( ix = 0; ix < pair->lvalue; ix += 1 ) {
+ 			fprintf( fd, " %02x", (u_char)(pair->strvalue[ ix ]) );
+ 		    }
+ 		    printf( "\n" );
+ 		}
+ 		break;
+ #endif /* BINARY_FILTERS */
  
  	default:
  		fprintf(fd, "Unknown type %d", pair->type);
diff -c -N radiusd//builddbm.c ascendd//builddbm.c
*** radiusd//builddbm.c	Tue Dec 27 09:32:29 1994
--- ascendd//builddbm.c	Wed Dec 20 11:13:35 1995
***************
*** 3,9 ****
--- 3,11 ----
   *	RADIUS
   *	Remote Authentication Dial In User Service
   *
+  * ASCEND: @(#)builddbm.c	1.2 (95/07/25 00:55:26)
   *
+  *
   *	Livingston Enterprises, Inc.
   *	6920 Koll Center Parkway
   *	Pleasanton, CA   94566
***************
*** 28,33 ****
--- 30,45 ----
  static char sccsid[] =
  "@(#)builddbm.c	1.4 Copyright 1992 Livingston Enterprises Inc";
  
+ #if defined(SOLARIS)
+ #       include <sys/uio.h>
+ #       include <unistd.h>
+ #       include <sys/stat.h>
+ #       include <fcntl.h>
+ #       include </usr/ucbinclude/dbm.h>
+ #else
+ #       include <dbm.h>
+ #endif  /* SOLARIS */
+ 
  #include	<sys/types.h>
  #include	<sys/socket.h>
  #include	<sys/time.h>
***************
*** 36,97 ****
  
  #include	<stdio.h>
  #include	<netdb.h>
! #include	<strings.h>
  #include	<pwd.h>
  #include	<time.h>
  #include	<ctype.h>
- #include	<dbm.h>
  
  #include	"radius.h"
  
  char		*progname;
- int		debug_flag;
  char		*radius_dir;
! 
! #define FIND_MODE_NAME	0
! #define FIND_MODE_REPLY	1
! #define FIND_MODE_SKIP	2
! #define FIND_MODE_FLUSH	3
! 
  FILE		*userfd;
! 
! main(argc,argv)
! int argc;
! char **argv;
  {
  	char	name[128];
! 	char	content[1024];
! 	char 	*progname;
  	int	fd;
  	datum	named;
  	datum	contentd;
  
  	progname = *argv;
  
! 	if((fd = open("users.pag", O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
! 		fprintf(stderr, "%s: Couldn't open users.pag for writing\n",progname);
  		exit(-1);
  	}
  	close(fd);
! 	if((fd = open("users.dir", O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
! 		fprintf(stderr, "%s: Couldn't open users.dir for writing\n",progname);
  		exit(-1);
  	}
  	close(fd);
! 	radius_dir = ".";
! 	if(dbminit("users") != 0) {
! 		fprintf(stderr, "%: Couldn't init dbm\n",progname);
  		exit(-1);
  	}
  
! 	while(user_read(name, content) == 0) {
  		named.dptr = name;
! 		named.dsize = strlen(name);
  		contentd.dptr = content;
! 		contentd.dsize = strlen(content);
  		if(store(named, contentd) != 0) {
! 			fprintf(stderr, "%s: Couldn't store datum for %s\n",
! 				progname,name);
  			exit(-1);
  		}
  	}
--- 48,173 ----
  
  #include	<stdio.h>
  #include	<netdb.h>
! #include	<string.h>
  #include	<pwd.h>
  #include	<time.h>
  #include	<ctype.h>
  
  #include	"radius.h"
+ #include	"protos.h"
  
  char		*progname;
  char		*radius_dir;
! char		*radius_users;
! char		pagfile[256];
! char		dirfile[256];
! char		dbmname[256];
  FILE		*userfd;
! FILE		*errf;
! extern int	curParseLine;
! int		verbose;
! extern int	warning;
! 
! #if !defined(FALSE)
! #  define FALSE	0
! #  define TRUE	1
! #endif
! 
! int main P__((int argc, char **argv));
! 
! int
! main(argc, argv)
! int	argc;
! char	**argv;
  {
  	char	name[128];
! 	char	content[4 * 1024];
  	int	fd;
  	datum	named;
  	datum	contentd;
+ 	int	c;
+ 	extern char	*optarg;
+ 	extern int	optind, opterr;
  
  	progname = *argv;
+ 	radius_dir = RADIUS_DIR;
+ 	radius_users = RADIUS_USERS;
+ 	errf = stderr;
+ 	verbose = FALSE;
+ 	warning = TRUE;
+ 
+ 	while( (c = getopt(argc, argv, "d:ehu:v")) != -1 ) {
+ 		switch( c ) {
+ 		case 'h':
+ 		case '?':
+ 		default:
+ 			printf("\n%s options are:\n%s%s%s%s%s\n", progname,
+ 				"\t-d dir\t\tradius directory\n",
+ 				"\t-e\t\tuse stdout rather than stderr\n",
+ 				"\t-h\t\trequest help\n",
+ 				"\t-u file\t\tradius users file\n",
+ 				"\t-v\t\tverbose mode\n"
+ 			);
+ 			return -1;
+ 		case 'd':
+ 			radius_dir = optarg;
+ 			break;
+ 		case 'e':
+ 			errf = stdout;
+ 			break;
+ 		case 'u':
+ 			radius_users = optarg;
+ 			break;
+ 		case 'v':
+ 			verbose = TRUE;
+ 			break;
+ 		}
+ 	}
  
! 	sprintf(pagfile, "%s/%s.pag", radius_dir, radius_users);
! 	if((fd = open(pagfile, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
! 		fprintf(errf, "%s: Couldn't open %s for writing\n",
! 			progname, pagfile);
  		exit(-1);
  	}
  	close(fd);
! 	sprintf(dirfile, "%s/%s.dir", radius_dir, radius_users);
! 	if((fd = open(dirfile, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
! 		fprintf(errf, "%s: Couldn't open %s for writing\n",
! 			progname, dirfile);
  		exit(-1);
  	}
  	close(fd);
! 	sprintf(dbmname, "%s/%s", radius_dir, radius_users);
! 	if(dbminit(dbmname) != 0) {
! 		fprintf(errf, "%s: Couldn't dbminit(%s)\n", progname, dbmname);
  		exit(-1);
  	}
  
! 	userfd = (FILE *)NULL;
! 	curParseLine = 0;
! 	while(user_read(&userfd, name, content) == 0) {
! 		if( verbose ) {
! 			fprintf(stdout, "\nRECORD: {'%s', '%s'}\n",
! 				name, content);
! 		}
! 		named.dptr = name;
! 		named.dsize = strlen(name)+1;
! 		contentd = fetch(named);
! 		if(contentd.dsize != 0) {	/* name found */
! 			char msg[128];
! 
! 			sprintf(msg, "Skipping duplicate record\n\tfor user '%s'", name);
! 			warn(msg);
! 			continue;
! 		}
  		named.dptr = name;
! 		named.dsize = strlen(name)+1;
  		contentd.dptr = content;
! 		contentd.dsize = strlen(content)+1;
  		if(store(named, contentd) != 0) {
! 			fprintf(errf, "%s: Couldn't store datum for %s\n",
! 				progname, name);
  			exit(-1);
  		}
  	}
***************
*** 99,187 ****
  	exit(0);
  }
  
- /*************************************************************************
-  *
-  *	Function: user_read
-  *
-  *	Purpose: Return each user in the database - name is key content
-  *		 is 2 strings - check values, and reply values seperated
-  *		 by a newline.
-  *
-  *************************************************************************/
- 
- user_read(name, content)
- char	*name;
- char	*content;
- {
- 	char		buffer[256];
- 	char		*ptr;
- 	int		namelen;
- 	int		mode;
- 	VALUE_PAIR	*check_first;
- 	VALUE_PAIR	*reply_first;
- 
- 	/*
- 	 * Open the user table
- 	 */
- 	if(userfd == (FILE *)NULL) {
- 		sprintf(buffer, "%s/%s", radius_dir, RADIUS_USERS);
- 		if((userfd = fopen(buffer, "r")) == (FILE *)NULL) {
- 			fprintf(stderr, "%s:Couldn't open %s for reading\n",
- 					progname, buffer);
- 			exit(-1);
- 		}
- 	}
- 
- 	mode = FIND_MODE_NAME;
- 
- 	while(fgets(buffer, sizeof(buffer), userfd) != (char *)NULL) {
- 		if(mode == FIND_MODE_NAME) {
- 			/*
- 			 * Find the entry starting with the users name
- 			 */
- 			if(*buffer != '#' && *buffer != '\t') {
- 				ptr = buffer;
- 				while(*ptr != ' ' && *ptr != '\t' &&
- 								*ptr != '\0') {
- 					*name++ = *ptr++;
- 				}
- 				*name = '\0';
- 				if(*ptr == '\0') {
- 					continue;
- 				}
- 				ptr++;
- 				while(*ptr == ' ' || *ptr == '\t') {
- 					ptr++;
- 				}
- 				strcpy(content, ptr);
- 				content += strlen(content);
- 				mode = FIND_MODE_REPLY;
- 			}
- 		}
- 		else {
- 			if(*buffer == ' ' || *buffer == '\t') {
- 				ptr = buffer;
- 				while(*ptr == ' ' || *ptr == '\t') {
- 					ptr++;
- 				}
- 				strcpy(content, ptr);
- 				content += strlen(content);
- 				content -= 2;
- 				while(*content == ' ' || *content == '\t' ) {
- 					content--;
- 				}
- 				content++;
- 				*content = '\0';
- 				if(*(content - 1) != ',') {
- 					return(0);
- 				}
- 			}
- 			else {
- 				/* We are done */
- 				return(0);
- 			}
- 		}
- 	}
- 	fclose(userfd);
- 	return(-1);
- }
--- 175,177 ----
diff -c -N radiusd//cache.c ascendd//cache.c
*** radiusd//cache.c
--- ascendd//cache.c	Wed Dec 20 09:43:18 1995
***************
*** 0 ****
--- 1,596 ----
+ /*
+  * ASCEND: @(#)cache.c	1.0 (95/10/05 00:55:30)
+  *
+  *      Copyright (c) 1994 Ascend Communications, Inc.
+  *      All rights reserved.
+  *
+  *	Permission to copy all or part of this material for any purpose is
+  *	granted provided that the above copyright notice and this paragraph
+  *	are duplicated in all copies.  THIS SOFTWARE IS PROVIDED ``AS IS''
+  *	AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+  *	LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+  *	FOR A PARTICULAR PURPOSE.
+  */
+ 
+ #include	<sys/types.h>
+ #include	<ctype.h>
+ #if defined(BSDI)
+ #	include	<memory.h>
+ #	include	<stdlib.h>
+ #else
+ #	include	<malloc.h>
+ #endif
+ #include	<string.h>
+ #include	<sys/time.h>
+ 
+ #if defined(AUTOTEST)
+ #	include	<stdio.h>
+ #	include	<unistd.h>
+ #endif
+ 
+ #include	"cache.h"
+ 
+ static CONST HASHVAL *
+ 	_hlist_search P__((HASHLIST **list, CONST HASHKEY *key, int len));
+ static HASHLIST *
+ 	_hlist_locate P__((HASHLIST **list, CONST HASHKEY *key, int len));
+ static void _hlist_expire P__((HASHLIST **list));
+ static int _key_expired P__((HASHLIST *elem));
+ static int _idle_expired P__((HASHLIST *elem));
+ static time_t _calc_expiration P__((time_t duration));
+ 
+ #if defined(AUTOTEST)
+ 	static CACHE	cache;	/* allocate storage for the cache */
+ 	int	count[BUCKETS];	/* allocater storage for statistics */
+ #	define log_err	printf	/* debug output */
+ #else
+ 	extern int log_err P__((char *msg));
+ #endif
+ 
+ 
+ 	/*
+ 	 * Initialise the given cache.
+ 	 */
+ void
+ cache_init(cache, buckets)
+ 	CACHE	*cache;
+ 	int		buckets;
+ {
+ 	int	i;
+ 
+ 	cache->buckets = buckets;
+ 	for( i = 0; i < buckets; i++ ) {
+ 		cache->table[i] = (HASHLIST *)0;
+ #if defined(AUTOTEST)
+ 		count[i] = 0;
+ #endif
+ 	}
+ }
+ 
+ 	/*
+ 	 * Search the given cache for the indicated key.
+ 	 *
+ 	 * Return a pointer to the associated value or (HASHVAL *)0
+ 	 * if the key is not found
+ 	 */
+ CONST HASHVAL *
+ cache_search(cache, key, len)
+ 	CACHE		*cache;
+ 	CONST HASHKEY	*key;
+ 	int		len;
+ {
+ 	int bucket;
+ 
+ 	if( len > MAX_KEY_LEN ) {
+ 		return (CONST HASHVAL *)0;
+ 	}
+ 
+ 	bucket = hash(key, len, cache->buckets);
+ 	if( cache->table[bucket] ) {
+ 		return _hlist_search(&cache->table[bucket], key, len);
+ 	}
+ 	else {
+ 		return (CONST HASHVAL *)0;
+ 	}
+ }
+ 
+ 	/*
+ 	 * Insert the given info into the given cache.
+ 	 *
+ 	 * Checks for duplicate records.
+ 	 *
+ 	 * Return TRUE if inserted, else FALSE.
+ 	 */
+ int
+ cache_insert(cache, key, key_len, val, val_len, duration, idle)
+ 	CACHE		*cache;
+ 	CONST HASHKEY	*key;
+ 	int		key_len;
+ 	CONST HASHVAL	*val;
+ 	int		val_len;
+ 	time_t		duration;
+ 	time_t		idle;
+ {
+ 	HASHLIST *elem;
+ 	int bucket;
+ 	CONST HASHVAL *res;
+ 
+ 	if( (key_len > MAX_KEY_LEN) || (val_len > MAX_VAL_LEN) ) {
+ 		return FALSE;
+ 	}
+ 
+ 	bucket = hash(key, key_len, cache->buckets);
+ 	res = _hlist_search(&cache->table[bucket], key, key_len);
+ 
+ 	if( res && (res != ELEM_DELETED) ) {
+ 		return FALSE;	/* already in table, delete first */
+ 	}
+ 
+ 	elem = (HASHLIST *)malloc(sizeof(*elem));
+ 	if( !elem ) {
+ 		return FALSE;
+ 	}
+ 	else {
+ 		elem->next = cache->table[bucket];
+ 		memcpy(elem->key, key, (size_t)key_len);
+ 		memcpy(elem->val, val, (size_t)val_len);
+ 		elem->time = _calc_expiration(duration);
+ 		if( idle ) {
+ 			elem->idle = _calc_expiration(idle);
+ 			elem->idling = TRUE;
+ 		}
+ 		else {
+ 			elem->idling = FALSE;
+ 		}
+ 		cache->table[bucket] = elem;
+ #if defined(AUTOTEST)
+ 		count[bucket]++;
+ #endif
+ #if(0)
+ 		printf("cache_insert(key<%d><%s>, val<%d><%s>)\n",
+ 			key_len, elem->key, val_len, elem->val);
+ #endif
+ 		return TRUE;
+ 	}
+ }
+ 
+ 	/*
+ 	 * Delete the given info from the given cache.
+ 	 *
+ 	 * Return TRUE if deleted, else FALSE.
+ 	 */
+ int
+ cache_delete(cache, key, len)
+ 	CACHE		*cache;
+ 	CONST HASHKEY	*key;
+ 	int		len;
+ {
+ 	int bucket;
+ 	HASHLIST *cur;
+ 	HASHLIST *prev = (HASHLIST *)0;
+ 	HASHLIST **list;
+ 	int result = FALSE;
+ 
+ 	if( len > MAX_KEY_LEN ) {
+ 		return FALSE;
+ 	}
+ 
+ 	bucket = hash(key, len, cache->buckets);
+ 	list = &cache->table[bucket];
+ 
+ 	for( cur = *list; cur; prev = cur, cur = cur->next ) {
+ 		if( memcmp(key, cur->key, len) == 0 ) {
+ 			if( prev ) {
+ 				prev->next = cur->next;
+ 			}
+ 			else {
+ 				*list = cur->next;
+ 			}
+ 			free(cur);
+ 			result = TRUE;
+ 			break;
+ 		}
+ 	}
+ 	return result;
+ }
+ 
+ 	/*
+ 	 * Update the idle time for this entry
+ 	 *
+ 	 * Return TRUE if elem has idling enabled, else FALSE.
+ 	 */
+ int
+ cache_idle_update(cache, key, len, idle)
+ 	CACHE		*cache;
+ 	CONST HASHKEY	*key;
+ 	int		len;
+ 	time_t		idle;
+ {
+ 	int bucket;
+ 	HASHLIST *elem;
+ 
+ 	if( len > MAX_KEY_LEN ) {
+ 		return FALSE;
+ 	}
+ 
+ 	bucket = hash(key, len, cache->buckets);
+ 	elem = _hlist_locate(&cache->table[bucket], key, len);
+ 	elem->idle = _calc_expiration(idle);
+ 	return elem->idling;
+ }
+ 
+ 	/*
+ 	 * Search the given cache for expired keys and delete them.
+ 	 */
+ void
+ cache_expire(cache)
+ 	CACHE		*cache;
+ {
+ 	int ix;
+ 
+ 	for(ix = 0; ix < cache->buckets; ix++ ) {
+ 		_hlist_expire(&cache->table[ix]);
+ 	}
+ }
+ 
+ 	/*
+ 	 * Search the given hash list for the indicated key.
+ 	 *
+ 	 * Return a pointer to the associated elem or (HASHLIST *)0
+ 	 * if the key is not found.
+ 	 */
+ static HASHLIST *
+ _hlist_locate(list, key, len)
+ 	HASHLIST	**list;
+ 	CONST HASHKEY	*key;
+ 	int		len;
+ {
+ 	HASHLIST *cur;
+ 	HASHLIST *prev;
+ 	HASHLIST *retval = (HASHLIST *)0;
+ 	prev = (HASHLIST *)0;
+ 	for( cur = *list; cur; prev = cur, cur = cur->next ) {
+ 		if( memcmp(key, cur->key, len) == 0 ) {
+ 			retval = cur;
+ 			break;
+ 		}
+ 	}
+ 
+ 	return retval;
+ }
+ 
+ 	/*
+ 	 * Search the given hash list for the indicated key.
+ 	 *
+ 	 * Return a pointer to the associated value or (HASHVAL *)0
+ 	 * if the key is not found.
+ 	 *
+ 	 * For efficiency, delete the search entry if it has expired
+ 	 * and return ELEM_DELETED.
+ 	 *
+ 	 * Does NOT update the idle timer.
+ 	 */
+ static CONST HASHVAL *
+ _hlist_search(list, key, len)
+ 	HASHLIST	**list;
+ 	CONST HASHKEY	*key;
+ 	int		len;
+ {
+ 	HASHLIST *cur;
+ 	HASHLIST *prev;
+ 	HASHVAL *retval = (HASHVAL *)0;
+ 	prev = (HASHLIST *)0;
+ 	for( cur = *list; cur; prev = cur, cur = cur->next ) {
+ 		if( memcmp(key, cur->key, len) == 0 ) {
+ 			retval = cur->val;
+ 			break;
+ 		}
+ 	}
+ 	if( retval ) {
+ 		if( (_key_expired(cur) == TRUE)
+ 		 || ((cur->idling == TRUE) && (_idle_expired(cur) == TRUE)) ) {
+ 			/* delete it now */
+ 			if( prev ) {
+ 				prev->next = cur->next;
+ 			}
+ 			else {
+ 				*list = cur->next;
+ 			}
+ 			retval = ELEM_DELETED;
+ 			free(cur);
+ 		}
+ 	}
+ 	return (CONST HASHVAL *)retval;
+ }
+ 
+ 	/*
+ 	 * Search for and delete all expired keys
+ 	 */
+ static void
+ _hlist_expire(list)
+ 	HASHLIST	**list;
+ {
+ 	HASHLIST *cur;
+ 	HASHLIST *prev;
+ 	prev = (HASHLIST *)0;
+ 	for( cur = *list; cur; prev = cur, cur = cur->next ) {
+ 		if( _key_expired(cur) ) {
+ 			if( prev ) {
+ 				prev->next = cur->next;
+ 			}
+ 			else {
+ 				*list = cur->next;
+ 			}
+ 			free(cur);
+ 		}
+ 	}
+ }
+ 
+ 	/*
+ 	 * Return TRUE if the key has expired
+ 	 */
+ static int
+ _key_expired(elem)
+ 	HASHLIST	*elem;
+ {
+ 	time_t curtime;
+ 
+ 	curtime = time((time_t *)0);
+ 	if( curtime == -1 ) {
+ 		log_err("_key_expired(): time() err\n");
+ 		return TRUE;
+ 	}
+ 	if( curtime > elem->time ) {
+ 		return TRUE;
+ 	}
+ 	else {
+ 		return FALSE;
+ 	}
+ }
+ 
+ 	/*
+ 	 * Return TRUE if the idle timer has expired
+ 	 */
+ static int
+ _idle_expired(elem)
+ 	HASHLIST	*elem;
+ {
+ 	time_t curtime;
+ 
+ 	curtime = time((time_t *)0);
+ 	if( curtime == -1 ) {
+ 		log_err("_key_expired(): time() err\n");
+ 		return TRUE;
+ 	}
+ 	if( curtime > elem->idle ) {
+ 		return TRUE;
+ 	}
+ 	else {
+ 		return FALSE;
+ 	}
+ }
+ 
+ 	/*
+ 	 * Calculate the time of expiration
+ 	 */
+ static time_t
+ _calc_expiration(duration)
+ 	time_t duration;
+ {
+ 	time_t curtime;
+ 
+ 	curtime = time((time_t *)0);
+ 	if( curtime == -1 ) {
+ 		log_err("_calc_expiration(): time() err\n");
+ 		return duration;
+ 	}
+ 	curtime += duration;
+ 	return curtime;
+ }
+ 
+ #define	CRC_16_POLY	(0xa001)
+ /*--------------------------------------------------------------------
+ 		NOTE: 17 (_not_ 16) terms [x^16 ... x^0]
+ 
+ 		X^16 + X^15 + X^2 + 1
+ 			= 1 1000 0000 0000 0101
+ 			= 18005
+ 			  ^ implicit value (17th bit)
+ 
+ 		Inverting the bit order yields
+ 			= 1010 0000 0000 0001 1
+ 			= a0011
+ 			      ^ implicit value (17th  bit)
+ --------------------------------------------------------------------*/
+ 
+ /**********************************************************
+ 
+ 
+ 	CRC-16 Byte Look-up Table <initial crc=0>
+ 
+ 		P(x) = a001 = 1 + x^2 + x^15 + x^16
+ 
+ 	This table was automatically generated by 'gencrc'
+ 
+ 	-- Do _NOT_ modify this table manually ! --
+ 
+ 	Table generated on Thu Oct  5 16:45:34 1995
+ 
+ 
+ **********************************************************/
+ 
+ unsigned short crc_16_lookup[256] = {
+ 	0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 
+ 	0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, 
+ 	0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 
+ 	0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, 
+ 	0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, 
+ 	0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, 
+ 	0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, 
+ 	0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, 
+ 	0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, 
+ 	0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, 
+ 	0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, 
+ 	0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, 
+ 	0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 
+ 	0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, 
+ 	0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, 
+ 	0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, 
+ 	0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, 
+ 	0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, 
+ 	0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 
+ 	0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 
+ 	0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 
+ 	0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, 
+ 	0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, 
+ 	0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, 
+ 	0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, 
+ 	0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, 
+ 	0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, 
+ 	0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, 
+ 	0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 
+ 	0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, 
+ 	0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 
+ 	0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
+ };
+ 
+ /*-----------------------------------------------------------------------
+ 	unsigned short hash(key, len, buckets)
+ 
+ 
+ 	Calculate the CRC-16 of a key, modulo MODULUS
+ 
+ 		uses the x^16 + x^15 + x^2 + 1 CRC-16 algorithm
+ 
+ 	Return the 16 bit crc number for a key, mod BUCKETS
+ 	Uses a 256 entry table lookup
+ -----------------------------------------------------------------------*/
+ u_short
+ hash(key, len, buckets)
+ 	CONST HASHKEY	*key;
+ 	int		len;
+ 	int		buckets;
+ {
+ 	u_short	n, crc;
+ 	int	i;
+   
+ 	crc = 0;
+ 	for( i = len; i; i-- ) {
+ 		n = *key++;	
+ 		n ^= crc;
+ 		crc = crc_16_lookup[n & 0xff] ^ (crc >> 8);
+ 	}
+ 	return (unsigned int)crc % (unsigned int)buckets;
+ }
+ 
+ /**********************************************************************
+ 
+ 			Test code
+ 
+ **********************************************************************/
+ 
+ #if defined(AUTOTEST)
+ int
+ main(argc, argv)
+ 	int	argc;
+ 	char	**argv;
+ {
+ 	FILE	*fd;
+ 	HASHVAL	*val;
+ 	int	stat;
+ 	char	buf[101];
+ 	int	least, most;
+ 	int	i;
+ 	char	*words;		/* typically, /usr/dict/words */
+ 	int	len;
+ 
+ 	if( argc < 2 ) {
+ 		words = "/usr/dict/words";
+ 	}
+ 	else {
+ 		words = argv[1];
+ 	}
+ 
+ 	cache_init(&cache, BUCKETS);
+ 	fd = fopen(words, "r");
+ 	if( !fd ) {
+ 		printf("Error opening '%s'\n", words);
+ 		exit(-1);
+ 	}
+ 
+ 	while( fgets(buf, 100, fd) != (char *)0 ) {
+ 		len = strlen(buf);
+ 		if( buf[len-1] == '\n' ) {
+ 			buf[len-1] = '\0';
+ 			len--;
+ 		}
+ 		len = MIN((size_t)MAX_KEY_LEN, strlen(buf));
+ 		buf[len+1] = '\0';
+ 		stat = cache_insert(&cache, buf, len+1, buf, len+1, 1000);
+ 		printf("Insert key <%s>: %s\n",
+ 				buf, (stat == TRUE) ? "GOOD" : "BAD");
+ 	}
+ 
+ 	least = most = 0;
+ 	for( i = 0; i < BUCKETS; i++ ) {
+ 		if( count[i] < least ) {
+ 			least = count[i];
+ 		}
+ 		else if( count[i] > most ) {
+ 			most = count[i];
+ 		}
+ 	}
+ 	printf("\n\nShortest List Len=%d, Longest List Len=%d\n\n",
+ 		least, most);
+ 	for( i = 0; i < BUCKETS; i++ ) {
+ 		if( (i % 10) == 0 ) {
+ 			printf("\ncount[%4x]= ", i);
+ 		}
+ 		printf("%4d ", count[i]);
+ 	}
+ 	printf("\n\n");
+ 
+ 	rewind(fd);
+ 	while( fgets(buf, 100, fd) != (char *)0 ) {
+ 		char	*msg;
+ 
+ 		len = strlen(buf);
+ 		if( buf[len-1] == '\n' ) {
+ 			buf[len-1] = '\0';
+ 			len--;
+ 		}
+ 		len = MIN((size_t)MAX_KEY_LEN, strlen(buf));
+ 		buf[len+1] = '\0';
+ 		val = (HASHVAL *)cache_search(&cache, buf, len+1);
+ 		if( val && (val != ELEM_DELETED) ) {
+ 			msg = "GOOD";
+ 		}
+ 		else if( val == ELEM_DELETED ) {
+ 			msg = "DELETED";
+ 		}
+ 		else {
+ 			msg = "BAD";
+ 		}
+ 		printf("Search key <%s, %s>: %s\n", buf, val, msg);
+ 	}
+ 
+ 	rewind(fd);
+ 	while( fgets(buf, 100, fd) != (char *)0 ) {
+ 		len = strlen(buf);
+ 		if( buf[len-1] == '\n' ) {
+ 			buf[len-1] = '\0';
+ 			len--;
+ 		}
+ 		len = MIN((size_t)MAX_KEY_LEN, strlen(buf));
+ 		buf[len+1] = '\0';
+ 		stat = cache_delete(&cache, buf, len+1);
+ 		printf("Delete key <%s>: %s\n",
+ 				buf, (stat == TRUE) ? "GOOD" : "BAD");
+ 	}
+ 
+ 	fclose(fd);
+ 	return 0;
+ }
+ 
+ #endif
+ 
diff -c -N radiusd//cache.h ascendd//cache.h
*** radiusd//cache.h
--- ascendd//cache.h	Wed Dec 20 09:42:17 1995
***************
*** 0 ****
--- 1,91 ----
+ /*
+  * ASCEND: @(#)cache.h	1.0 (95/10/05 00:55:30)
+  *
+  *      Copyright (c) 1994 Ascend Communications, Inc.
+  *      All rights reserved.
+  *
+  *	Permission to copy all or part of this material for any purpose is
+  *	granted provided that the above copyright notice and this paragraph
+  *	are duplicated in all copies.  THIS SOFTWARE IS PROVIDED ``AS IS''
+  *	AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+  *	LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+  *	FOR A PARTICULAR PURPOSE.
+  */
+ 
+ #if defined(__STDC__) && (__STDC__ == 1)
+ #	define	P__(s)	s
+ #	define	CONST	const
+ #else
+ #	define	P__(s)	(/* s */)
+ #	define	CONST	/* const */
+ #endif
+ 
+ #if !defined(TRUE)
+ #	define TRUE	1
+ #endif
+ #if !defined(FALSE)
+ #	define FALSE	0
+ #endif
+ 
+ #if !defined(MIN)
+ #	define MIN(x, y)	(((x) < (y)) ? (x) : (y))
+ #endif
+ 
+ #if !defined(MAX)
+ #	define MAX(x, y)	(((x) > (y)) ? (x) : (y))
+ #endif
+ 
+ #define MAX_KEY_LEN	16
+ #define MAX_VAL_LEN	16
+ 
+ 	/*
+ 	 * BUCKETS should be prime; try 1021, 2039, 4093, 8191, 16381.
+ 	 * More buckets use more statically allocated memory but decrease
+ 	 * the length of the hash lists, which will improve performance.
+ 	 */
+ #define BUCKETS	4093
+ 
+ typedef char HASHKEY;
+ typedef char HASHVAL;
+ 
+ #define ELEM_DELETED	((HASHVAL *)(-1))
+ 
+ typedef struct HASHLIST {
+ 	struct HASHLIST	*next;
+ 	HASHKEY		key[MAX_KEY_LEN + 1];
+ 	HASHVAL		val[MAX_VAL_LEN + 1];
+ 	time_t		time;
+ 	int		idling;		/* Boolean: use idle time */
+ 	time_t		idle;
+ } HASHLIST;
+ 
+ typedef struct CACHE {
+ 	int		buckets;
+ 	HASHLIST	*table[BUCKETS];
+ } CACHE;
+ 
+ typedef enum CacheMsgType {
+ 	CACHE_INSERT	= 1,
+ 	CACHE_DELETE,
+ 	CACHE_IDLE_UPDATE
+ } CacheMsgType;
+ 
+ typedef struct CacheMsg {
+ 	CacheMsgType	type;
+ 	HASHKEY		key[MAX_KEY_LEN + 1];
+ 	HASHVAL		val[MAX_VAL_LEN + 1];
+ 	time_t		time;
+ 	time_t		idle;
+ } CacheMsg;
+ 
+ 	/***********************/
+ 	/* function prototypes */
+ 	/***********************/
+ 
+ u_short hash P__((CONST HASHKEY *key, int len, int buckets));
+ void cache_init P__((CACHE *dict, int buckets));
+ CONST HASHVAL *cache_search P__((CACHE *dict, CONST HASHKEY *key, int len));
+ int cache_insert P__((CACHE *dict, CONST HASHKEY *key, int key_len, CONST HASHVAL *val, int val_len, time_t duration, time_t idle));
+ int cache_delete P__((CACHE *dict, CONST HASHKEY *key, int len));
+ void cache_expire P__((CACHE *dict));
+ int cache_idle_update P__((CACHE *cache, CONST HASHKEY *key, int len, time_t idle));
diff -c -N radiusd//conf.h ascendd//conf.h
*** radiusd//conf.h	Tue Dec 27 09:32:29 1994
--- ascendd//conf.h	Wed Dec 20 09:39:08 1995
***************
*** 3,9 ****
--- 3,11 ----
   *	RADIUS
   *	Remote Authentication Dial In User Service
   *
+  * ASCEND: @(#)conf.h	1.2 (95/07/25 00:55:28)
   *
+  *
   *	Livingston Enterprises, Inc.
   *	6920 Koll Center Parkway
   *	Pleasanton, CA   94566
***************
*** 30,37 ****
--- 32,41 ----
   */
  
  #if defined(__alpha) && defined(__osf__)
+ #define UINT4_IS_UINT
  typedef unsigned int	UINT4;
  #else
+ #define UINT4_IS_ULONG
  typedef unsigned long	UINT4;
  #endif
  
***************
*** 38,52 ****
  #if defined(unixware) || defined(sys5) || defined(M_UNIX)
  #include        <string.h>
  #else   /* unixware */
  #include        <strings.h>
  #endif  /* unixware */
  
! #if defined(bsdi)
  #include        <machine/inline.h>
  #include        <machine/endian.h>
! #else	/* bsdi */
  #include        <malloc.h>
! #endif	/* bsdi */
  
  #if defined(aix)
  #include	<sys/select.h>
--- 42,61 ----
  #if defined(unixware) || defined(sys5) || defined(M_UNIX)
  #include        <string.h>
  #else   /* unixware */
+ #if defined(SOLARIS)
+ #include	<string.h>
+ #else
  #include        <strings.h>
+ #endif
  #endif  /* unixware */
  
! #if defined(BSDI)
  #include        <machine/inline.h>
  #include        <machine/endian.h>
! #include        <stdlib.h>
! #else	/* BSDI */
  #include        <malloc.h>
! #endif	/* BSDI */
  
  #if defined(aix)
  #include	<sys/select.h>
diff -c -N radiusd//dict.c ascendd//dict.c
*** radiusd//dict.c	Tue Dec 27 09:32:29 1994
--- ascendd//dict.c	Wed Dec 20 09:39:04 1995
***************
*** 3,9 ****
--- 3,11 ----
   *	RADIUS
   *	Remote Authentication Dial In User Service
   *
+  * ASCEND: @(#)dict.c	1.2 (95/07/25 00:55:29)
   *
+  *
   *	Livingston Enterprises, Inc.
   *	6920 Koll Center Parkway
   *	Pleasanton, CA   94566
***************
*** 32,39 ****
--- 34,44 ----
  #include	<sys/types.h>
  #include	<pwd.h>
  #include	<ctype.h>
+ #include	<stdlib.h>
+ #include	<sys/time.h>	/* gettimeofday() */
  
  #include	"radius.h"
+ #include	"protos.h"
  
  extern char		*progname;
  extern int		debug_flag;
***************
*** 72,80 ****
  	if((dictfd = fopen(buffer, "r")) == (FILE *)NULL) {
  		fprintf (stderr, "%s: Couldn't open dictionary: %s\n",
  			progname, buffer);
! 		return(-1);
  	}
  
  	line_no = 0;
  	while(fgets(buffer, sizeof(buffer), dictfd) != (char *)NULL) {
  		line_no++;
--- 77,88 ----
  	if((dictfd = fopen(buffer, "r")) == (FILE *)NULL) {
  		fprintf (stderr, "%s: Couldn't open dictionary: %s\n",
  			progname, buffer);
! 		return DICTFILE_READ_ERR;
  	}
  
+ 	dictionary_attributes = (DICT_ATTR *)0;
+ 	dictionary_values = (DICT_VALUE *)0;
+ 
  	line_no = 0;
  	while(fgets(buffer, sizeof(buffer), dictfd) != (char *)NULL) {
  		line_no++;
***************
*** 92,108 ****
  				fprintf(stderr,
  			"%s: Invalid attribute on line %d of dictionary\n",
  					progname, line_no);
! 				return(-1);
  			}
  
  			/*
  			 * Validate all entries
  			 */
! 			if(strlen(namestr) > 31) {
  				fprintf(stderr,
  			"%s: Invalid name length on line %d of dictionary\n",
  					progname, line_no);
! 				return(-1);
  			}
  
  			if(!isdigit(*valstr)) {
--- 100,116 ----
  				fprintf(stderr,
  			"%s: Invalid attribute on line %d of dictionary\n",
  					progname, line_no);
! 				return DICTFILE_ATTRLINE_ERR;
  			}
  
  			/*
  			 * Validate all entries
  			 */
! 			if(strlen(namestr) > (size_t)31) {
  				fprintf(stderr,
  			"%s: Invalid name length on line %d of dictionary\n",
  					progname, line_no);
! 				return DICTFILE_ATTRNAME_ERR;
  			}
  
  			if(!isdigit(*valstr)) {
***************
*** 109,115 ****
  				fprintf(stderr,
  			"%s: Invalid value on line %d of dictionary\n",
  					progname, line_no);
! 				return(-1);
  			}
  			value = atoi(valstr);
  
--- 117,123 ----
  				fprintf(stderr,
  			"%s: Invalid value on line %d of dictionary\n",
  					progname, line_no);
! 				return DICTFILE_ATTRVALUE_ERR;
  			}
  			value = atoi(valstr);
  
***************
*** 125,135 ****
  			else if(strcmp(typestr, "date") == 0) {
  				type = PW_TYPE_DATE;
  			}
  			else {
  				fprintf(stderr,
  			"%s: Invalid type on line %d of dictionary\n",
  					progname, line_no);
! 				return(-1);
  			}
  
  			/* Create a new attribute for the list */
--- 133,148 ----
  			else if(strcmp(typestr, "date") == 0) {
  				type = PW_TYPE_DATE;
  			}
+ #if defined( BINARY_FILTERS )
+                         else if(strcmp(typestr, "abinary") == 0) {
+                                 type = PW_TYPE_FILTER_BINARY;
+                         }
+ #endif /* BINARY_FILTERS */
  			else {
  				fprintf(stderr,
  			"%s: Invalid type on line %d of dictionary\n",
  					progname, line_no);
! 				return DICTFILE_ATTRTYPE_ERR;
  			}
  
  			/* Create a new attribute for the list */
***************
*** 137,143 ****
  					(DICT_ATTR *)NULL) {
  				fprintf(stderr, "%s: out of memory\n",
  							progname);
! 				return(-1);
  			}
  			strcpy(attr->name, namestr);
  			attr->value = value;
--- 150,156 ----
  					(DICT_ATTR *)NULL) {
  				fprintf(stderr, "%s: out of memory\n",
  							progname);
! 				return MEMORY_ERR;
  			}
  			strcpy(attr->name, namestr);
  			attr->value = value;
***************
*** 155,178 ****
  				fprintf(stderr,
  			"%s: Invalid value entry on line %d of dictionary\n",
  					progname, line_no);
! 				return(-1);
  			}
  
  			/*
  			 * Validate all entries
  			 */
! 			if(strlen(attrstr) > 31) {
  				fprintf(stderr,
  			"%s: Invalid attribute length on line %d of dictionary\n",
  					progname, line_no);
! 				return(-1);
  			}
  
! 			if(strlen(namestr) > 31) {
  				fprintf(stderr,
  			"%s: Invalid name length on line %d of dictionary\n",
  					progname, line_no);
! 				return(-1);
  			}
  
  			if(!isdigit(*valstr)) {
--- 168,191 ----
  				fprintf(stderr,
  			"%s: Invalid value entry on line %d of dictionary\n",
  					progname, line_no);
! 				return DICTFILE_VALLINE_ERR;
  			}
  
  			/*
  			 * Validate all entries
  			 */
! 			if(strlen(attrstr) > (size_t)31) {
  				fprintf(stderr,
  			"%s: Invalid attribute length on line %d of dictionary\n",
  					progname, line_no);
! 				return DICTFILE_VALATTR_ERR;
  			}
  
! 			if(strlen(namestr) > (size_t)31) {
  				fprintf(stderr,
  			"%s: Invalid name length on line %d of dictionary\n",
  					progname, line_no);
! 				return DICTFILE_VALNAME_ERR;
  			}
  
  			if(!isdigit(*valstr)) {
***************
*** 179,185 ****
  				fprintf(stderr,
  			"%s: Invalid value on line %d of dictionary\n",
  					progname, line_no);
! 				return(-1);
  			}
  			value = atoi(valstr);
  
--- 192,198 ----
  				fprintf(stderr,
  			"%s: Invalid value on line %d of dictionary\n",
  					progname, line_no);
! 				return DICTFILE_VALVALUE_ERR;
  			}
  			value = atoi(valstr);
  
***************
*** 188,194 ****
  					(DICT_VALUE *)NULL) {
  				fprintf(stderr, "%s: out of memory\n",
  							progname);
! 				return(-1);
  			}
  			strcpy(dval->attrname, attrstr);
  			strcpy(dval->name, namestr);
--- 201,207 ----
  					(DICT_VALUE *)NULL) {
  				fprintf(stderr, "%s: out of memory\n",
  							progname);
! 				return MEMORY_ERR;
  			}
  			strcpy(dval->attrname, attrstr);
  			strcpy(dval->name, namestr);
diff -c -N radiusd//filters.c ascendd//filters.c
*** radiusd//filters.c
--- ascendd//filters.c	Wed Dec 20 09:39:04 1995
***************
*** 0 ****
--- 1,841 ----
+ /*
+  * ASCEND: @(#)filters.c	1.3 (95/07/25 00:55:30)
+  *
+  *      Copyright (c) 1994 Ascend Communications, Inc.
+  *      All rights reserved.
+  *
+  *	Permission to copy all or part of this material for any purpose is
+  *	granted provided that the above copyright notice and this paragraph
+  *	are duplicated in all copies.  THIS SOFTWARE IS PROVIDED ``AS IS''
+  *	AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+  *	LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+  *	FOR A PARTICULAR PURPOSE.
+  */
+ 
+ #if defined( BINARY_FILTERS )
+ 
+ #include <sys/types.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <ctype.h>
+ #include <errno.h>
+ #include <netinet/in.h>
+ #include <stdlib.h>
+ #include <sys/time.h>	/* gettimeofday() */
+ 
+ #include "radius.h"
+ #include "protos.h"
+ 
+ VALUE_PAIR*	prevRadPair = 0;
+ 
+ #undef DEBUG
+ #if defined( DEBUG )
+ #define PRINTF(x)	printf x
+ #else
+ #define PRINTF( x )
+ #endif
+ 
+ #define NO_TOKEN -1
+ 
+ typedef struct {
+     char*	name;
+     int 	value;
+ } KeywordStruct;
+ 
+     /*
+      * FilterPortType:
+      *
+      * Ascii names of some well known tcp/udp services.
+      * Used for filtering on a port type.
+      *
+      */
+ 
+ static KeywordStruct _filterPortType[] = {
+     { "ftp-data", 20 },
+     { "ftp", 21 },
+     { "telnet", 23 },
+     { "smtp", 25 },
+     { "nameserver", 42 },
+     { "domain", 53 },
+     { "tftp", 69 },
+     { "gopher", 70 },
+     { "finger", 79 },
+     { "www", 80 },
+     { "kerberos", 88 },
+     { "hostname", 101 },
+     { "nntp", 119 },
+     { "ntp", 123 },
+     { "exec", 512 },
+     { "login", 513 },
+     { "cmd", 514 },
+     { "talk", 517 },
+     {  NULL , NO_TOKEN },
+ };
+ 
+ typedef enum {
+     FILTER_IP_TYPE,
+     FILTER_GENERIC_TYPE,
+     FILTER_IN,
+     FILTER_OUT,
+     FILTER_FORWARD,
+     FILTER_DROP,
+     FILTER_GENERIC_OFFSET,
+     FILTER_GENERIC_MASK,
+     FILTER_GENERIC_VALUE,
+     FILTER_GENERIC_COMPNEQ,
+     FILTER_GENERIC_COMPEQ,
+     FILTER_MORE,
+     FILTER_IP_DST,
+     FILTER_IP_SRC,
+     FILTER_IP_PROTO,
+     FILTER_IP_DST_PORT,
+     FILTER_IP_SRC_PORT,
+     FILTER_EST
+ } FilterTokens;
+ 
+ 
+ static KeywordStruct _filterKeywords[] = {
+     { "ip", 	FILTER_IP_TYPE },
+     { "generic",FILTER_GENERIC_TYPE },
+     { "in", 	FILTER_IN },
+     { "out",	FILTER_OUT },
+     { "forward",FILTER_FORWARD },
+     { "drop",	FILTER_DROP },
+     { "dstip",  FILTER_IP_DST },
+     { "srcip",  FILTER_IP_SRC },
+     { "dstport",FILTER_IP_DST_PORT },
+     { "srcport",FILTER_IP_SRC_PORT },
+     { "est",	FILTER_EST },
+     { "more",	FILTER_MORE },
+     { "!=",	FILTER_GENERIC_COMPNEQ },
+     { "==",	FILTER_GENERIC_COMPEQ  },
+     {  NULL , NO_TOKEN },
+ };
+ 
+ #define FILTER_DIRECTION 	0
+ #define FILTER_DISPOSITION	1
+ #define IP_FILTER_COMPLETE  	0x3	/* bits shifted by FILTER_DIRECTION */
+ 					/* FILTER_DISPOSITION */
+ #define GENERIC_FILTER_COMPLETE 0x1c3	/* bits shifted for FILTER_DIRECTION */
+ 					/* FILTER_DISPOSITION, FILTER_GENERIC_OFFSET*/
+ 					/* FILTER_GENERIC_MASK, FILTER_GENERIC_VALUE*/
+ 
+     /*
+      * FilterProtoName:
+      *
+      * Ascii name of protocols used for filtering.
+      *
+      */
+ static KeywordStruct _filterProtoName[] = {
+     { "tcp",  6 },
+     { "udp",  17 },
+     { "ospf", 89 },
+     { "icmp", 1 },
+     {  NULL , NO_TOKEN },
+ };
+ 
+ static KeywordStruct _filterCompare[] = {
+     { ">", RAD_COMPARE_GREATER },
+     { "=", RAD_COMPARE_EQUAL },
+     { "<", RAD_COMPARE_LESS },
+     { "!=", RAD_COMPARE_NOT_EQUAL },
+     {  NULL , NO_TOKEN },
+ };
+ 
+ static char	_errMsg[512];
+ static char	_curString[512];
+ 
+ int _findKey P__(( char *string, KeywordStruct *list ));
+ static int _isAllDigit P__(( char *token ));
+ 
+     /*
+      * _findKey:
+      *
+      * Given a table of keywords, it will try and match string to an
+      * entry. If it does it returns that keyword value. if no NO_TOKEN is
+      * returned. A sanity check is made for upper case characters.
+      *
+      *	string:			Pointer to the token to match.
+      *
+      *	list:			Point to the list of keywords.
+      *
+      *	returns:		Keyword value on a match or NO_TOKEN.
+      */
+ int 
+ _findKey(string, list)
+ char		*string;
+ KeywordStruct	*list;
+ {
+     short 	len;
+     KeywordStruct*  entry;
+     char	buf[80], *ptr;
+ 
+     len = strlen( (char *) string );
+     for( ptr = buf ; len; len--, string++ ) {
+ 	if( isupper( *string ) ) {
+ 	    *ptr++ = tolower( *string );
+ 	} else {
+ 	    *ptr++ = *string;
+ 	}
+     }
+     *ptr = 0;
+     entry = list;
+     while( entry->name ) {
+    	if( strcmp( (char*) entry->name, (char*) buf ) == 0 ) {
+ 	    break;
+ 	}
+ 	entry++;
+     }
+     return( entry->value );
+ }
+ 
+     /*
+      * _isAllDigit:
+      *
+      * Routine checks a string to make sure all values are digits.
+      *
+      *	token:			Pointer to sting to check.
+      *
+      * 	returns:		TRUE if all digits, or FALSE.
+      *
+      */
+ 
+ static int
+ _isAllDigit(token)
+ char	*token;
+ {
+     int i;
+ 
+     i = strlen( (char *) token );
+     while( i-- ) {
+ 	if( isdigit( *token ) ) {
+ 	    token++;
+ 	} else {
+ 	    break;
+ 	}
+     }
+     if( i > 0 ) {
+ 	return( FALSE );
+     } 
+ 
+     return( TRUE );
+ }
+ 
+     /*
+      * _a2octet:
+      *
+      * Converts the ascii mask and value for generic filters into octets.
+      * It also does a sanity check to see if the string is greater than
+      * MAX_FILTER_LEN. It assumes the sting is hex with NO leading "0x"
+      *
+      *	tok:			Pointer to the string.
+      *
+      *  retBuf:			Pointer to place the octets.
+      *
+      *	returns:		Number of octects or -1 for error.
+      * 
+      */
+ static short
+ _a2octet(tok, retBuf)
+ char	*tok;
+ char	*retBuf;
+ {
+     short	rc, len, val, retLen, i;
+     char	buf[ RAD_MAX_FILTER_LEN *2 ];
+     char	*octet = buf;
+ 
+     rc = -1;
+     retLen = 0;
+ 
+     if( ( len = strlen( (char*) tok ) ) <= ( RAD_MAX_FILTER_LEN*2 ) ) {
+ 	retLen = len/2;
+ 	if( len % 2 ) {
+ 	    retLen++;
+ 	}
+ 	memset( buf, '\0', RAD_MAX_FILTER_LEN * 2 );
+ 	for( ; len; len-- ) {
+ 	    if( *tok <= '9' && *tok >= '0' ) {
+ 		val = '0';
+ 	        *octet++ = *tok++ - val;
+ 	    } else if( isxdigit( *tok ) ) {
+ 		if( *tok > 'Z' ) {
+ 		    val = 'a';
+ 		} else {
+ 		    val = 'A';
+ 		}
+ 	        *octet++ = ( *tok++ - val ) + 10;
+ 	    } else {
+ 		break;	
+ 	    }
+ 	}
+ 	if( !len ) {
+ 	    /* merge the values */
+ 	    for( i = 0; i < RAD_MAX_FILTER_LEN*2; i+=2 ) {
+ 		*retBuf++ = (buf[i] << 4) | buf[i+1];
+ 	    }
+ 	}
+     }
+ 
+     if( len ) {
+ 	rc = -1;
+     } else {
+ 	rc = retLen;
+     }
+     return( rc );
+ }
+ 
+ 
+ 
+     /*
+      * _defaultNetMask:
+      *
+      *	Given an ip address this routine calculate a default netmask.
+      *
+      *	address:		Ip address.
+      *
+      *	returns:		Number of bits for the netmask
+      *
+      */
+ static char
+ _defaultNetmask(address)
+ unsigned long	address;
+ {
+     char netmask;
+ 
+     if ( ! address ) {
+ 	netmask = 0;
+     } else if (( address & htonl( 0x80000000 ) ) == 0 ) {
+ 	netmask = 8;
+     } else if (( address & htonl( 0xc0000000 ) ) == htonl( 0x80000000 ) ) {
+ 	netmask = 16;
+     } else if (( address & htonl( 0xe0000000 ) ) == htonl( 0xc0000000 ) ) {
+ 	netmask = 24;
+     } else {
+ 	netmask = 32;
+     }
+     return netmask;
+ }
+ 
+ 		
+ static char ipAddressDigits[] = "1234567890./";
+     /*
+      * This functions attempts to convert an IP address in ASCII dot
+      * with an optional netmask part to a pair of IpAddress.  Note:
+      * An IpAddress is always stored in network byte order.
+      *
+      * Parameters:
+      *
+      *  string:		Pointer to a NULL terminated IP address in dot 
+      *			notation followed by an optional /nn to indicate
+      *			the number leading of bits in the netmask.
+      * 
+      *  ipAddress:	Pointer to an IpAddress where the converted
+      *			address will be stored.
+      *
+      *	netmask:	Pointer to an IpAddress where the netmask
+      *			will be stored.  If no netmask is passed as
+      *			as part of the address the default netmask will
+      *			be stored here.
+      *
+      * Returns:
+      *	<>		TRUE if valid conversion, FALSE otherwise.
+      *
+      *	*ipAddress:	If function returns TRUE, the IP address in NBO.
+      *	*netmask:	If function returns TRUE, the netmask in NBO.
+      */
+ 
+ static int
+ _ipAddressStringToValue(string, ipAddress, netmask)
+ char		*string;
+ unsigned long	*ipAddress;
+ char		*netmask;
+ {
+     u_char*	dst;
+     char*	cp;
+     int		numDots;
+     int		i;
+     long	value;
+ 
+     if ( ! string ) {
+     	return(FALSE);
+     }
+ 
+     /* Allow an IP address to be blanked instead of forcing entry of
+        0.0.0.0 -- the user will like it. */
+ 
+     if ( *string == 0 ) {
+ 	*ipAddress = 0;
+ 	*netmask = 0;
+ 	return TRUE;
+     }
+ 
+     /* First just count the number of dots in the address.  If there
+        are more or less than three the address is invalid. */
+ 
+     cp = string;
+     numDots = 0;
+     while( *cp ) {
+ 	if( !strchr( ipAddressDigits, *cp) ) {
+ 	    return( FALSE );
+ 	}
+ 	if ( *cp == '.') {
+ 	    ++numDots;
+ 	}
+ 	++cp;
+     }
+     if ( numDots != 3 ) {
+ 	return( FALSE );
+     }
+ 
+     dst = (u_char *) ipAddress;
+     cp = string;
+ 
+     for ( i = 0; i < sizeof( *ipAddress ); i++ ) {
+ 	value = strtol( cp, (char**) &cp, 10 );
+ 	if (( value < 0 ) || ( value > 255 )) {
+ 	    return( FALSE );
+ 	}
+ 	*dst++ = (u_char) value;
+ 	if ( *cp == '.' ) {
+ 	    cp += 1;
+ 	}
+     }
+ 
+     /* If there is a netmask part, parse it, otherwise figure out the
+        default netmask for this class of address. */
+ 
+     if ( *cp == '/' ) {
+ 	value = strtol( cp + 1, (char**) &cp, 10 );
+ 	if (( *cp != 0 ) || ( value < 0 ) || ( value > 32 )) {
+ 	    return FALSE;
+ 	}
+ 	*netmask = (char) value;
+     } else {
+ 	*netmask = _defaultNetmask( *ipAddress );
+     }
+     return TRUE;
+ }
+ 
+     /*
+      * _parseIpFilter:
+      *
+      * This routine parses an IP filter string from a RADIUS
+      * reply. The format of the string is:
+      *
+      *	ip dir action [ dstip n.n.n.n/nn ] [ srcip n.n.n.n/nn ]
+      *	    [ proto [ dstport cmp value ] [ srcport cmd value ] [ est ] ] 
+      *
+      * Fields in [...] are optional.
+      *	where:
+      *
+      *  ip:		Keyword to designate an IP filter. Actually this
+      *			has been determined by _parseFilter.
+      *
+      *	dir:		Filter direction. "IN" or "OUT"
+      *
+      *	action:		Filter action. "FORWARD" or "DROP"
+      *
+      *	dstip:		Keyword for destination IP address.
+      *			n.n.n.n = IP address. /nn - netmask. 
+      *			
+      *	srcip:		Keyword for source IP address.
+      *			n.n.n.n = IP address. /nn - netmask. 
+      *			
+      *	proto:		Optional protocol field. Either a name or
+      *			number. Known names are in FilterProtoName[].
+      *			
+      *	dstpost:	Keyword for destination port. Only valid with tcp
+      *			or udp. 'cmp' are in FilterPortType[]. 'value' can be
+      *			a name or number.
+      *
+      *	srcpost:	Keyword for source port. Only valid with tcp
+      *			or udp. 'cmp' are in FilterPortType[]. 'value' can be
+      *			a name or number.
+      *			
+      *	est:		Keyword for TCP established. Valid only for tcp.
+      *			
+      * expects:
+      *
+      *	curEntry:	Pointer to place the filter structure
+      *
+      *	returns:	-1 for error or 0 for OK
+      *	
+      */
+ 
+ static int 
+ _parseIpFilter(curEntry)
+ RadFilter	*curEntry;
+ {
+  
+     unsigned long	elements = 0l;
+     int			tok; 
+     char*		token;
+     RadIpFilter*	ip;
+ 
+     token = (char *) strtok( NULL, " " ); 
+ 
+     PRINTF((" in ip  filter \n")); 
+ 
+     memset( curEntry, '\0', sizeof( RadFilter ) );
+     curEntry->type = RAD_FILTER_IP; 
+     ip = &curEntry->u.ip;
+     ip->established = FALSE;
+  
+     while( token ) {
+ 	PRINTF((" token %s ", token ));
+   	tok = _findKey( token, _filterKeywords );
+ 	switch( tok ) {
+ 	    case FILTER_IN:
+ 	    case FILTER_OUT:
+ 		curEntry->indirection = tok == FILTER_IN ? TRUE: FALSE;
+ 		PRINTF((" got %s ", tok == FILTER_IN?"FILTER_IN":"FILTER_OUT"));
+ 	        elements |= (1 << FILTER_DIRECTION );
+ 		break;
+ 	    case FILTER_FORWARD:
+ 	    case FILTER_DROP:
+ 		PRINTF((" got %s ", tok == FILTER_DROP?
+ 			"FILTER_DROP":"FILTER_FORWARD"));
+ 	        elements |= (1 << FILTER_DISPOSITION );
+ 		if( tok == FILTER_FORWARD ) {
+ 		    curEntry->forward = TRUE;
+ 		} else {
+ 		    curEntry->forward = FALSE;
+ 		}
+ 		break;
+ 	    case FILTER_IP_DST:
+ 	    case FILTER_IP_SRC:
+ 		PRINTF((" got %s ", tok == FILTER_IP_DST?
+ 			"FILTER_IP_DST":"FILTER_IP_SRC"));
+ 		token = (char *) strtok( NULL, " " );
+ 		if ( token ) {
+ 		    if( tok == FILTER_IP_DST ) {
+ 			
+ 		        if( _ipAddressStringToValue( (char*)token, 
+ 				 &ip->dstip, (char *)&ip->dstmask ) ) {
+ 			    PRINTF((" ip %lx netmask %lx \n", ip->dstip, 
+ 				     ip->dstmask ));
+ 			    break;
+ 			}
+ 		    } else {
+ 		        if( _ipAddressStringToValue( (char *)token, 
+ 				&ip->srcip, (char *)&ip->srcmask ) ) {
+ 			    PRINTF((" ip %lx netmask %lx \n", ip->srcip,
+ 				     ip->srcmask ));
+ 			    break;
+ 			}
+ 		    }
+ 		} 
+ 
+ 		PRINTF(( "RADIF: IP Filter syntax error %s \n", token ));
+ 		sprintf( _errMsg, 
+ 		  	 "ip filter error: do not recognize %s in %s \n",
+ 			  token, _curString );
+ 		goto doneErr; 
+ 	    case FILTER_IP_DST_PORT:
+ 	    case FILTER_IP_SRC_PORT:
+ 	    {
+ 		RadFilterComparison cmp;
+ 		short		 port;
+ 
+ 		PRINTF((" got %s ", tok == FILTER_IP_DST_PORT?
+ 			"FILTER_IP_DST_PORT":"FILTER_IP_SRC_PORT"));
+ 		token = (char *) strtok( NULL, " " );
+ 		if ( token ) {
+   		    cmp = _findKey( token, _filterCompare );
+ 		    PRINTF((" cmp value = %d \n", cmp ));
+ 		    if( cmp != NO_TOKEN ) {
+ 			token = (char *) strtok( NULL, " " );
+ 			if ( token ) {
+ 			    if( _isAllDigit( token ) ) {
+ 				port = atoi( (char *) token );
+ 			    } else {
+   		    	        port = _findKey( token, _filterPortType );
+ 			    }
+ 			    if( port != (short) NO_TOKEN ) {
+ 		    	    	PRINTF((" port = %d \n", port ));
+ 				if( tok == FILTER_IP_DST_PORT ) {
+ 				    ip->dstPortComp = cmp;
+ 				    ip->dstport = htons( port );
+ 				} else {
+ 				    ip->srcPortComp = cmp;
+ 				    ip->srcport = htons( port );
+ 				}
+ 				break;
+ 			    }
+ 			}
+ 		    }
+ 		}
+ 		sprintf( _errMsg, 
+ 		  	 "ip filter error: do not recognize %s in %s \n",
+ 			  token, _curString );
+ 		PRINTF(( "RADIF: IP Filter syntax error %s \n", token ));
+ 		goto doneErr;
+ 		break;
+ 	    }
+ 	    case FILTER_EST:
+ 		PRINTF((" got est %s ", token ));
+ 		ip->established = TRUE;
+ 		break;
+ 	    default:
+ 		/* no keyword match but may match a protocol list */
+ 		if( _isAllDigit( token ) ) {
+ 		    tok = atoi( (char *) token );
+ 		} else {
+ 		    tok = _findKey( token, _filterProtoName );
+ 
+ 		    if( tok == NO_TOKEN ) {
+ 			PRINTF(( "RADIF: IP proto error %s \n", token ));
+ 			sprintf( _errMsg, 
+ 		  	     "ip filter error: do not recognize %s in %s \n",
+ 			     token, _curString );
+ 			goto doneErr;
+ 		    }
+ 		}
+ 		ip->proto = tok;
+ 		PRINTF(("ip proto cmd = %d ", tok));
+ 	}
+         token = (char *) strtok( NULL, " " ); 
+     } 
+ 
+     if( elements == IP_FILTER_COMPLETE ) {
+ 	return( 0 );
+     }
+ 
+ doneErr:
+     PRINTF((" done err \n"));
+     log_err( _errMsg );
+     return( -1 );
+ }
+ 
+     /*
+      * _parseGenericFilter:
+      *
+      * This routine parses a Generic filter string from a RADIUS
+      * reply. The format of the string is:
+      *
+      *	GENERIC dir action offset mask value [== or != ] [more]
+      *
+      * Fields in [...] are optional.
+      *	where:
+      *
+      * 	generic:	Keyword to indicate a generic filter. This
+      *			has been determined by _parseFilter.
+      *
+      *	dir:		Filter direction. "IN" or "OUT"
+      *
+      *	action:		Filter action. "FORWARD" or "DROP"
+      *
+      *	offset:		A Number. Specifies an offset into a frame 
+      *			to start comparing.
+      *			
+      *	mask:		A hexadecimal mask of bits to compare.
+      *			
+      *	value:		A value to compare with the masked data.
+      *
+      *	compNeq:	Defines type of comparison. ( "==" or "!=")
+      *			Default is "==".
+      *			
+      *	more:		Optional keyword MORE, to represent the attachment
+      *			to the next entry.
+      *
+      * expects:
+      *
+      *	curEntry:	Pointer to place the filter structure
+      *
+      *	returns:	-1 for error or 0 for OK
+      *	
+      */
+ 
+ static int
+ _parseGenericFilter(curEntry)
+ RadFilter	*curEntry;
+ {
+     unsigned long	elements = 0l; 
+     int			tok; 
+     int			gstate = FILTER_GENERIC_OFFSET;
+     char*		token;
+     short		valLen, maskLen;
+     RadGenericFilter*	gen;
+ 
+     token = (char *) strtok( NULL, " " ); 
+ 
+     PRINTF((" in parse generic filter \n")); 
+ 
+     maskLen = 0;
+     memset( (char *)curEntry, '\0', sizeof( RadFilter ) );
+     curEntry->type = RAD_FILTER_GENERIC;
+     gen = &curEntry->u.generic;
+     gen->more = FALSE; 
+     gen->compNeq = FALSE;	
+ 
+     while( token ) {
+ 	PRINTF((" token %s ", token ));
+   	tok = _findKey( token, _filterKeywords );
+    	PRINTF(("tok %d ", tok));
+ 	switch( tok ) {
+ 	    case FILTER_IN:
+ 	    case FILTER_OUT:
+ 		curEntry->indirection = tok == FILTER_IN ? TRUE: FALSE;
+ 	        elements |= (1 << FILTER_DIRECTION );
+ 		PRINTF((" got %s ", tok == FILTER_IN?"FILTER_IN":"FILTER_OUT"));
+ 		break;
+ 	    case FILTER_FORWARD:
+ 	    case FILTER_DROP:
+ 	        elements |= (1 << FILTER_DISPOSITION );
+ 		PRINTF((" got %s ", tok == FILTER_DROP?
+ 			"FILTER_DROP":"FILTER_FORWARD"));
+ 		if( tok == FILTER_FORWARD ) {
+ 		    curEntry->forward = TRUE;
+ 		} else {
+ 		    curEntry->forward = FALSE;
+ 		}
+ 		break;
+ 	    case FILTER_GENERIC_COMPNEQ:
+ 		gen->compNeq = TRUE;
+ 		PRINTF((" got compare %s ", token));
+ 		break;
+ 	    case FILTER_GENERIC_COMPEQ:
+ 		gen->compNeq = FALSE;
+ 		PRINTF((" got compare %s ", token));
+ 		break;
+ 	    case FILTER_MORE:
+ 		gen->more = htons( TRUE );
+ 		PRINTF((" got more %s ", token ));
+ 		break;
+ 	    default:
+ 	        elements |= ( 1 << gstate );
+ 		switch( gstate ) {
+ 		    case FILTER_GENERIC_OFFSET:
+ 			gstate = FILTER_GENERIC_MASK;
+ 			gen->offset = htons( atoi( (char *) token ) );
+ 			break;
+ 		    case FILTER_GENERIC_MASK:
+ 			gstate = FILTER_GENERIC_VALUE;
+ 			maskLen = _a2octet( token, (char *)gen->mask );
+ 			if( maskLen == (short) -1 ) {
+ 			    sprintf( _errMsg, 
+ 		  		     "filter mask error: %s \n", _curString );
+ 			    goto doneErr;
+ 			}
+ #ifdef DEBUG
+ 			PRINTF((" octet retlen = %d ", maskLen ));
+ 			for( tok = 0; tok < maskLen; tok++) {
+         		    PRINTF(("%2x", gen->mask[tok]));
+ 		        }
+ 			PRINTF(("\n"));
+ #endif
+ 
+ 			break;
+ 		    case FILTER_GENERIC_VALUE:
+ 			gstate ++;
+ 			valLen = _a2octet( token, (char *)gen->value );
+ 			if( valLen != maskLen ) {
+ 			    sprintf( _errMsg, 
+     "filter value size is not the same size as the filter mask: %s \n", 
+ 				     _curString );
+ 			    goto doneErr;
+ 			}
+ 			gen->len = htons( valLen );
+ #ifdef DEBUG
+ 			PRINTF((" octet retlen = %d ", maskLen ));
+ 			for( tok = 0; tok < maskLen; tok++) {
+         		    PRINTF(("%2x", gen->value[tok]));
+ 		        }
+ 			PRINTF(("\n"));
+ #endif
+ 
+ 			break;
+ 		    default:
+ 			sprintf( _errMsg, "filter: do not know %s in %s \n",
+ 				 token, _curString );
+ 			PRINTF(( "RADIF: Filter syntax error %s \n", token ));
+ 		       goto doneErr;    
+ 		}
+ 	}
+         token = (char *) strtok( NULL, " " ); 
+     }
+ 
+     if( elements == GENERIC_FILTER_COMPLETE ) {
+ 	return( 0 );
+     }
+ 
+ doneErr:
+     PRINTF((" done err \n"));
+     log_err( _errMsg );
+     return( -1 );
+ }
+ 		       
+     /*
+      * filterBinary:
+      *
+      * This routine will call routines to parse entries from an ASCII format
+      * to a binary format recognized by the Ascend boxes.
+      *
+      *	pair:			Pointer to value_pair to place return.
+      *
+      *	valstr:			The string to parse	
+      *
+      *	return:			-1 for error or 0.
+      */
+ int 
+ filterBinary(pair, valstr)
+ VALUE_PAIR	*pair;
+ char		*valstr;
+ {
+ 
+     char*		token;
+     unsigned long	tok;
+     int			rc;
+     RadFilter		radFil, *filt;
+     RadGenericFilter*	gen;
+ 
+     rc = -1;
+     strcpy( _curString, valstr );
+ 
+     token = (char *) strtok( (char *)valstr, " " );
+     tok = _findKey( token, _filterKeywords );
+     pair->lvalue = sizeof( RadFilter );
+     switch( tok ) {
+       case FILTER_IP_TYPE:
+ 	rc = _parseIpFilter( &radFil );
+ 	break;
+       case FILTER_GENERIC_TYPE:
+ 	rc = _parseGenericFilter( &radFil );
+ 	break;
+     }
+ 
+     /*
+      * if more is set then this new entry must exist, be a 
+      * FILTER_GENERIC_TYPE, direction and disposition must match for 
+      * the previous more to be valid. If any should fail then TURN OFF 
+      * previos more
+      */
+     if( prevRadPair ) {
+ 	filt = ( RadFilter * )prevRadPair->strvalue;
+ 	if(( tok != FILTER_GENERIC_TYPE ) || (rc == -1 ) ||
+ 	   ( prevRadPair->attribute != pair->attribute ) || 
+ 	   ( filt->indirection != radFil.indirection ) || 
+ 	   ( filt->forward != radFil.forward ) ) {
+ 	    gen = &filt->u.generic;
+ 	    gen->more = FALSE;
+ 	    sprintf( _errMsg,
+ 	       "filterBinary:  'more' for previous entry doesn't match: %s.\n",
+ 		     _curString );
+ 	    log_err( _errMsg );
+ 	}
+     }
+     prevRadPair = NULL;
+     if( rc != -1 && tok == FILTER_GENERIC_TYPE ) {
+ 	if( radFil.u.generic.more ) {
+ 	    prevRadPair = pair;
+ 	} 
+     }
+ 
+     if( rc != -1 ) {
+ 	memcpy( pair->strvalue, (char *) &radFil, pair->lvalue );
+     }
+     return(rc);
+ }
+ 
+ #endif /* BINARY_FILTERS */
+ 
diff -c -N radiusd//md5.c ascendd//md5.c
*** radiusd//md5.c	Tue Dec 27 09:32:29 1994
--- ascendd//md5.c	Wed Dec 20 09:39:04 1995
***************
*** 1,6 ****
--- 1,10 ----
  /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
   */
  
+ /*
+  * ASCEND: @(#)md5.c	1.2 (95/07/25 00:55:46)
+  */
+ 
  /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
  rights reserved.
  
***************
*** 93,102 ****
   (a) += (b); \
    }
  
  md5_calc(output, input, inlen)
! unsigned char *output;
! unsigned char *input;                                /* input block */
! unsigned int inlen;                     /* length of input block */
  {
  	MD5_CTX	context;
  
--- 97,107 ----
   (a) += (b); \
    }
  
+ void
  md5_calc(output, input, inlen)
! 	unsigned char	*output;	/* output block */
! 	unsigned char	*input;		/* input block */
! 	unsigned int	inlen;		/* length of input block */
  {
  	MD5_CTX	context;
  
***************
*** 107,114 ****
  
  /* MD5 initialization. Begins an MD5 operation, writing a new context.
   */
! void MD5Init (context)
! MD5_CTX *context;                                        /* context */
  {
    context->count[0] = context->count[1] = 0;
    /* Load magic initialization constants.
--- 112,120 ----
  
  /* MD5 initialization. Begins an MD5 operation, writing a new context.
   */
! void 
! MD5Init (context)
! 	MD5_CTX	*context;		/* context */
  {
    context->count[0] = context->count[1] = 0;
    /* Load magic initialization constants.
***************
*** 123,132 ****
    operation, processing another message block, and updating the
    context.
   */
! void MD5Update (context, input, inputLen)
! MD5_CTX *context;                                        /* context */
! unsigned char *input;                                /* input block */
! unsigned int inputLen;                     /* length of input block */
  {
    unsigned int i, index, partLen;
  
--- 129,139 ----
    operation, processing another message block, and updating the
    context.
   */
! void 
! MD5Update (context, input, inputLen)
! 	MD5_CTX		*context;	/* context */
! 	unsigned char	*input;		/* input block */
! 	unsigned int	inputLen;	/* length of input block */
  {
    unsigned int i, index, partLen;
  
***************
*** 141,148 ****
  
    partLen = 64 - index;
  
!   /* Transform as many times as possible.
! */
    if (inputLen >= partLen) {
   MD5_memcpy
     ((POINTER)&context->buffer[index], (POINTER)input, partLen);
--- 148,154 ----
  
    partLen = 64 - index;
  
!   /* Transform as many times as possible. */
    if (inputLen >= partLen) {
   MD5_memcpy
     ((POINTER)&context->buffer[index], (POINTER)input, partLen);
***************
*** 165,173 ****
  /* MD5 finalization. Ends an MD5 message-digest operation, writing the
    the message digest and zeroizing the context.
   */
! void MD5Final (digest, context)
! unsigned char digest[16];                         /* message digest */
! MD5_CTX *context;                                       /* context */
  {
    unsigned char bits[8];
    unsigned int index, padLen;
--- 171,180 ----
  /* MD5 finalization. Ends an MD5 message-digest operation, writing the
    the message digest and zeroizing the context.
   */
! void 
! MD5Final (digest, context)
! 	unsigned char	digest[16];	/* message digest */
! 	MD5_CTX		*context;	/* context */
  {
    unsigned char bits[8];
    unsigned int index, padLen;
***************
*** 194,202 ****
  
  /* MD5 basic transformation. Transforms state based on block.
   */
! static void MD5Transform (state, block)
! UINT4 state[4];
! unsigned char block[64];
  {
    UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
  
--- 201,210 ----
  
  /* MD5 basic transformation. Transforms state based on block.
   */
! static void 
! MD5Transform (state, block)
! 	UINT4		state[4];
! 	unsigned char	block[64];
  {
    UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
  
***************
*** 287,296 ****
  /* Encodes input (UINT4) into output (unsigned char). Assumes len is
    a multiple of 4.
   */
! static void Encode (output, input, len)
! unsigned char *output;
! UINT4 *input;
! unsigned int len;
  {
    unsigned int i, j;
  
--- 295,305 ----
  /* Encodes input (UINT4) into output (unsigned char). Assumes len is
    a multiple of 4.
   */
! static void 
! Encode (output, input, len)
! 	unsigned char	*output;
! 	UINT4		*input;
! 	unsigned int	len;
  {
    unsigned int i, j;
  
***************
*** 305,314 ****
  /* Decodes input (unsigned char) into output (UINT4). Assumes len is
    a multiple of 4.
   */
! static void Decode (output, input, len)
! UINT4 *output;
! unsigned char *input;
! unsigned int len;
  {
    unsigned int i, j;
  
--- 314,324 ----
  /* Decodes input (unsigned char) into output (UINT4). Assumes len is
    a multiple of 4.
   */
! static void 
! Decode (output, input, len)
! 	UINT4		*output;
! 	unsigned char	*input;
! 	unsigned int	len;
  {
    unsigned int i, j;
  
***************
*** 320,345 ****
  /* Note: Replace "for loop" with standard memcpy if possible.
   */
  
! static void MD5_memcpy (output, input, len)
! POINTER output;
! POINTER input;
! unsigned int len;
  {
    unsigned int i;
  
    for (i = 0; i < len; i++)
!  output[i] = input[i];
  }
  
  /* Note: Replace "for loop" with standard memset if possible.
   */
! static void MD5_memset (output, value, len)
! POINTER output;
! int value;
! unsigned int len;
  {
    unsigned int i;
  
    for (i = 0; i < len; i++)
!  ((char *)output)[i] = (char)value;
  }
--- 330,365 ----
  /* Note: Replace "for loop" with standard memcpy if possible.
   */
  
! static void 
! MD5_memcpy ( output, input, len)
! 	POINTER		output;
! 	POINTER		input;
! 	unsigned int	len;
  {
    unsigned int i;
  
+ #if( 1 )
    for (i = 0; i < len; i++)
! 	output[i] = input[i];
! #else
! 	memmove(output, input, len);
! #endif
  }
  
  /* Note: Replace "for loop" with standard memset if possible.
   */
! static void 
! MD5_memset (output, value, len)
! 	POINTER		output;
! 	int		value;
! 	unsigned int	len;
  {
    unsigned int i;
  
+ #if( 1 )
    for (i = 0; i < len; i++)
! 	((char *)output)[i] = (char)value;
! #else
! 	memset(output, value, len);
! #endif
  }
diff -c -N radiusd//md5.h ascendd//md5.h
*** radiusd//md5.h	Tue Dec 27 09:32:29 1994
--- ascendd//md5.h	Wed Dec 20 09:39:08 1995
***************
*** 1,13 ****
  /* GLOBAL.H - RSAREF types and constants
   */
  
  /* PROTOTYPES should be set to one if and only if the compiler supports
    function argument prototyping.
    The following makes PROTOTYPES default to 0 if it has not already
!   been defined with C compiler flags.
   */
! #ifndef PROTOTYPES
! #define PROTOTYPES 0
  #endif
  
  /* POINTER defines a generic pointer type */
--- 1,21 ----
  /* GLOBAL.H - RSAREF types and constants
   */
  
+ /*
+  * ASCEND: @(#)md5.h	1.2 (95/07/25 00:55:48)
+  */
+ 
  /* PROTOTYPES should be set to one if and only if the compiler supports
    function argument prototyping.
    The following makes PROTOTYPES default to 0 if it has not already
!   been defined explictly or with C compiler flags.
   */
! #if !defined(PROTOTYPES)
! #	if defined(__STDC__) && (__STDC__ == 1)
! #		define PROTOTYPES 1
! #	else
! #		define PROTOTYPES 0
! #	endif
  #endif
  
  /* POINTER defines a generic pointer type */
***************
*** 18,26 ****
  
  /* UINT4 defines a four byte word */
  #if defined(__alpha) && defined(__osf__)
! typedef unsigned int UINT4;
  #else
! typedef unsigned long int UINT4;
  #endif
  
  /* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
--- 26,34 ----
  
  /* UINT4 defines a four byte word */
  #if defined(__alpha) && defined(__osf__)
! 	typedef unsigned int UINT4;
  #else
! 	typedef unsigned long int UINT4;
  #endif
  
  /* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
***************
*** 28,36 ****
    returns an empty list.
   */
  #if PROTOTYPES
! #define PROTO_LIST(list) list
  #else
! #define PROTO_LIST(list) ()
  #endif
  
  /* MD5.H - header file for MD5C.C
--- 36,44 ----
    returns an empty list.
   */
  #if PROTOTYPES
! #	define PROTO_LIST(list) list
  #else
! #	define PROTO_LIST(list) ()
  #endif
  
  /* MD5.H - header file for MD5C.C
diff -c -N radiusd//protos.h ascendd//protos.h
*** radiusd//protos.h
--- ascendd//protos.h	Wed Dec 20 09:42:00 1995
***************
*** 0 ****
--- 1,89 ----
+ /*
+  * ASCEND: @(#)protos.h	1.3 (95/07/25 00:55:32)
+  *
+  *      Copyright (c) 1995 Ascend Communications, Inc.
+  *      All rights reserved.
+  *
+  *	Permission to copy all or part of this material for any purpose is
+  *	granted provided that the above copyright notice and this paragraph
+  *	are duplicated in all copies.  THIS SOFTWARE IS PROVIDED ``AS IS''
+  *	AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+  *	LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+  *	FOR A PARTICULAR PURPOSE.
+  */
+ 
+ #if defined(__STDC__) && (__STDC__ == 1)
+ #	define	P__(s)	s
+ #	define	CONST	const
+ #else
+ #	define	P__(s)	(/* s */)
+ #	define	CONST	/* const */
+ #endif
+ 
+ 	/* function prototypes */
+ #if defined(SOLARIS)
+ 	extern int getopt P__((int, char *CONST *, CONST char *));
+ 	extern int gettimeofday P__((struct timeval *tp));
+ #else
+ 	extern int gettimeofday P__((struct timeval *tp, struct timezone *tzp));
+ #endif
+ extern void radversion P__((void));
+ extern char *get_errmsg P__((int errcode));
+ extern AUTH_REQ *authenticateAcctReq P__((AUTH_REQ *authreq, AUTH_HDR *auth));
+ #if(0)	/* parameter promotion due to old-style function definition */
+ extern AUTH_REQ *radrecv P__((UINT4 host, u_short udp_port, u_char *buffer, int length, char *isAcctPkt));
+ #else
+ extern AUTH_REQ *radrecv P__((UINT4 host, int udp_port, u_char *buffer, int length, char *isAcctPkt));
+ #endif
+ extern DICT_ATTR *dict_attrfind P__((char *attrname));
+ extern DICT_ATTR *dict_attrget P__((int attribute));
+ extern DICT_VALUE *dict_valfind P__((char *valname));
+ extern DICT_VALUE *dict_valget P__((UINT4 value, char *attrname));
+ extern UINT4 get_ipaddr P__((char *host));
+ extern UINT4 ipstr2long P__((char *ip_str));
+ extern char *ip_hostname P__((UINT4 ipaddr));
+ extern int get_client_info P__((UINT4 rqstIpAddr, UINT4 *ipaddr, u_char *secret, char *hostnm));
+ extern int calc_digest P__((u_char *digest, AUTH_REQ *authreq));
+ extern int config_init P__((void));
+ extern int dict_init P__((void));
+ extern int filterBinary P__((VALUE_PAIR *pair, char *valstr));
+ extern int good_ipaddr P__((char *addr));
+ extern int kill P__((pid_t pid, int sig));
+ extern int log_err P__((char *msg));
+ extern int pw_expired P__((UINT4 exptime, UINT4 usr_exp_days, UINT4 usr_warn_days));
+ extern int rad_spawn_child P__((AUTH_REQ *authreq, int activefd));
+ #if(0)	/* parameter promotion due to old-style function definition */
+ extern int radrespond P__((AUTH_REQ *authreq, int activefd, char isAcctPkt));
+ #else
+ extern int radrespond P__((AUTH_REQ *authreq, int activefd, int isAcctPkt));
+ #endif
+ extern int set_expiration P__((VALUE_PAIR *user_check, UINT4 expiration));
+ extern int unix_pass P__((char *name, char *passwd));
+ extern int user_find P__((char *name, VALUE_PAIR **check_pairs, VALUE_PAIR **reply_pairs));
+ extern int user_update P__((char *name, VALUE_PAIR *user_check, VALUE_PAIR *user_reply));
+ extern void debug_pair P__((FILE *fd, VALUE_PAIR *pair));
+ extern void fprint_attr_val P__((FILE *fd, VALUE_PAIR *pair));
+ extern void ipaddr2str P__((char *buffer, UINT4 ipaddr));
+ extern void md5_calc P__((unsigned char *output, unsigned char *input, unsigned int inlen));
+ extern void pairfree P__((VALUE_PAIR *pair));
+ extern void rad_accounting P__((AUTH_REQ *authreq, int activefd));
+ extern void rad_authenticate P__((AUTH_REQ *authreq, int activefd));
+ extern void rad_passchange P__((AUTH_REQ *authreq, int activefd));
+ extern void send_accept P__((AUTH_REQ *authreq, VALUE_PAIR *reply, char *msg, int activefd));
+ extern void send_accounting_response P__((AUTH_REQ *authreq, int activefd, char *msg));
+ extern PasswordType getPasswordType P__((char *pwd));
+ extern UINT4 get_attr_lvalue P__((VALUE_PAIR *list, int attribute));
+ extern char *get_attr_strvalue P__((VALUE_PAIR *list, int attribute));
+ extern void send_acct_reply P__((AUTH_REQ *authreq, VALUE_PAIR *reply, char *msg, int activefd));
+ extern void send_challenge P__((AUTH_REQ *authreq, char *msg, int msgLen, char *state, int stateLen, int activefd));
+ extern void send_newpin P__((AUTH_REQ *authreq, char *state, int stateLen, int activefd));
+ extern void send_nextcode P__((AUTH_REQ *authreq, char *msg, int msgLen, char *state, int stateLen, int activefd));
+ extern void send_pwack P__((AUTH_REQ *authreq, int activefd));
+ extern void send_pwexpired P__((AUTH_REQ *authreq, char *msg, int activefd));
+ extern void make_secret P__((u_char *digest, u_char *vector, u_char *secret, char *value));
+ extern void send_reject P__((AUTH_REQ *authreq, char *msg, int activefd));
+ extern void sig_cleanup P__((int sig));
+ extern void sig_fatal P__((int sig));
+ extern void sig_hup P__((int sig));
+ extern int user_read P__((FILE **userfd, char *name, char *content));
+ extern void warn P__((char *msg));
diff -c -N radiusd//radius.h ascendd//radius.h
*** radiusd//radius.h	Tue Dec 27 09:32:29 1994
--- ascendd//radius.h	Wed Dec 20 09:39:08 1995
***************
*** 3,9 ****
--- 3,11 ----
   *	RADIUS
   *	Remote Authentication Dial In User Service
   *
+  * ASCEND: @(#)radius.h	1.3 (95/07/25 00:55:33)
   *
+  *
   *	Livingston Enterprises, Inc.
   *	6920 Koll Center Parkway
   *	Pleasanton, CA   94566
***************
*** 32,39 ****
  #include "conf.h"
  
  #define AUTH_VECTOR_LEN		16
! #define AUTH_PASS_LEN		16
  #define AUTH_STRING_LEN		128	/* maximum of 254 */
  
  
  typedef struct pw_auth_hdr {
--- 34,45 ----
  #include "conf.h"
  
  #define AUTH_VECTOR_LEN		16
! #define AUTH_PASS_LEN		254
! #ifdef ORIG
  #define AUTH_STRING_LEN		128	/* maximum of 254 */
+ #else
+ #define AUTH_STRING_LEN		254	/* need 256 ???? */ 
+ #endif
  
  
  typedef struct pw_auth_hdr {
***************
*** 44,49 ****
--- 50,62 ----
  	u_char		data[2];
  } AUTH_HDR;
  
+     /* types of passwords */
+ typedef enum PasswordType {
+ 	PWD_UNKNOWN	= 1,	/* not yet determined */
+ 	PWD_SPECIAL,		/* triggers for external authentication */
+ 	PWD_NORMAL		/* plain jane */
+ } PasswordType;
+ 
  #define AUTH_HDR_LEN			20
  #define CHAP_VALUE_LENGTH		16
  
***************
*** 54,61 ****
--- 67,78 ----
  #define PW_TYPE_INTEGER			1
  #define PW_TYPE_IPADDR			2
  #define PW_TYPE_DATE			3
+ #if defined( BINARY_FILTERS )
+ #define PW_TYPE_FILTER_BINARY           4
+ #endif /* BINARY_FILTERS */
  
  
+ 	/* Types */
  #define	PW_AUTHENTICATION_REQUEST	1
  #define	PW_AUTHENTICATION_ACK		2
  #define	PW_AUTHENTICATION_REJECT	3
***************
*** 62,73 ****
  #define	PW_ACCOUNTING_REQUEST		4
  #define	PW_ACCOUNTING_RESPONSE		5
  #define	PW_ACCOUNTING_STATUS		6
! #define PW_PASSWORD_REQUEST		7
! #define PW_PASSWORD_ACK			8
! #define PW_PASSWORD_REJECT		9
  #define	PW_ACCOUNTING_MESSAGE		10
  #define PW_ACCESS_CHALLENGE		11
  
  #define	PW_USER_NAME			1
  #define	PW_PASSWORD			2
  #define	PW_CHAP_PASSWORD		3
--- 79,96 ----
  #define	PW_ACCOUNTING_REQUEST		4
  #define	PW_ACCOUNTING_RESPONSE		5
  #define	PW_ACCOUNTING_STATUS		6
! #define PW_PASSWORD_REQUEST		7	/* Livingston-specific code */
! #define PW_PASSWORD_ACK			8	/* Livingston-specific code */
! #define PW_PASSWORD_REJECT		9	/* Livingston-specific code */
  #define	PW_ACCOUNTING_MESSAGE		10
  #define PW_ACCESS_CHALLENGE		11
+ #define PW_NEXT_PASSCODE		29	/* Ascend-specific code */
+ #define PW_NEW_PIN			30	/* Ascend-specific code */
+ #define PW_TERMINATE_SESSION		31	/* Ascend-specific code */
+ #define PW_PASSWORD_EXPIRED		32	/* Ascend-spcific code */
  
+ 
+ 	/* Attributes */
  #define	PW_USER_NAME			1
  #define	PW_PASSWORD			2
  #define	PW_CHAP_PASSWORD		3
***************
*** 88,94 ****
  #define PW_PORT_MESSAGE			18
  #define PW_DIALBACK_NO			19
  #define PW_DIALBACK_NAME		20
! #define PW_EXPIRATION			21
  #define PW_FRAMED_ROUTE			22
  #define PW_FRAMED_IPXNET		23
  #define PW_STATE			24
--- 111,117 ----
  #define PW_PORT_MESSAGE			18
  #define PW_DIALBACK_NO			19
  #define PW_DIALBACK_NAME		20
! #define ASCEND_PW_EXPIRATION		21	/* Officially Un-assigned */
  #define PW_FRAMED_ROUTE			22
  #define PW_FRAMED_IPXNET		23
  #define PW_STATE			24
***************
*** 101,106 ****
--- 124,142 ----
  #define PW_ACCT_AUTHENTIC		45
  #define PW_ACCT_SESSION_TIME		46
  
+ #define	ASCEND_TOKEN_IDLE		199
+ #define	ASCEND_TOKEN_IMMEDIATE		200	
+ 	/* 201 - 203 allocated but not used in this implementation */
+ #define ASCEND_REQUIRE_AUTH		201
+ #define ASCEND_NUMBER_SESSIONS		202
+ #define ASCEND_AUTHEN_ALIAS		203
+ #define ASCEND_TOKEN_EXPIRY		204	/* internal */
+ 	/* 205, 206 allocated but not used in this implementation */
+ #define ASCEND_MENU_SELECTOR		205
+ #define ASCEND_MENU_ITEM		206
+ #define	ASCEND_PW_WARNTIME		207
+ #define	ASCEND_PW_LIFETIME		208
+ 
  /*
   *	INTEGER TRANSLATIONS
   */
***************
*** 147,152 ****
--- 183,198 ----
  #define PW_STATUS_STOP			2
  #define PW_STATUS_ALIVE			3
  
+ /*	Token Immediate Values	*/
+ #define TOK_IMM_NO			0
+ #define TOK_IMM_YES			1
+ 
+ /*	Password Aging Attribute	*/
+ #define PW_EXPIRATION_NAME	"Ascend-PW-Expiration"	/* attribute name */
+ /*	Password Aging Value Names for Attribute Ascend-Expiration	*/
+ #define PW_LIFETIME		"Lifetime-In-Days"	/* value name */
+ #define PW_WARNTIME		"Days-Of-Warning"	/* value name */
+ 
  /* Default Database File Names */
  
  #define RADIUS_DIR		"/etc/raddb"
***************
*** 179,184 ****
--- 225,231 ----
  	int			attribute;
  	int			type;
  	UINT4			lvalue;
+ 	int			size;
  	char			strvalue[AUTH_STRING_LEN];
  	struct value_pair	*next;
  } VALUE_PAIR;
***************
*** 196,204 ****
  	struct auth_req		*next;		/* Next active request */
  } AUTH_REQ;
  
  #define DEBUG	if(debug_flag)printf
  
! #define SECONDS_PER_DAY		86400
  #define MAX_REQUEST_TIME	30
  #define CLEANUP_DELAY		5
  #define MAX_REQUESTS		100
--- 243,496 ----
  	struct auth_req		*next;		/* Next active request */
  } AUTH_REQ;
  
+     /*
+      * Struct to pass information around to password authentication
+      * subroutines
+      */
+ typedef struct AuthInfo {
+ 	int		fd;		/* file descriptor to use */
+ 	AUTH_REQ	*authreq;	/* original auth request */
+ 	UINT4		ipaddr;		/* from authreq, for convenience */
+ 	u_char		*vector;	/* ditto */
+ 	int		cacheAuth;	/* Boolean, cache hit */
+ 	VALUE_PAIR	*cutList;	/* list of cut attributes */
+ 	VALUE_PAIR	*authName;	/* PW_USER_NAME from req */
+ 	VALUE_PAIR	*authPwd;	/* PW_[CHAP]_PASSWORD from req */
+ 	VALUE_PAIR	*authState;	/* STATE from req */
+ 	VALUE_PAIR	*chkPwd;	/* PW_PASSWORD from 'users' */
+ 	VALUE_PAIR	*chkSecret;	/* ASCEND_RECEIVE_SECRET from 'users' */
+ 	VALUE_PAIR	*chkImmediate;	/* Boolean: true skips challenge */
+ 	VALUE_PAIR	*chkIdle;	/* idle timer value */
+ 	VALUE_PAIR	*tokExp;	/* ASCEND_TOKEN_EXPIRY from 'users' */
+ 	time_t		tokExpSecs;	/* Seconds till token expires */
+ 	char		*pw_digest;	/* as calculated */
+ 	char		*user_msg;	/* return message */
+ } AuthInfo;
+ 
  #define DEBUG	if(debug_flag)printf
  
! 	/*
! 	 *	try to regularize the error status handling
! 	 *
! 	 *	make *SURE* you update radiusd.c "db_errmsgs"
! 	 *	when you update this list!
! 	 */
! typedef enum DBASE_ERRS {
! 	FIRST_DBASE_ERROR	= -100,
! 	DEFAULT_PARSE_ERR	= -99,
! 	DICT_VALFIND_ERR	= -98,
! 	BINARY_FILTER_ERR	= -97,
! 	MISSING_EQUALS		= -96,
! 	DICT_ATTRFIND_ERR	= -95,
! 	REPLY_FIRST_IS_NULL	= -94,
! 	MISSING_NEWLINE		= -93,
! 	NO_USER_OR_DEFAULT_NAME	= -92,
! 	ZERO_LENGTH_NAME	= -91,
! 	NO_USER_FILE		= -90,
! 	NO_WHITESPACE		= -89,
! 	USERFILE_RENAME_FAILED	= -88,
! 	USERFILE_READ_ERR	= -87,
! 	USERFILE_WRITE_ERR	= -86,
! 	END_OF_USERS_LIST	= -85,
! 	MEMORY_ERR		= -84,
! 	DICTFILE_READ_ERR	= -83,
! 	DICTFILE_ATTRLINE_ERR	= -82,
! 	DICTFILE_ATTRNAME_ERR	= -81,
! 	DICTFILE_ATTRVALUE_ERR	= -80,
! 	DICTFILE_ATTRTYPE_ERR	= -79,
! 	DICTFILE_VALLINE_ERR	= -78,
! 	DICTFILE_VALATTR_ERR	= -77,
! 	DICTFILE_VALNAME_ERR	= -76,
! 	DICTFILE_VALVALUE_ERR	= -75,
! 	UNIX_GETPWNAME_ERR	= -74,
! 	UNIX_GETSHDWNAME_ERR	= -73,
! 	UNIX_BAD_PASSWORD	= -72,
! 	CLIENTFILE_READ_ERR	= -71,
! 	WRONG_NAS_ADDR		= -70,
! 	LOGFILE_APPEND_ERR	= -69,
! 	NULL_VALUEPAIR		= -68,
! 	PWD_EXPIRED		= -67,
! 	PIPE_CREATE_ERR		= -66,
! 	LAST_DBASE_ERROR
! } DBASE_ERRS;
! #define	NUM_DBASE_ERRORS	((LAST_DBASE_ERROR - FIRST_DBASE_ERROR) - 1)
! 
! 	/* associate strings with error codes */
! typedef struct DBASE_ERRMSG {
! 	DBASE_ERRS	ecode;
! 	char	*emsg;
! } DBASE_ERRMSG;
! 
! 
! #define SECONDS_PER_MINUTE	(60)
! #define SECONDS_PER_HOUR	(60 * SECONDS_PER_MINUTE)
! #define SECONDS_PER_DAY		(24 * SECONDS_PER_HOUR)
! 
! #if defined( BINARY_FILTERS )
! 
!     /*
!      * TRUE and FALSE in case they are needed
!      */
! #if ! defined( FALSE )
! # define FALSE			0
! # define TRUE			(! FALSE)
! #endif
! 
!     /*
!      * Two types of filters are supported, GENERIC and IP.  The identifiers
!      * are:
!      */
! #define RAD_FILTER_GENERIC	0
! #define RAD_FILTER_IP		1
! 
!     /*
!      * Generic filters mask and match up to RAD_MAX_FILTER_LEN bytes
!      * starting at some offset.  The length is:
!      */
! #define RAD_MAX_FILTER_LEN	6
! 
! 
!     /*
!      * RadFilterComparison:
!      *
!      * An enumerated values for the IP filter port comparisons.
!      */
! typedef enum {
!     RAD_NO_COMPARE,
!     RAD_COMPARE_LESS,
!     RAD_COMPARE_EQUAL,
!     RAD_COMPARE_GREATER,
!     RAD_COMPARE_NOT_EQUAL
! } RadFilterComparison;
! 
!     /*
!      * RadIpFilter:
!      *
!      * The binary format of an IP filter.  ALL fields are stored in
!      * network byte order.
!      *
!      *	srcip:		The source IP address.
!      *
!      *	dstip:		The destination IP address.
!      *
!      *	srcmask:	The number of leading one bits in the source address
!      *			mask.  Specifies the bits of interest.
!      *
!      *	dstmask:	The number of leading one bits in the destination
!      *			address mask. Specifies the bits of interest.
!      *
!      *	proto:		The IP protocol number
!      *
!      *	establised:	A boolean value.  TRUE when we care about the
!      *			established state of a TCP connection.  FALSE when
!      *			we dont care.
!      *
!      *	srcport:	TCP or UDP source port number.
!      *
!      *	dstport:	TCP or UDP destination port number.
!      *
!      *	srcPortCmp:	One of the values of the RadFilterComparison enumeration
!      *			specifying how to compare the srcport value.
!      *
!      *	dstPortCmp:	One of the values of the RadFilterComparison enumeration
!      *			specifying how to compare the dstport value.
!      *
!      *	fill:		Round things out to a dword boundary.
!      */
! typedef struct radip {
!     UINT4  		srcip;
!     UINT4  		dstip;
!     unsigned char 	srcmask;
!     unsigned char 	dstmask;
!     unsigned char	proto;
!     unsigned char	established;
!     unsigned short	srcport;
!     unsigned short	dstport;
!     unsigned char	srcPortComp;
!     unsigned char	dstPortComp;
!     unsigned char	fill[2];
! } RadIpFilter;
! 
!     /*
!      * RadGenericFilter:
!      *
!      * The binary format of a GENERIC filter.  ALL fields are stored in
!      * network byte order.
!      *
!      *	offset:		Number of bytes into packet to start comparison.
!      *
!      *	len:		Number of bytes to mask and compare.  May not
!      *			exceed RAD_MAX_FILTER_LEN.
!      *
!      *	more:		Boolean.  If non-zero the next filter entry is
!      *			also to be applied to a packet.
!      *
!      *	mask:		A bit mask specifying the bits to compare.
!      *
!      *	value:		A value to compare against the masked bits at
!      *			offset in a users packet.
!      *			
!      *	compNeq:	Defines type of comarison (Equal or Notequal)
!      *			default is Equal.
!      *
!      *	fill:		Round things out to a dword boundary
!      */
! typedef struct radgeneric {
!     unsigned short	offset;
!     unsigned short	len;
!     unsigned short	more;
!     unsigned char	mask[ RAD_MAX_FILTER_LEN ];
!     unsigned char	value[ RAD_MAX_FILTER_LEN ];
!     unsigned char	compNeq;
!     unsigned char	fill;
! } RadGenericFilter;
! 
!     /*
!      * RadFilter:
!      *
!      * A binary filter element.  Contains either a RadIpFilter or a
!      * RadGenericFilter.  All fields are stored in network byte order.
!      *
!      *	type:		Either RAD_FILTER_GENERIC or RAD_FILTER_IP.
!      *
!      *	forward:	TRUE if we should forward packets that match this
!      *			filter, FALSE if we should drop packets that match
!      *			this filter.
!      *
!      *	indirection:	TRUE if this is an input filter, FALSE if this is
!      *			an output filter.
!      *
!      *	fill:		Round things out to a dword boundary.
!      *
!      *	u:		A union of
!      *			ip:		An ip filter entry
!      *			generic:	A generic filter entry
!      */
! typedef struct filter {
!     unsigned char 	type;
!     unsigned char	forward;
!     unsigned char	indirection;
!     unsigned char	fill;
!     union {
! 	RadIpFilter   	 ip;
! 	RadGenericFilter generic;
!     } u;
! } RadFilter;
! 
! #endif /* BINARY_FILTERS */
! 
! #if defined( ASCEND_SECRET )
! 
!     /*
!      * The name/number of the string attribute that will be encoded
!      * in response packets.  The encoding is similar to the way PAP
!      * secrets are encoded in request packets.
!      */
! #define ASCEND_SEND_SECRET	214
! #define ASCEND_RECV_SECRET	215
! 
! #endif /* ASCEND_SECRET */
! 
  #define MAX_REQUEST_TIME	30
  #define CLEANUP_DELAY		5
  #define MAX_REQUESTS		100
diff -c -N radiusd//radiusd.c ascendd//radiusd.c
*** radiusd//radiusd.c	Fri Jan  6 13:58:16 1995
--- ascendd//radiusd.c	Wed Dec 20 11:01:52 1995
***************
*** 3,9 ****
--- 3,11 ----
   *	RADIUS
   *	Remote Authentication Dial In User Service
   *
+  * ASCEND: @(#)radiusd.c	1.4 (95/07/25 00:55:34)
   *
+  *
   *	Livingston Enterprises, Inc.
   *	6920 Koll Center Parkway
   *	Pleasanton, CA   94566
***************
*** 23,28 ****
--- 25,39 ----
   *	the suitability of this software for any purpose.  It is
   *	provided "as is" without express or implied warranty.
   *
+  *	Modified by Ascend Communications, Inc. to support authentication
+  *	via the Enigma Logic SafeWord library, version 4.0 (sync and async
+  *	modes but not semisync). No retries supported (CHALLENGE, PASS, or
+  *	FAIL are the only possible replies). Also, only dynamic passwords
+  *	are supported (no fixed passwords, etc).
+  *
+  *      Modified by Ascend Communications, Inc. to support authentication
+  *      via the Security Dynamics ACE library. Next_passcode is supported,
+  *	new_pin support is not complete.
   */
  
  /* don't look here for the version, run radiusd -v or look in version.c */
***************
*** 31,37 ****
  
  #include	<sys/types.h>
  #include	<sys/socket.h>
- #include	<sys/time.h>
  #include	<sys/file.h>
  #include	<netinet/in.h>
  
--- 42,47 ----
***************
*** 46,77 ****
  #include	<errno.h>
  #include	<sys/wait.h>
  
  #if !defined(NOSHADOW)
  #include	<shadow.h>
  #endif /* !NOSHADOW */
  
  #include	"radius.h"
  
! char		recv_buffer[4096];
! char		send_buffer[4096];
  char		*progname;
  int		sockfd;
  int		acctfd;
  int		debug_flag;
  int		spawn_flag;
  int		acct_pid;
  char		*radius_dir;
  char		*radacct_dir;
  UINT4		expiration_seconds;
  UINT4		warning_seconds;
  extern int	errno;
  static AUTH_REQ	*first_request;
  
! void		sig_fatal();
! void		sig_hup();
! void		sig_cleanup();
! void		rad_passchange();
  
  main(argc, argv)
  int	argc;
  char	**argv;
--- 56,269 ----
  #include	<errno.h>
  #include	<sys/wait.h>
  
+ #include	<sys/time.h>	/* gettimeofday() */
+ #include	<pwd.h>
+ #include	<memory.h>
+ #include	<string.h>
+ 
  #if !defined(NOSHADOW)
  #include	<shadow.h>
  #endif /* !NOSHADOW */
  
+ #include	"cache.h"
  #include	"radius.h"
+ #include	"protos.h"
+ 
+ #undef	PWD_DEBUG	/* undef to avoid clear-text password debug info */
+ 
+ #define UNIX_PWD	"UNIX"	/* Unix reserved password */
+ 
+     /* enumeration of results of authentication */
+ typedef enum authResults {
+ 	SAFEWORD_FAILED	= -100,
+ 	SAFEWORD_PASSED,
+ 	SAFEWORD_CHALLENGING,
+ 	ACE_FAILED,
+ 	ACE_PASSED,
+ 	ACE_CHALLENGING,
+ 	ACE_NEXT_PASSCODE,
+ 	ACE_NEW_PIN
+ } authResults;
+ 
+ #if !defined(sys5)
+ typedef unsigned long	ulong;
+ #endif
+ 
+ FILE	*errf;
+ 
+ 	/* associate strings with the error messages */
+ 	/* keep these in the same order as the typedefs in radius.h */
+ DBASE_ERRMSG db_errmsgs[NUM_DBASE_ERRORS] = {
+ 	{DEFAULT_PARSE_ERR,		"Default Parse Error"},
+ 	{DICT_VALFIND_ERR,		"Dict-Value Find Error"},
+ 	{BINARY_FILTER_ERR,		"Binary Filter Error"},
+ 	{MISSING_EQUALS,		"Missing Equals Sign"},
+ 	{DICT_ATTRFIND_ERR,		"Dict-Attribute Find Error"},
+ 	{REPLY_FIRST_IS_NULL,		"INTERNAL: No Valid Reply Attributes"},
+ 	{MISSING_NEWLINE,		"Missing Newline"},
+ 	{NO_USER_OR_DEFAULT_NAME,	"Neither User Nor Default Name"},
+ 	{ZERO_LENGTH_NAME,		"Zero Length Name"},
+ 	{NO_USER_FILE,			"Missing Radius Users File"},
+ 	{NO_WHITESPACE,			"Missing Whitespace After User Name"},
+ 	{USERFILE_RENAME_FAILED,	"Failed Renaming Users File"},
+ 	{USERFILE_READ_ERR,		"Failed Reading Users File"},
+ 	{USERFILE_WRITE_ERR,		"Failed Writing Users File"},
+ 	{END_OF_USERS_LIST,		"Reached End of Users File"},
+ 	{MEMORY_ERR,			"Out of Memory"},
+ 	{DICTFILE_READ_ERR,		"Failed Reading Dictionary File"},
+ 	{DICTFILE_ATTRLINE_ERR,		"Error on Dictionary Attribute Line"},
+ 	{DICTFILE_ATTRNAME_ERR,		"Dictionary Attribute Name Error"},
+ 	{DICTFILE_ATTRVALUE_ERR,	"Dictionary Attribute Name Error"},
+ 	{DICTFILE_ATTRTYPE_ERR,		"Dictionary Attribute Type Error"},
+ 	{DICTFILE_VALLINE_ERR,		"Error on Dictionary Value Line"},
+ 	{DICTFILE_VALATTR_ERR,		"Dictionary Value Attribute Error"},
+ 	{DICTFILE_VALNAME_ERR,		"Dictionary Value Name Error"},
+ 	{DICTFILE_VALVALUE_ERR,		"Dictionary Value Value Error"},
+ 	{UNIX_GETPWNAME_ERR,		"Unix Get Pwd Name Error"},
+ 	{UNIX_GETSHDWNAME_ERR,		"Unix Get Shadow Pwd Name Error"},
+ 	{UNIX_BAD_PASSWORD,		"Unix Bad Password"},
+ 	{CLIENTFILE_READ_ERR,		"Failed Reading Clients File"},
+ 	{WRONG_NAS_ADDR,		"Wrong NAS Address"},
+ 	{LOGFILE_APPEND_ERR,		"Failed Appending to Log File"},
+ 	{NULL_VALUEPAIR,		"INTERNAL: Null Value-Pair Parameter"},
+ 	{PWD_EXPIRED,			"Password Expired"},
+ 	{PIPE_CREATE_ERR,		"Pipe Creation Failed"}
+ };
+ 
+ /*------------------------------------------------------------*/
+ 
+ 	/* function prototypes */
+ extern int main P__((int argc, char **argv));
+ static void usage P__((void));
+ extern char *get_errmsg P__((int errcode));
+ #if defined(sys5) || defined(BSDI)
+ extern char *crypt P__((CONST char *, CONST char *));
+ #else
+ extern char *crypt P__((u_char *, u_char *));
+ #endif
+ /*------------------------------------------------------------*/
+ 
+ 
+ 
+ #if defined(SAFEWORD)
+ /*-------------- Safeword Interface Begin --------------*/
+ 
+ 	/* SafeWord interface files */
+ #include "custpb.h"	/* interface information */
+ #include "custfail.h"	/* failure codes */
+ 
+ 	/* forward function declarations */
+ extern void pbmain P__((struct pblk *));	/* invoke SafeWord */
+ extern void initpb P__((struct pblk *));	/* init SafeWord param blk */
+ extern void dbgPblk P__((struct pblk *pb));	/* show SafeWord param blk */
+ extern int safeword_chall P__((AuthInfo *authInfo, struct pblk *pb));
+ extern int safeword_eval P__((AuthInfo *authInfo, struct pblk *pb));
+ 		/* request authentication via SafeWord */
+ extern int safeword_pass P__((AuthInfo *authInfo, struct pblk *pb));
  
! 	/* useful definitions */
! #define EL_PWD	"SAFEWORD"	/* Enigma Logic's reserved password */
! 
! #define BEG_PB_1ST(pb)    (&(pb)->uport)
! #define END_PB_1ST(pb)    (&(pb)->msg1)
! 
! #define BEG_PB_2ND(pb)    (&(pb)->errcode)
! #define END_PB_2ND(pb)    (&(pb)->status + sizeof((pb)->status))
! 
! #define LEN_PB_1ST(pb)    ((ulong)END_PB_1ST((pb)) - (ulong)BEG_PB_1ST((pb)))
! #define LEN_PB_2ND(pb)    ((ulong)END_PB_2ND((pb)) - (ulong)BEG_PB_2ND((pb)))
! 
! #define LEN_PB_TOTAL(pb)  (LEN_PB_1ST(pb) + LEN_PB_2ND(pb))
! 
! /*-------------- Safeword Interface End --------------*/
! #endif
! 
! #if defined(ACE)
! /*-------------- Ace Interface Begin --------------*/
! #include "sdi_athd.h"
! #include "sdi_size.h"
! #include "sdi_type.h"
! #include "sdacmvls.h"
! #include "sdconf.h"
! 
! 	/* Security Dynamics header files do not include prototypes
! 		for these 4 functions */
! extern void creadcfg P__((void));
! extern int sd_init P__((struct SD_CLIENT *sd));
! extern int sd_check P__((char *passcode, char *name, struct SD_CLIENT *sd));
! extern int sd_next P__((char *passcode, struct SD_CLIENT *sd));
! 
! extern void dbgSdClient P__((struct SD_CLIENT *sd));
! extern int ace_eval P__((AuthInfo *authInfo, struct SD_CLIENT *sd));
! extern int ace_next P__((AuthInfo *authInfo, struct SD_CLIENT *sd));
! 	/* request authentication via ACE */
! extern int ace_pass P__((AuthInfo *authInfo, struct SD_CLIENT *sd));
! 
! union	config_record configure;
! 
! 	/* useful definitions */
! #define SD_PWD	"ACE"	/* Security Dynamics reserved password */
! #define ACE_DUMMY_STATE	"ACE_DUMMY_STATE"
! #define LEN_ACE_DUMMY_STATE	strlen(ACE_DUMMY_STATE)
! 
! #define BEG_SD_1ST(sd)    (&(sd)->application_id)
! #define END_SD_1ST(sd)    (&(sd)->application_id + sizeof((sd)->application_id))
! 
! #define BEG_SD_2ND(sd)    (&(sd)->passcode_time)
! #define END_SD_2ND(sd)    (&(sd)->passcode_time + sizeof((sd)->passcode_time))
! 
! #define BEG_SD_3RD(sd)    (&(sd)->ignition_key)
! #define END_SD_3RD(sd)    (&(sd)->alphanumeric + sizeof((sd)->alphanumeric))
! 
! #define LEN_SD_1ST(sd)    ((ulong)END_SD_1ST((sd)) - (ulong)BEG_SD_1ST((sd)))
! #define LEN_SD_2ND(sd)    ((ulong)END_SD_2ND((sd)) - (ulong)BEG_SD_2ND((sd)))
! #define LEN_SD_3RD(sd)    ((ulong)END_SD_3RD((sd)) - (ulong)BEG_SD_3RD((sd)))
! 
! #define LEN_SD_TOTAL(sd)  (LEN_SD_1ST(sd) + LEN_SD_2ND(sd) + LEN_SD_3RD(sd))
! 
! /*-------------- Ace Interface End --------------*/
! #endif
! 
! #define MAX_RCVBUF_SIZE		(4096)
! #if defined( ORIG )
! # define MAX_SNDBUF_SIZE	(4096)
! #else
! # define MAX_SNDBUF_SIZE	(8192)
! #endif
! 
! 	/* Order of these enum values is important! */
! typedef enum ACCT_FLAGS {
! 	ACCT_NONE,
! 	ACCT_BY_NAME,
! 	ACCT_ANY
! } ACCT_FLAG;
! 
! char		recv_buffer[MAX_RCVBUF_SIZE];
! char		send_buffer[MAX_SNDBUF_SIZE];
  char		*progname;
  int		sockfd;
  int		acctfd;
+ int		acct_flag;
  int		debug_flag;
  int		spawn_flag;
  int		acct_pid;
  char		*radius_dir;
+ char		*radius_users;
  char		*radacct_dir;
  UINT4		expiration_seconds;
  UINT4		warning_seconds;
+ int		allow_passchange;
+ int		allow_token_caching;
+ CACHE		*cache;
  extern int	errno;
  static AUTH_REQ	*first_request;
+ extern int	warning;
+ int		rdCachefd;
+ int		wrCachefd;
  
! /**********************************************************************/
  
+ int
  main(argc, argv)
  int	argc;
  char	**argv;
***************
*** 84,90 ****
  	struct	servent		*svp;
          u_short                 lport;
  	AUTH_REQ		*authreq;
- 	AUTH_REQ		*radrecv();
  	char			argval;
  	int			t;
  	int			pid;
--- 276,281 ----
***************
*** 91,96 ****
--- 282,289 ----
  	int			cons;
  	fd_set			readfds;
  	int			status;
+ 	char			isAcctPkt;
+ 	int			sockOptFlag;
  
  	progname = *argv++;
  	argc--;
***************
*** 99,104 ****
--- 292,307 ----
  	spawn_flag = 1;
  	radacct_dir = RADACCT_DIR;
  	radius_dir = RADIUS_DIR;
+ 	radius_users = RADIUS_USERS;
+ 	errf = stdout;	/* or stderr */
+ 	warning = 0;
+ 	allow_passchange = 0;
+ 	allow_token_caching = 0;
+ 	rdCachefd = -1;
+ 	wrCachefd = -1;
+ 	acctfd = -1;
+ 	sockfd = -1;
+ 	acct_flag = ACCT_ANY;
  
  	signal(SIGHUP, sig_hup);
  	signal(SIGINT, sig_fatal);
***************
*** 112,118 ****
  
  	while(argc) {
  
! 		if(**argv != '-') {
  			usage();
  		}
  
--- 315,321 ----
  
  	while(argc) {
  
! 		if( **argv != '-' ) {
  			usage();
  		}
  
***************
*** 122,127 ****
--- 325,350 ----
  
  		switch(argval) {
  
+ 		case 'A':
+ 			if(argc == 0) {
+ 				usage();
+ 			}
+ 			if( !strcmp(*argv, "none") ) {
+ 				acct_flag = ACCT_NONE;
+ 			}
+ 			else if( !strcmp(*argv, "services") ) {
+ 				acct_flag = ACCT_BY_NAME;
+ 			}
+ 			else if( !strcmp(*argv, "incr") ) {
+ 				acct_flag = ACCT_ANY;
+ 			}
+ 			else {
+ 				usage();
+ 			}
+ 			argc--;
+ 			argv++;
+ 			break;
+ 
  		case 'a':
  			if(argc == 0) {
  				usage();
***************
*** 131,136 ****
--- 354,363 ----
  			argv++;
  			break;
  		
+ 		case 'c':
+ 			allow_token_caching = 1;
+ 			break;
+ 
  		case 'd':
  			if(argc == 0) {
  				usage();
***************
*** 140,151 ****
  			argv++;
  			break;
  		
  		case 's':	/* Single process mode */
  			spawn_flag = 0;
  			break;
  
  		case 'v':
! 			version();
  			break;
  
  		case 'x':
--- 367,395 ----
  			argv++;
  			break;
  		
+ 		case 'p':
+ 			allow_passchange = 1;
+ 			break;
+ 
  		case 's':	/* Single process mode */
  			spawn_flag = 0;
  			break;
  
+ 		case 'u':
+ 			if(argc == 0) {
+ 				usage();
+ 			}
+ 			radius_users = *argv;
+ 			argc--;
+ 			argv++;
+ 			break;
+ 
  		case 'v':
! 			radversion();
! 			break;
! 
! 		case 'w':
! 			warning = 1;
  			break;
  
  		case 'x':
***************
*** 159,176 ****
  	}
  
  	/* Initialize the dictionary */
! 	if(dict_init() != 0) {
! 		exit(-1);
  	}
  
  	/* Initialize Configuration Values */
! 	if(config_init() != 0) {
! 		exit(-1);
  	}
  
  	svp = getservbyname ("radius", "udp");
  	if (svp == (struct servent *) 0) {
! 		fprintf (stderr, "%s: No such service: radius/udp\n",
  			progname);
  		exit(-1);
  	}
--- 403,446 ----
  	}
  
  	/* Initialize the dictionary */
! 	if( (result = dict_init()) != 0) {
! 		exit(result);
  	}
  
  	/* Initialize Configuration Values */
! 	if( (result = config_init()) != 0) {
! 		exit(result);
! 	}
! 
! 	/* Init token caching */
! 	if( allow_token_caching ) {
! 		int	pd[2];
! 		int	stat;
! 
! 		cache = (CACHE *)malloc(sizeof(*cache));
! 		if( !cache ) {
! 			DEBUG("Cache Creation Failed\r\n");
! 			log_err("Cache Creation Failed\n");
! 			exit(MEMORY_ERR);
! 		}
! 		cache_init(cache, BUCKETS);
! 		if( spawn_flag ) {
! 			stat = pipe(pd);
! 			if( stat != 0 ) {
! 				(void)perror("Pipe Creation Failed:");
! 				log_err("Pipe Creation Failed\n");
! 				exit(PIPE_CREATE_ERR);
! 			}
! 			else {
! 				rdCachefd = pd[0];
! 				wrCachefd = pd[1];
! 			}
! 		}
  	}
  
  	svp = getservbyname ("radius", "udp");
  	if (svp == (struct servent *) 0) {
! 		fprintf (errf, "%s: No such service: radius/udp\n",
  			progname);
  		exit(-1);
  	}
***************
*** 182,187 ****
--- 452,464 ----
  		exit(-1);
  	}
  
+ 	sockOptFlag = 1;	/* enable */
+ 	if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR,
+ 		     (char*) &sockOptFlag, sizeof(sockOptFlag)) < 0 ) {
+ 		(void)perror("setsockopt auth SO_REUSEADDR");
+ 		exit(-1);
+ 	}
+ 
  	sin = (struct sockaddr_in *) & salocal;
          memset ((char *) sin, '\0', sizeof (salocal));
  	sin->sin_family = AF_INET;
***************
*** 197,225 ****
  	/*
  	 * Open Accounting Socket.
  	 */
! 	/* svp = getservbyname ("radacct", "udp");
! 	if (svp == (struct servent *) 0) {
! 		fprintf (stderr, "%s: No such service: %s/%s\n",
! 			progname, "radacct", "udp");
! 		exit(-1);
! 	} */
! 	lport = htons(ntohs(lport) +1);
! 	acctfd = socket (AF_INET, SOCK_DGRAM, 0);
! 	if (acctfd < 0) {
! 		(void) perror ("acct socket");
! 		exit(-1);
! 	}
  
! 	sin = (struct sockaddr_in *) & salocal;
!         memset ((char *) sin, '\0', sizeof (salocal));
! 	sin->sin_family = AF_INET;
! 	sin->sin_addr.s_addr = INADDR_ANY;
! 	sin->sin_port = lport;
  
! 	result = bind (acctfd, & salocal, sizeof (*sin));
! 	if (result < 0) {
! 		(void) perror ("acct bind");
! 		exit(-1);
  	}
  
  	/*
--- 474,522 ----
  	/*
  	 * Open Accounting Socket.
  	 */
! 	if( acct_flag >= ACCT_BY_NAME ) {
! 		svp = getservbyname ("radacct", "udp");
! 		if( svp != (struct servent *) 0 ) {
! 			lport = (u_short) svp->s_port;
! 		}
! 		else {
! 			fprintf (errf, "%s: Service %s/%s not defined ",
! 				progname, "radacct", "udp");
  
! 			if( acct_flag >= ACCT_ANY ) {
! 				lport = htons(ntohs(lport) +1);
! 				fprintf(errf, "-Using port %d\n", ntohs(lport));
! 			}
! 			else {
! 				fprintf(errf, "-Aborting\n");
! 				exit(-1);
! 			}
! 		}
  
! 		acctfd = socket (AF_INET, SOCK_DGRAM, 0);
! 		if (acctfd < 0) {
! 			(void) perror ("acct socket");
! 			exit(-1);
! 		}
! 
! 		sockOptFlag = 1;	/* enable */
! 		if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR,
! 		     (char*) &sockOptFlag, sizeof(sockOptFlag)) < 0 ) {
! 			(void)perror("setsockopt acct SO_REUSEADDR");
! 			exit(-1);
! 		}
! 
! 		sin = (struct sockaddr_in *) & salocal;
! 		memset ((char *) sin, '\0', sizeof (salocal));
! 		sin->sin_family = AF_INET;
! 		sin->sin_addr.s_addr = INADDR_ANY;
! 		sin->sin_port = lport;
! 
! 		result = bind (acctfd, & salocal, sizeof (*sin));
! 		if (result < 0) {
! 			(void) perror ("acct bind");
! 			exit(-1);
! 		}
  	}
  
  	/*
***************
*** 228,234 ****
  	if(debug_flag == 0) {
  		pid = fork();
  		if(pid < 0) {
! 			fprintf(stderr, "%s: Couldn't fork\n",
  						progname);
  			exit(-1);
  		}
--- 525,531 ----
  	if(debug_flag == 0) {
  		pid = fork();
  		if(pid < 0) {
! 			fprintf(errf, "%s: Couldn't fork\n",
  						progname);
  			exit(-1);
  		}
***************
*** 241,247 ****
  	 *	Disconnect from tty
  	 */
  	for (t = 32; t >= 3; t--) {
! 		if(t != sockfd && t != acctfd) {
  			close(t);
  		}
  	}
--- 538,545 ----
  	 *	Disconnect from tty
  	 */
  	for (t = 32; t >= 3; t--) {
! 		if(t != sockfd && t != acctfd
! 		&& t != rdCachefd && t != wrCachefd ) {
  			close(t);
  		}
  	}
***************
*** 261,270 ****
  	 * to listen for Accounting requests.  If not, we will 
  	 * listen for them ourself.
  	 */
! 	if(spawn_flag) {
  		acct_pid = fork();
  		if(acct_pid < 0) {
! 			fprintf(stderr, "%s: Couldn't fork\n",
  						progname);
  			exit(-1);
  		}
--- 559,568 ----
  	 * to listen for Accounting requests.  If not, we will 
  	 * listen for them ourself.
  	 */
! 	if( spawn_flag && (acctfd >= 0) ) {
  		acct_pid = fork();
  		if(acct_pid < 0) {
! 			fprintf(errf, "%s: Couldn't fork\n",
  						progname);
  			exit(-1);
  		}
***************
*** 275,280 ****
--- 573,585 ----
  		else {
  			close(sockfd);
  			sockfd = -1;
+ 			if( allow_token_caching ) {
+ 				free(cache);
+ 				close(rdCachefd);
+ 				rdCachefd = -1;
+ 				close(wrCachefd);
+ 				wrCachefd = -1;
+ 			}
  		}
  	}
  		
***************
*** 294,305 ****
--- 599,660 ----
  			FD_SET(acctfd, &readfds);
  		}
  
+ 		if( rdCachefd >= 0 ) {
+ 			FD_SET(rdCachefd, &readfds);
+ 		}
+ 
  		status = select(32, &readfds, NULL, NULL, NULL);
  		if(status == -1) {
  			if (errno == EINTR)
  				continue;
+ 			(void)perror("main:select");
+ 			fprintf(errf, "%s: select status=%d\n",
+ 				progname, status);
  			sig_fatal(101);
  		}
+ 		if( rdCachefd >= 0 && FD_ISSET(rdCachefd, &readfds) ) {
+ 			CacheMsg	msg;
+ 			char		buf[128];
+ 			int		stat;
+ 			int		n = 0;
+ 
+ 			while( n != sizeof(msg) ) {
+ 				n += read(rdCachefd, ((char *)&msg)+n,
+ 					sizeof(msg)-n);
+ 			}
+ 			switch( msg.type ) {
+ 			case CACHE_INSERT:
+ 				stat = cache_insert(cache,
+ 						msg.key, strlen(msg.key)+1,
+ 						msg.val, strlen(msg.val)+1,
+ 						msg.time, msg.idle);
+ 				sprintf(buf, "Insert cache <%s> FAILED\n",
+ 						msg.key);
+ 				break;
+ 			case CACHE_DELETE:
+ 				stat = cache_delete(cache,
+ 						msg.key, strlen(msg.key)+1);
+ 				sprintf(buf, "Delete cache <%s> FAILED\n",
+ 						msg.key);
+ 				break;
+ 			case CACHE_IDLE_UPDATE:
+ 				stat = cache_idle_update(cache,
+ 						msg.key, strlen(msg.key)+1,
+ 						msg.idle);
+ 				sprintf(buf, "Idle Update cache <%s> FAILED\n",
+ 						msg.key);
+ 				break;
+ 			default:
+ 				sprintf(buf, "Unknown cache msg type %d\n",
+ 					msg.type);
+ 				stat = FALSE;
+ 				break;
+ 			}
+ 			if( stat != TRUE ) {
+ 				log_err(buf);
+ 				DEBUG("%s", buf);
+ 			}
+ 		}
  		if(sockfd >= 0 && FD_ISSET(sockfd, &readfds)) {
  			salen = sizeof (saremote);
  			result = recvfrom (sockfd, (char *) recv_buffer,
***************
*** 310,321 ****
  				authreq = radrecv(
  					ntohl(sin->sin_addr.s_addr),
  					ntohs(sin->sin_port),
! 					recv_buffer, result);
! 				radrespond(authreq, sockfd);
  			}
  			else if(result < 0 && errno == EINTR) {
  				result = 0;
  			}
  		}
  		if(acctfd >=0 && FD_ISSET(acctfd, &readfds)) {
  			salen = sizeof (saremote);
--- 665,683 ----
  				authreq = radrecv(
  					ntohl(sin->sin_addr.s_addr),
  					ntohs(sin->sin_port),
! 					(u_char *)recv_buffer,
! 					result, &isAcctPkt);
! 				if( authreq ) {
! 					radrespond(authreq, sockfd, isAcctPkt);
! 				}
  			}
  			else if(result < 0 && errno == EINTR) {
  				result = 0;
  			}
+ 			else {
+ 				fprintf(errf, "%s: recvfrom result=%d\n",
+ 					progname, result);
+ 			}
  		}
  		if(acctfd >=0 && FD_ISSET(acctfd, &readfds)) {
  			salen = sizeof (saremote);
***************
*** 327,334 ****
  				authreq = radrecv(
  					ntohl(sin->sin_addr.s_addr),
  					ntohs(sin->sin_port),
! 					recv_buffer, result);
! 				radrespond(authreq, acctfd);
  			}
  			else if(result < 0 && errno == EINTR) {
  				result = 0;
--- 689,699 ----
  				authreq = radrecv(
  					ntohl(sin->sin_addr.s_addr),
  					ntohs(sin->sin_port),
! 					(u_char *)recv_buffer,
! 					result, &isAcctPkt);
! 				if( authreq ) {
! 					radrespond(authreq, acctfd, isAcctPkt);
! 				}
  			}
  			else if(result < 0 && errno == EINTR) {
  				result = 0;
***************
*** 335,340 ****
--- 700,706 ----
  			}
  		}
  	}
+ 	return 0;	/* never reached */
  }
  
  /*************************************************************************
***************
*** 347,358 ****
   *
   *************************************************************************/
  
! AUTH_REQ	*
! radrecv(host, udp_port, buffer, length)
  UINT4	host;
  u_short	udp_port;
  u_char	*buffer;
  int	length;
  {
  	u_char		*ptr;
  	AUTH_HDR	*auth;
--- 713,725 ----
   *
   *************************************************************************/
  
! AUTH_REQ *
! radrecv(host, udp_port, buffer, length, isAcctPkt)
  UINT4	host;
  u_short	udp_port;
  u_char	*buffer;
  int	length;
+ char	*isAcctPkt;
  {
  	u_char		*ptr;
  	AUTH_HDR	*auth;
***************
*** 360,374 ****
  	int		attribute;
  	int		attrlen;
  	DICT_ATTR	*attr;
- 	DICT_ATTR	*dict_attrget();
- 	char		string[64];
  	UINT4		lvalue;
- 	char		*ip_hostname();
  	VALUE_PAIR	*first_pair;
  	VALUE_PAIR	*prev;
  	VALUE_PAIR	*pair;
  	AUTH_REQ	*authreq;
  
  	/*
  	 * Pre-allocate the new request data structure
  	 */
--- 727,740 ----
  	int		attribute;
  	int		attrlen;
  	DICT_ATTR	*attr;
  	UINT4		lvalue;
  	VALUE_PAIR	*first_pair;
  	VALUE_PAIR	*prev;
  	VALUE_PAIR	*pair;
  	AUTH_REQ	*authreq;
  
+ 	*isAcctPkt = FALSE;
+ 
  	/*
  	 * Pre-allocate the new request data structure
  	 */
***************
*** 375,389 ****
  
  	if((authreq = (AUTH_REQ *)malloc(sizeof(AUTH_REQ))) ==
  						(AUTH_REQ *)NULL) {
! 		fprintf(stderr, "%s: no memory\n", progname);
! 		exit(-1);
  	}
  
  	auth = (AUTH_HDR *)buffer;
  	totallen = ntohs(auth->length);
  
! 	DEBUG("radrecv: Request from host %lx code=%d, id=%d, length=%d\n",
! 				(u_long)host, auth->code, auth->id, totallen);
  
  	/*
  	 * Fill header fields
--- 741,755 ----
  
  	if((authreq = (AUTH_REQ *)malloc(sizeof(AUTH_REQ))) ==
  						(AUTH_REQ *)NULL) {
! 		fprintf(errf, "%s: no memory\n", progname);
! 		exit(MEMORY_ERR);
  	}
  
  	auth = (AUTH_HDR *)buffer;
  	totallen = ntohs(auth->length);
  
! 	DEBUG("radrecv: Request from host %lx code=%d, id=%d, length=%d\r\n",
! 		(u_long)host, auth->code, auth->id, totallen);
  
  	/*
  	 * Fill header fields
***************
*** 393,398 ****
--- 759,765 ----
  	authreq->id = auth->id;
  	authreq->code = auth->code;
  	memcpy(authreq->vector, auth->vector, AUTH_VECTOR_LEN);
+ 	authreq->secret[0] = '\0';	/* ensure known contents */
  
  	/*
  	 * Extract attribute-value pairs
***************
*** 412,427 ****
  		}
  		attrlen -= 2;
  		if((attr = dict_attrget(attribute)) == (DICT_ATTR *)NULL) {
! 			DEBUG("Received unknown attribute %d\n", attribute);
  		}
  		else if ( attrlen >= AUTH_STRING_LEN ) {
! 			DEBUG("attribute %d too long, %d >= %d\n", attribute,
! 				attrlen, AUTH_STRING_LEN);
  		}
  		else {
  			if((pair = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) ==
  						(VALUE_PAIR *)NULL) {
! 				fprintf(stderr, "%s: no memory\n",
  						progname);
  				exit(-1);
  			}
--- 779,798 ----
  		}
  		attrlen -= 2;
  		if((attr = dict_attrget(attribute)) == (DICT_ATTR *)NULL) {
! 		    DEBUG("Received unknown attribute %d\r\n", attribute);
  		}
  		else if ( attrlen >= AUTH_STRING_LEN ) {
! 		    DEBUG("attribute %d too long, %d >= %d\r\n", attribute,
! 			attrlen, AUTH_STRING_LEN);
  		}
  		else {
+ 			if( attribute == PW_ACCT_STATUS_TYPE ) {
+ 				*isAcctPkt = TRUE;
+ 			}
+ 
  			if((pair = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) ==
  						(VALUE_PAIR *)NULL) {
! 				fprintf(errf, "%s: no memory\n",
  						progname);
  				exit(-1);
  			}
***************
*** 428,433 ****
--- 799,805 ----
  			strcpy(pair->name, attr->name);
  			pair->attribute = attr->value;
  			pair->type = attr->type;
+ 			pair->size = attrlen;
  			pair->next = (VALUE_PAIR *)NULL;
  
  			switch(attr->type) {
***************
*** 458,466 ****
  				}
  				prev = pair;
  				break;
  			
  			default:
! 				DEBUG("    %s (Unknown Type %d)\n", attr->name,attr->type);
  				free(pair);
  				break;
  			}
--- 830,848 ----
  				}
  				prev = pair;
  				break;
+ #if defined( BINARY_FILTERS )
+                         case PW_TYPE_FILTER_BINARY:
+                                 memcpy(pair->strvalue, ptr, attrlen);
+                                 pair->strvalue[attrlen] = '\0';
+                                 debug_pair(stdout, pair);
+                                 pair->next = first_pair;
+                                 first_pair = pair;
+                                 break;
+ #endif /* BINARY_FILTERS */
  			
  			default:
! 				DEBUG("    %s (Unknown Type %d)\r\n",
! 					attr->name,attr->type);
  				free(pair);
  				break;
  			}
***************
*** 470,480 ****
--- 852,934 ----
  		length -= attrlen + 2;
  	}
  	authreq->request = first_pair;
+ 
+ 	if( (auth->code == PW_ACCOUNTING_REQUEST) && *isAcctPkt ) {
+ 		authreq = authenticateAcctReq(authreq, auth);
+ 	}
+ 
  	return(authreq);
  }
  
  /*************************************************************************
   *
+  *	Function: authenticateAcctReq
+  *
+  *	Purpose: Authenticate an accounting request packet 
+  *
+  *************************************************************************/
+ 
+ AUTH_REQ *
+ authenticateAcctReq(authreq, auth)
+ AUTH_REQ	*authreq;
+ AUTH_HDR	*auth;
+ {
+ 	u_char	*buffer;
+ 	int	totallen;
+ 	u_char	saveDigest[AUTH_VECTOR_LEN];
+ 	u_char	digest[AUTH_VECTOR_LEN];
+ 	int	secretlen;
+ 	u_char	secret[256];
+ 	char	tmpbuf[256];
+ 	UINT4	ipaddr;
+ 	u_char	error = FALSE;
+ 	int	stat;
+ 
+ 	totallen = ntohs(auth->length);
+ 	stat = get_client_info( authreq->ipaddr, &ipaddr, secret, tmpbuf );
+ 	secretlen = strlen( (CONST char *)secret );
+ 	if( stat != 0 ) {
+ 		sprintf(tmpbuf, "authenticateAcctReq: from %s, ID %d : %s\n",
+ 			ip_hostname(authreq->ipaddr),
+ 			authreq->id, get_errmsg(stat));
+ 		log_err(tmpbuf);
+ 		memset(secret, 0, sizeof(secret));
+ 		error = TRUE;
+ 	}
+ 	else if( totallen + secretlen > MAX_RCVBUF_SIZE ) {
+ 		sprintf( tmpbuf,
+ 			"rcv req from %s plus secret : too long: s - ID: %d\n",
+ 				ip_hostname(authreq->ipaddr), authreq->id);
+ 		log_err( tmpbuf );
+ 		error = TRUE;
+ 	}
+ 	else {
+ 		strcpy((char *)authreq->secret, (CONST char *)secret);
+ 		memcpy( saveDigest, auth->vector, AUTH_VECTOR_LEN );
+ 		memset( auth->vector, 0, AUTH_VECTOR_LEN );
+ 		buffer = (u_char *)auth;
+ 		memcpy( &buffer[totallen], secret, secretlen );
+ 		md5_calc( digest, (u_char *)auth, totallen + secretlen );
+ 		if ( memcmp( digest, saveDigest, AUTH_VECTOR_LEN) ) {
+ 			sprintf( tmpbuf,
+ 				"Bad authenticator: from %s - ID: %d\n",
+ 				ip_hostname(authreq->ipaddr), authreq->id);
+ 			log_err( tmpbuf );
+ 			error = TRUE;
+ 		}
+ 	}
+ 
+ 	if (error) {
+ 		pairfree( authreq->request );
+ 		memset( authreq, 0, sizeof(*authreq) );
+ 		free( authreq );
+ 		authreq = 0;
+ 	}
+ 	return authreq;
+ }
+ 
+ /*************************************************************************
+  *
   *	Function: radrespond
   *
   *	Purpose: Respond to supported requests:
***************
*** 489,497 ****
   *
   *************************************************************************/
  
! radrespond(authreq, activefd)
  AUTH_REQ	*authreq;
  int		activefd;
  {
  	switch(authreq->code) {
  
--- 943,953 ----
   *
   *************************************************************************/
  
! int
! radrespond(authreq, activefd, isAcctPkt)
  AUTH_REQ	*authreq;
  int		activefd;
+ char		isAcctPkt;
  {
  	switch(authreq->code) {
  
***************
*** 505,517 ****
  		break;
  	
  	case PW_ACCOUNTING_REQUEST:
! 		rad_accounting(authreq, activefd);
  		break;
! 	
  	case PW_PASSWORD_REQUEST:
  		rad_passchange(authreq, activefd);
  		break;
! 	
  	default:
  		break;
  	}
--- 961,981 ----
  		break;
  	
  	case PW_ACCOUNTING_REQUEST:
! 		if( isAcctPkt ) {
! 			rad_accounting(authreq, activefd);
! 		}
! #if defined( ASCEND_LOGOUT )
! 		else {
!                 	send_accounting_response(authreq, activefd,
! 				"added by Ascend");
! 		}
! #endif /* ASCEND_LOGOUT */
  		break;
! 
  	case PW_PASSWORD_REQUEST:
  		rad_passchange(authreq, activefd);
  		break;
! 
  	default:
  		break;
  	}
***************
*** 532,537 ****
--- 996,1002 ----
   *
   *************************************************************************/
  
+ int
  rad_spawn_child(authreq, activefd)
  AUTH_REQ	*authreq;
  int		activefd;
***************
*** 541,547 ****
  	UINT4		curtime;
  	int		request_count;
  	char		msg[128];
- 	char		*ip_hostname();
  	int		child_pid;
  
  	curtime = (UINT4)time(0);
--- 1006,1011 ----
***************
*** 624,629 ****
--- 1088,1094 ----
  	}
  	if(child_pid == 0) {
  		/* This is the child, it should go ahead and respond */
+ 		close(rdCachefd);
  		rad_authenticate(authreq, activefd);
  		exit(0);
  	}
***************
*** 634,645 ****
  }
  
  void
! sig_cleanup()
  {
  	int		status;
          pid_t		pid;
  	AUTH_REQ	*curreq;
   
          for (;;) {
  		pid = waitpid((pid_t)-1,&status,WNOHANG);
  		signal(SIGCHLD, sig_cleanup);
--- 1099,1113 ----
  }
  
  void
! sig_cleanup(sig)
! int	sig;
  {
  	int		status;
          pid_t		pid;
  	AUTH_REQ	*curreq;
   
+ 	(void)sig;	/* ignore param */
+ 
          for (;;) {
  		pid = waitpid((pid_t)-1,&status,WNOHANG);
  		signal(SIGCHLD, sig_cleanup);
***************
*** 665,670 ****
--- 1133,1437 ----
          }
  }
  
+ #if defined( ASCEND_LOGOUT )
+ /*************************************************************************
+  *
+  *      Function: send_accounting_response
+  *
+  *      Purpose: Reply to the request with an ACKNOWLEDGE.  Also attach
+  *               any user message provided.
+  *
+  *************************************************************************/
+  
+ void
+ send_accounting_response(authreq, activefd, msg)
+ AUTH_REQ	*authreq;
+ int		activefd;
+ char		*msg;
+ {
+         AUTH_HDR                *auth;
+         u_short                 total_length;
+         struct  sockaddr_in     saremote;
+         struct  sockaddr_in     *sin;
+         u_char                  *ptr;
+         int                     len;
+         u_char                  digest[AUTH_VECTOR_LEN];
+         int                     secretlen;
+ 
+         auth = (AUTH_HDR *)send_buffer;
+ 
+         /* Build standard header */
+         auth->code = PW_ACCOUNTING_RESPONSE;
+         auth->id = authreq->id;
+         memcpy(auth->vector, authreq->vector, AUTH_VECTOR_LEN);
+ 
+         DEBUG("Accounting Ack of id %d to %lx -port- %x (%s)\r\n",
+               authreq->id, authreq->ipaddr, authreq->udp_port,
+               ip_hostname(authreq->ipaddr));
+ 
+         total_length = AUTH_HDR_LEN;
+         ptr = auth->data;
+ 
+         /* Append the user message */
+         if(msg != (char *)NULL) {
+                 len = strlen(msg);
+                 if(len > 0 && len < 250) {
+                         *ptr++ = PW_PORT_MESSAGE;
+                         *ptr++ = len + 2;
+                         memcpy(ptr, msg, len);
+                         ptr += len;
+                         total_length += len + 2;
+                 }
+         }
+ 
+         auth->length = htons(total_length);
+ 
+         /* Calcuate the response digest */
+         secretlen = strlen((char *)authreq->secret);
+         memcpy(send_buffer + total_length, authreq->secret, secretlen);
+         md5_calc(digest, (u_char *)auth, total_length + secretlen);
+         memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
+         memset(send_buffer + total_length, 0, secretlen);
+ 
+         sin = (struct sockaddr_in *) &saremote;
+         memset ((char *) sin, 0, sizeof (saremote));
+         sin->sin_family = AF_INET;
+ 	sin->sin_addr.s_addr = htonl(authreq->ipaddr);
+ 	sin->sin_port = htons(authreq->udp_port);
+ 
+         /* Send it to the user */
+         sendto(activefd, (char *)auth, (int)total_length, (int)0,
+                         (struct sockaddr *)sin, sizeof(struct sockaddr_in));
+ }
+ #endif /* ASCEND_LOGOUT */
+ 
+ /*************************************************************************
+  *
+  *	Function: getUnixPwdType
+  *
+  *	Purpose: Determine if the password indicates UNIX authentication
+  *
+  *************************************************************************/
+ 
+ PasswordType
+ getUnixPwdType(pwd)
+ char	*pwd;
+ {
+ 	if( strcmp(pwd, UNIX_PWD) == 0) {
+ 		return PWD_SPECIAL;
+ 	}
+ 
+ 	return PWD_NORMAL;
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: getTokenPwdType
+  *
+  *	Purpose: Determine if the password indicates token authentication
+  *
+  *************************************************************************/
+ 
+ PasswordType
+ getTokenPwdType(pwd)
+ char	*pwd;
+ {
+ #if defined(SAFEWORD)
+ 	if( strcmp(pwd, EL_PWD) == 0) {
+ 		return PWD_SPECIAL;
+ 	}
+ #endif
+ #if defined(ACE)
+ 	if( strcmp(pwd, SD_PWD) == 0) {
+ 		return PWD_SPECIAL;
+ 	}
+ #endif
+ 	return PWD_NORMAL;
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: getPasswordType
+  *
+  *	Purpose: Determine if the password is 'special'
+  *
+  *************************************************************************/
+ 
+ PasswordType
+ getPasswordType(pwd)
+ char	*pwd;
+ {
+ 	if( getUnixPwdType(pwd) == PWD_SPECIAL ) {
+ 		return PWD_SPECIAL;
+ 	}
+ 	else {
+ 		return getTokenPwdType(pwd);
+ 	}
+ }
+ 
+ #if( 0 )
+ /*************************************************************************
+  *
+  *	Function: get_attribute
+  *
+  *	Purpose: Given an attribute list, an attribute identifier, and
+  *		an indirect pointer to an attribute struct, return a
+  *		pointer to the original list; the attribute
+  *		struct pointer will be set to the matching attribute
+  *		struct, if any.
+  *
+  *************************************************************************/
+ 
+ VALUE_PAIR *
+ get_attribute(list, attributeId, attribute)
+ VALUE_PAIR	*list;
+ int		attributeId;
+ VALUE_PAIR	**attribute;
+ {
+ 	VALUE_PAIR *cur = list;
+ 
+ 	*attribute = (VALUE_PAIR *)0;
+ 
+ 	while( cur ) {
+ 		if( cur->attribute == attributeId ) {
+ 			*attribute = cur;
+ 			break;
+ 		}
+ 		else {
+ 			cur = cur->next;
+ 		}
+ 	}
+ 	return list;
+ }
+ #endif
+ 
+ /*************************************************************************
+  *
+  *	Function: cut_attribute
+  *
+  *	Purpose: Given an attribute list, an attribute identifier, and
+  *		an indirect pointer to an attribute struct, return a list
+  *		of all the attributes in the original list EXCEPT the first
+  *		occurence of one matching the attribute id; the attribute
+  *		struct pointer will be set to the matching attribute
+  *		struct, if any.
+  *
+  *************************************************************************/
+ 
+ VALUE_PAIR *
+ cut_attribute(list, attributeId, attribute)
+ VALUE_PAIR	*list;
+ int		attributeId;
+ VALUE_PAIR	**attribute;
+ {
+ 	VALUE_PAIR *head = (VALUE_PAIR *)0;
+ 
+ 	*attribute = (VALUE_PAIR *)0;
+ 	if( !list ) {
+ 		head = list;
+ 	}
+ 	else if( list->attribute == attributeId ) {
+ 		*attribute = list;
+ 		head = list->next;
+ 	}
+ 	else {
+ 		VALUE_PAIR *cur;
+ 
+ 		cur = head = list;
+ 		list = list->next;
+ 		while( list != (VALUE_PAIR *)NULL ) {
+ 			if( list->attribute == attributeId ) {
+ 				*attribute = list;
+ 				cur->next = list->next;
+ 				(*attribute)->next = (VALUE_PAIR *)0;
+ 				break;
+ 			}
+ 			else {
+ 				cur->next = list;
+ 				cur = cur->next;
+ 				list = list->next;
+ 			}
+ 		}
+ 	}
+ 	return head;
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: get_attr_lvalue
+  *
+  *	Purpose: Given an attribute list and an attribute identifier
+  *		return the the lvalue of the specified attribute
+  *		or zero if the attribute is not in the list.
+  *
+  *		In other languages we could return the *value*, whether
+  *		that was the lvalue or the strvalue, etc. but C mandates
+  *		a single function return type.  There are of course ways
+  *		around this but they are overkill for this function, and
+  *		kind of ugly, as well.
+  *
+  *************************************************************************/
+ 
+ UINT4
+ get_attr_lvalue(list, attribute)
+ VALUE_PAIR	*list;
+ int		attribute;
+ {
+ 	UINT4		lval;
+ 
+ 	while(list != (VALUE_PAIR *)NULL) {
+ 		if(list->attribute == attribute) {
+ 			break;
+ 		}
+ 		list = list->next;
+ 	}
+ 
+ 	if(list == (VALUE_PAIR *)NULL) {
+ 		lval = 0;
+ 	}
+ 	else {
+ 		lval = list->lvalue;
+ 	}
+ 
+         DEBUG("get_attr_lvalue(%d) == %ld\r\n", attribute, lval);
+ 	return lval;
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: get_attr_strvalue
+  *
+  *	Purpose: Given an attribute list and an attribute identifier
+  *		return the the strvalue of the specified attribute
+  *		or zero if the attribute is not in the list.
+  *
+  *************************************************************************/
+ 
+ char *
+ get_attr_strvalue(list, attribute)
+ VALUE_PAIR	*list;
+ int		attribute;
+ {
+ 	char	*strval;
+ 
+ 	while(list != (VALUE_PAIR *)NULL) {
+ 		if(list->attribute == attribute) {
+ 			break;
+ 		}
+ 		list = list->next;
+ 	}
+ 
+ 	if(list == (VALUE_PAIR *)NULL) {
+ 		strval = (char *)0;
+ 	}
+ 	else {
+ 		strval = list->strvalue;
+ 	}
+ 
+         DEBUG("get_attr_strvalue(%d) == %s\r\n", attribute, strval);
+ 	return strval;
+ }
+ 
  /*************************************************************************
   *
   *	Function: rad_passchange
***************
*** 680,697 ****
  {
  	VALUE_PAIR	*namepair;
  	VALUE_PAIR	*check_item;
! 	VALUE_PAIR	*newpasspair;
! 	VALUE_PAIR	*oldpasspair;
  	VALUE_PAIR	*curpass;
  	VALUE_PAIR	*user_check;
  	VALUE_PAIR	*user_reply;
! 	char		pw_digest[16];
! 	char		string[64];
  	char		passbuf[AUTH_PASS_LEN];
  	int		i;
  	int		secretlen;
  	char		msg[128];
! 	char		*ip_hostname();
  
  	/* Get the username */
  	namepair = authreq->request;
--- 1447,1479 ----
  {
  	VALUE_PAIR	*namepair;
  	VALUE_PAIR	*check_item;
! 	VALUE_PAIR	*newpasspair = (VALUE_PAIR *)NULL;
! 	VALUE_PAIR	*oldpasspair = (VALUE_PAIR *)NULL;
  	VALUE_PAIR	*curpass;
  	VALUE_PAIR	*user_check;
  	VALUE_PAIR	*user_reply;
! 	char		pw_digest[AUTH_VECTOR_LEN];
! 	char		string[512];
  	char		passbuf[AUTH_PASS_LEN];
  	int		i;
  	int		secretlen;
  	char		msg[128];
! 	int		vecLen;
! 	int		retval;
! 	UINT4		user_expiration_days;
! 	UINT4		user_expiration_seconds;
! 
! 	if( allow_passchange == 0 ) {
! 		sprintf(msg,
! 			"Passchange: from %s: Password Changing NOT Allowed\n",
! 				ip_hostname(authreq->ipaddr));
! 		log_err(msg);
! 		send_reject(authreq, (char *)NULL, activefd);
! 		pairfree(authreq->request);
! 		memset(authreq, 0, sizeof(AUTH_REQ));
! 		free(authreq);
! 		return;
! 	}
  
  	/* Get the username */
  	namepair = authreq->request;
***************
*** 706,711 ****
--- 1488,1494 ----
  			"Passchange: from %s - No User name supplied\n",
  			ip_hostname(authreq->ipaddr));
  		log_err(msg);
+ 		send_reject(authreq, (char *)NULL, activefd);
  		pairfree(authreq->request);
  		memset(authreq, 0, sizeof(AUTH_REQ));
  		free(authreq);
***************
*** 715,724 ****
  	/*
  	 * Look the user up in the database
  	 */
! 	if(user_find(namepair->strvalue, &user_check, &user_reply) != 0) {
! 		sprintf(msg,
! 			"Passchange: from %s - Invalid User: %s\n",
! 			ip_hostname(authreq->ipaddr), namepair->strvalue);
  		log_err(msg);
  		send_reject(authreq, (char *)NULL, activefd);
  		pairfree(authreq->request);
--- 1498,1510 ----
  	/*
  	 * Look the user up in the database
  	 */
! 	if( (retval = user_find(namepair->strvalue, &user_check, &user_reply))
! 	  != 0) {
! 		DEBUG("Passchange: user_find(%s) error = %s\r\n",
! 			namepair->strvalue, get_errmsg(retval));
! 		sprintf(msg, "Passchange: from %s - %s: %s\n",
! 			ip_hostname(authreq->ipaddr), get_errmsg(retval),
! 			namepair->strvalue);
  		log_err(msg);
  		send_reject(authreq, (char *)NULL, activefd);
  		pairfree(authreq->request);
***************
*** 752,758 ****
  
  	/* Verify that both encrypted passwords were supplied */
  	if(newpasspair == (VALUE_PAIR *)NULL ||
! 					oldpasspair == (VALUE_PAIR *)NULL) {
  		/* Missing one of the passwords */
  		sprintf(msg,
  			"Passchange: from %s - Missing Password: %s\n",
--- 1538,1545 ----
  
  	/* Verify that both encrypted passwords were supplied */
  	if(newpasspair == (VALUE_PAIR *)NULL ||
! 	   oldpasspair == (VALUE_PAIR *)NULL)
! 	{
  		/* Missing one of the passwords */
  		sprintf(msg,
  			"Passchange: from %s - Missing Password: %s\n",
***************
*** 789,799 ****
  		free(authreq);
  		return;
  	}
! 	if(strcmp(curpass->strvalue,"UNIX") == 0) {
  		/* Can't change passwords that aren't in users file */
  		sprintf(msg,
  			"Passchange: from %s - system password change not allowed: %s\n",
! 			ip_hostname(authreq->ipaddr), namepair->strvalue);
  		log_err(msg);
  		send_reject(authreq, (char *)NULL, activefd);
  		pairfree(authreq->request);
--- 1576,1587 ----
  		free(authreq);
  		return;
  	}
! 	if( getPasswordType(curpass->strvalue) != PWD_NORMAL ) {
  		/* Can't change passwords that aren't in users file */
  		sprintf(msg,
  			"Passchange: from %s - system password change not allowed: %s\n",
! 				ip_hostname(authreq->ipaddr),
! 				namepair->strvalue);
  		log_err(msg);
  		send_reject(authreq, (char *)NULL, activefd);
  		pairfree(authreq->request);
***************
*** 806,825 ****
  
  	/* Decrypt the old password */
  	secretlen = strlen(curpass->strvalue);
  	memcpy(string, curpass->strvalue, secretlen);
! 	memcpy(string + secretlen, newpasspair->strvalue, AUTH_VECTOR_LEN);
! 	md5_calc(pw_digest, string, AUTH_VECTOR_LEN + secretlen);
! 	memcpy(passbuf, oldpasspair->strvalue, AUTH_PASS_LEN);
! 	for(i = 0;i < AUTH_PASS_LEN;i++) {
! 		passbuf[i] ^= pw_digest[i];
  	}
  
  	/* Did they supply the correct password ??? */
! 	if(strncmp(passbuf, curpass->strvalue, AUTH_PASS_LEN) != 0) {
  		sprintf(msg,
! 			"Passchange: from %s - Incorrect Password: %s\n",
! 			ip_hostname(authreq->ipaddr), namepair->strvalue);
  		log_err(msg);
  		send_reject(authreq, (char *)NULL, activefd);
  		pairfree(authreq->request);
  		pairfree(user_check);
--- 1594,1628 ----
  
  	/* Decrypt the old password */
  	secretlen = strlen(curpass->strvalue);
+ 	vecLen = newpasspair->size;
+ #if( 0 )
+ 	DEBUG("strlen(newpasspair->strvalue): %d, newpasspair->size: %d\r\n",
+ 		strlen(newpasspair->strvalue), newpasspair->size);
+ #endif
  	memcpy(string, curpass->strvalue, secretlen);
! 	memcpy(string + secretlen, newpasspair->strvalue, vecLen);
! 	md5_calc((u_char *)pw_digest, (u_char *)string, vecLen + secretlen);
! 
! 	memcpy(passbuf, oldpasspair->strvalue, oldpasspair->size);
! 	for(i = 0;i < oldpasspair->size;i++) {
! 		passbuf[i] ^= pw_digest[i % vecLen];
  	}
  
  	/* Did they supply the correct password ??? */
! 	if(memcmp(passbuf, curpass->strvalue, curpass->size) != 0) {
  		sprintf(msg,
! 			"Passchange: from %s - Bad Pwd for %s:\n",
! 				ip_hostname(authreq->ipaddr),
! 				namepair->strvalue);
! 		log_err(msg);
! 
! #if defined( PWD_DEBUG )
! 		sprintf(msg,
! 			"\tCont'd: Exp Pwd(%d, %.*s); User Exp Pwd(%d, %.*s)\n",
! 				curpass->size, curpass->size, curpass->strvalue,
! 				newpasspair->size, newpasspair->size, passbuf);
  		log_err(msg);
+ #endif
  		send_reject(authreq, (char *)NULL, activefd);
  		pairfree(authreq->request);
  		pairfree(user_check);
***************
*** 832,848 ****
  	/* Decrypt the new password */
  	memcpy(string, curpass->strvalue, secretlen);
  	memcpy(string + secretlen, authreq->vector, AUTH_VECTOR_LEN);
! 	md5_calc(pw_digest, string, AUTH_VECTOR_LEN + secretlen);
! 	memcpy(passbuf, newpasspair->strvalue, AUTH_PASS_LEN);
! 	for(i = 0;i < AUTH_PASS_LEN;i++) {
! 		passbuf[i] ^= pw_digest[i];
  	}
  
  	/* Update the users password */
! 	strncpy(curpass->strvalue, passbuf, AUTH_PASS_LEN);
  
  	/* Add a new expiration date if we are aging passwords */
! 	if(expiration_seconds != (UINT4)0) {
  		set_expiration(user_check, expiration_seconds);
  	}
  
--- 1635,1665 ----
  	/* Decrypt the new password */
  	memcpy(string, curpass->strvalue, secretlen);
  	memcpy(string + secretlen, authreq->vector, AUTH_VECTOR_LEN);
! 	md5_calc((u_char *)pw_digest, (u_char *)string, AUTH_VECTOR_LEN + secretlen);
! 	memcpy(passbuf, newpasspair->strvalue, newpasspair->size);
! 	for( i = 0; i < newpasspair->size; i++ ) {
! 		passbuf[i] ^= pw_digest[i % AUTH_VECTOR_LEN];
  	}
  
  	/* Update the users password */
! 	/* Note: It is impossible for newpasspair->size
! 	 *	to be larger than sizeof(curpass->strvalue), so
! 	 *	this strncpy is safe
! 	 *
! 	 *	Also, we *always* have room for the terminating NUL
! 	 */
! 	strncpy(curpass->strvalue, passbuf, newpasspair->size);
! 	curpass->strvalue[newpasspair->size] = 0;
  
+ 	/* Look for an existing expiration duration entry */
+ 	user_expiration_days = get_attr_lvalue(user_reply, ASCEND_PW_LIFETIME);
+ 	user_expiration_seconds = user_expiration_days * (UINT4)SECONDS_PER_DAY;
+ 
  	/* Add a new expiration date if we are aging passwords */
! 	if( user_expiration_seconds != (UINT4)0 ) {
! 		set_expiration(user_check, user_expiration_seconds);
! 	}
! 	else if( expiration_seconds != (UINT4)0 ) {
  		set_expiration(user_check, expiration_seconds);
  	}
  
***************
*** 853,859 ****
  			"Passchange: unable to update password for %s\n",
  			namepair->strvalue);
  		log_err(msg);
- 
  	}
  	else {
  		send_pwack(authreq, activefd);
--- 1670,1675 ----
***************
*** 868,873 ****
--- 1684,2330 ----
  
  /*************************************************************************
   *
+  *	Function: authCleanup
+  *
+  *	Purpose: Standard cleanup code when auth is finished
+  *
+  *************************************************************************/
+ 
+ void
+ authCleanup(authInfo)
+ AuthInfo	*authInfo;
+ {
+ 	pairfree(authInfo->cutList);
+ 	authInfo->cutList = (VALUE_PAIR *)0;
+ 	pairfree(authInfo->authreq->request);
+ 	memset(authInfo->authreq, 0, sizeof(AUTH_REQ));
+ 	free(authInfo->authreq);
+ 	authInfo->authreq = (AUTH_REQ *)0;
+ }
+ 
+ #if defined(SAFEWORD)
+ /*************************************************************************
+  *
+  *	Function: authSafewordPwd
+  *
+  *	Purpose: Setup for and invoke a SafeWord authentication request
+  *
+  *************************************************************************/
+ int
+ authSafewordPwd(authInfo)
+ AuthInfo	*authInfo;
+ {
+ 	int do_safeword_pass P__((AuthInfo *authInfo, struct pblk *pb));
+ 	struct pblk *pb;
+ 	char msg[128];
+ 
+ 	DEBUG("authSafewordPwd\r\n");
+     	authInfo->user_msg = (char *)NULL;
+ 	pb = (struct pblk *)malloc(sizeof(*pb));
+ 	if( !pb ) {
+ 		sprintf(msg, "authSafewordPwd: malloc err for user %s\n",
+ 			authInfo->authName->strvalue);
+ 		DEBUG("%s\r\n", msg);
+ 		log_err(msg);
+ 		authInfo->user_msg = (char *)NULL;
+ 		return -1;
+ 	}
+ 
+ 	return do_safeword_pass(authInfo, pb);
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: do_safeword_pass
+  *
+  *	Purpose: Process and reply to a SafeWord authentication request
+  *
+  *************************************************************************/
+ 
+ int
+ do_safeword_pass(authInfo, pb)
+ AuthInfo	*authInfo;
+ struct pblk	*pb;
+ {
+ 	char stateInfo[253];
+ 	char *si;
+ 	char msg[128];
+ 	int result;
+ 
+ 	result = safeword_pass(authInfo, pb);
+ 	switch( result ) {
+ 	default:
+ 		sprintf(msg,
+ 			"safeword_pass BIZARRE result %d, user %s, NAS %s\n",
+ 			result, authInfo->authName->strvalue,
+ 			ip_hostname(authInfo->authreq->ipaddr));
+ 		DEBUG("%s\r\n", msg);
+ 		log_err(msg);
+ 		authInfo->user_msg = (char *)NULL;
+ 		result = SAFEWORD_FAILED;
+ 		break;
+ 				
+ 	case SAFEWORD_FAILED:
+ 		sprintf(msg, "safeword_pass FAILED, user %s, NAS %s\n",
+ 			authInfo->authName->strvalue,
+ 			ip_hostname(authInfo->authreq->ipaddr));
+ 		DEBUG("%s\r\n", msg);
+ 		log_err(msg);
+ 		authInfo->user_msg = (char *)NULL;
+ 		result = SAFEWORD_FAILED;
+ 		break;
+ 				
+ 	case SAFEWORD_CHALLENGING:
+ 		DEBUG("safeword_pass CHALLENGING\r\n");
+ 		if( authInfo->chkImmediate ) {
+ 				/* short-circuit challenge */
+ 			si = authInfo->authState->strvalue;
+     			memcpy(si, BEG_PB_1ST(pb), LEN_PB_1ST(pb));
+ 			si += LEN_PB_1ST(pb);
+     			memcpy(si, BEG_PB_2ND(pb), LEN_PB_2ND(pb));
+ 			authInfo->authState->size = LEN_PB_TOTAL(pb);
+ 				/* once only, please! */
+ 			authInfo->chkImmediate = (VALUE_PAIR *)0;
+ 				/* NB: pb is zeroed and freed by this
+ 					tail-recursive call) */
+ 			return do_safeword_pass(authInfo, pb);
+ 		}
+ 		else {
+ 			si = stateInfo;
+     			memcpy(si, BEG_PB_1ST(pb), LEN_PB_1ST(pb));
+ 			si += LEN_PB_1ST(pb);
+     			memcpy(si, BEG_PB_2ND(pb), LEN_PB_2ND(pb));
+ 			send_challenge(	authInfo->authreq,
+ 					pb->chal, strlen(pb->chal),
+ 					stateInfo, LEN_PB_TOTAL(pb),
+ 					authInfo->fd);
+ 			result = -SAFEWORD_CHALLENGING;
+ 		}
+ 		break;
+ 
+ 	case SAFEWORD_PASSED:
+ 		DEBUG("safeword_pass PASSED\r\n");
+ 		result = 0;
+ 		break;
+ 	}
+ 	memset(pb, 0, sizeof(*pb));
+ 	free(pb);
+ 	return result;
+ }
+ #endif
+ 
+ #if defined(ACE)
+ /*************************************************************************
+  *
+  *	Function: authAcePwd
+  *
+  *	Purpose: Process and reply to an ACE authentication request
+  *
+  *************************************************************************/
+ 
+ int
+ authAcePwd(authInfo)
+ AuthInfo	*authInfo;
+ {
+ 	char stateInfo[253];
+ 	char *si;
+ 	struct SD_CLIENT *sd = (struct SD_CLIENT *)malloc(sizeof(*sd));
+ 	char *dummyState = ACE_DUMMY_STATE;
+ 	int stateLen = strlen(dummyState);
+ 	char *nextMsg = "(without PIN)";
+ 	char *nextCaution = "-- See your System Administrator!";
+ 	char *ncMsg;
+ 	char msg[128];
+ 	int result;
+ 
+ 	DEBUG("authAcePwd\r\n");
+     	authInfo->user_msg=(char *)NULL;
+ 	result = ace_pass(authInfo, sd);
+ 	switch( result ) {
+ 	default:
+ 		sprintf(msg, "ace_pass BIZARRE result %d for user %s, NAS %s\n",
+ 			result, authInfo->authName->strvalue,
+ 			ip_hostname(authInfo->authreq->ipaddr));
+ 		DEBUG("%s\r\n", msg);
+ 		log_err(msg);
+ 		authInfo->user_msg = (char *)NULL;
+ 		result = ACE_FAILED;
+ 		break;
+ 			
+ 	case ACE_FAILED:
+ 		sprintf(msg, "ace_pass FAILED for user %s, NAS %s\n",
+ 			authInfo->authName->strvalue,
+ 			ip_hostname(authInfo->authreq->ipaddr));
+ 		DEBUG("%s\r\n", msg);
+ 		log_err(msg);
+ 		authInfo->user_msg = (char *)NULL;
+ 		result = ACE_FAILED;
+ 		break;
+ 			
+ 	case ACE_CHALLENGING:
+ 		DEBUG("ace_pass CHALLENGING\r\n");
+ 		strcpy(stateInfo, dummyState);
+ 		send_challenge( authInfo->authreq, "", 0,
+ 				stateInfo, stateLen, authInfo->fd);
+ 		result = -ACE_CHALLENGING;
+ 		break;
+ 
+ 	case ACE_PASSED:
+ 		DEBUG("ace_pass PASSED\r\n");
+ 		result = 0;
+ 		break;
+ 
+ 	case ACE_NEXT_PASSCODE:
+ 		DEBUG("ace_pass NEXT_CODE\r\n");
+ 		if( spawn_flag != 0 ) {
+ 			sprintf(msg, "ACE Next_Code processing REQUIRES \'radiusd -s\'\r\n");
+ 				DEBUG("%s", msg);
+ 				log_err(msg);
+ #if(0)
+ 			authInfo->user_msg = (char *)NULL;
+ 			result = -ACE_NEXT_PASSCODE;
+ 			break;
+ #else
+ 			/* ok, let the user try - it cannot work, but at least
+ 				s/he'll understand a bit better why not */
+ 			ncMsg = nextCaution;
+ #endif
+ 		}
+ 		else {
+ 			ncMsg = nextMsg;
+ 		}
+ 
+ 		si = stateInfo;
+ 
+ 		*si = (char)(LEN_SD_TOTAL(sd) + 1);
+ 		si++;
+     		memcpy(si, BEG_SD_1ST(sd), LEN_SD_1ST(sd));
+ 		si += LEN_SD_1ST(sd);
+     		memcpy(si, BEG_SD_2ND(sd), LEN_SD_2ND(sd));
+ 		si += LEN_SD_2ND(sd);
+     		memcpy(si, BEG_SD_3RD(sd), LEN_SD_3RD(sd));
+ 		send_nextcode(	authInfo->authreq, ncMsg, strlen(ncMsg),
+ 				stateInfo, LEN_SD_TOTAL(sd), authInfo->fd);
+ 		result = -ACE_NEXT_PASSCODE;
+ 		break;
+ 
+ 	case ACE_NEW_PIN:
+ 		DEBUG("ace_pass NEXT_PIN\r\n");
+ 		send_newpin(
+ 			authInfo->authreq,
+ 			stateInfo, strlen(stateInfo),
+ 			authInfo->fd);
+ 		result = -ACE_NEW_PIN;
+ 		break;
+ 	}
+ 
+ 	memset(sd, 0, sizeof(*sd));
+ 	free(sd);
+ 	return result;
+ }
+ #endif
+ 
+ /*************************************************************************
+  *
+  *	Function: authChapToken
+  *
+  *	Purpose: Process and reply to a CHAP token authentication request
+  *
+  *************************************************************************/
+ 
+ int
+ authChapToken(authInfo)
+ AuthInfo	*authInfo;
+ {
+ 	char	msg[128];
+ 	char	string[AUTH_PASS_LEN + 64];
+ 	char	*ptr;
+ 	u_char	size;
+ 	int	result;
+ 	u_char	*pw_digest = (u_char *)authInfo->pw_digest;
+ 
+ 	DEBUG("authChapToken\r\n");
+ 
+ 	size = authInfo->authPwd->size;
+ 	if( size != AUTH_VECTOR_LEN + 1 ) {
+ 		sprintf(msg,
+ 			"CHAP Token - Bad Pwd Size(%d): user %s, NAS %s\n",
+ 				size, authInfo->authName->strvalue,
+ 				ip_hostname(authInfo->ipaddr));
+ 		log_err(msg);
+ 		DEBUG("%s", msg);
+ 		return -1;
+ 	}
+ 	ptr = string;
+ 	if( authInfo->authState && authInfo->chkSecret ) {
+ #if defined( PWD_DEBUG )
+ 		DEBUG("chkSecret(%s)\r\n", authInfo->chkSecret->strvalue);
+ #endif
+ 		size = authInfo->chkSecret->size - 1;	/* skip final NUL */
+ 		*ptr++ = authInfo->authPwd->strvalue[0];	/* pkt_id */
+ 		memcpy(ptr, authInfo->chkSecret->strvalue, size);
+ 		ptr += size;
+ 		memcpy(ptr, authInfo->vector, AUTH_VECTOR_LEN);
+ 		md5_calc(pw_digest, (u_char *)string,
+ 			1 + AUTH_VECTOR_LEN + size);
+ 		/* shift down to remove the pkt_id */
+ #if defined(OSUN)
+ 		/* sigh... just use the unsafe memcpy ... */
+ 		memcpy(authInfo->authPwd->strvalue,
+ 			&(authInfo->authPwd->strvalue[1]), CHAP_VALUE_LENGTH);
+ #else
+ 		memmove(authInfo->authPwd->strvalue,
+ 			&(authInfo->authPwd->strvalue[1]), CHAP_VALUE_LENGTH);
+ #endif
+ 		authInfo->authPwd->size -= 1;
+ 	}
+ 	else {
+ 		/* authState indicates requestor understands token
+ 		   authentication, and chkSecret is needed to decode
+ 		   the password.  If this request is missing either
+ 		   attribute then it must be rejected.
+ 		*/
+ 		return -1;
+ 	}
+ 
+ 	result = -1;
+ 	if( authInfo->tokExp && (allow_token_caching != 0) ) {
+ 		char *val;	/* the temporary shared password */
+ 		val = (char *)cache_search(cache, authInfo->authName->strvalue,
+ 					authInfo->authName->size);
+ 		if( val && val != ELEM_DELETED ) {
+ 			int	ix;
+ 			int	len;
+ 			int	stat;
+ 			char	*user;
+ 			char	pwd[CHAP_VALUE_LENGTH];
+ 
+ #if defined( PWD_DEBUG )
+ 			DEBUG("Cache val for %s: <%s>\r\n",
+ 				authInfo->authName->strvalue, val);
+ #endif
+ 			memcpy(pwd, authInfo->authPwd->strvalue,
+ 				CHAP_VALUE_LENGTH);
+ 			/* decrypt the given password */
+ 			for( ix = 0; ix < CHAP_VALUE_LENGTH; ix++ ) {
+ 				pwd[ix] ^= authInfo->pw_digest[ix];
+ 			}
+ 			/* see if we got the <password><.><username> format */
+ 			user = strchr(pwd, '.');
+ 			if( user ) {
+ 				*user = '\0';
+ 				user++;
+ 			}
+ 
+ 			len = MAX((int)strlen(val)+1, (int)strlen(pwd)+1);
+ 			len = MIN(len, CHAP_VALUE_LENGTH);
+ #if defined( PWD_DEBUG )
+ 			DEBUG("pwd(%d): %s\r\n", len, pwd);
+ #endif
+ 			stat = memcmp(pwd, val, len);
+ 			if( stat == 0 ) {
+ 				authInfo->cacheAuth = TRUE;
+ 				return stat;	/* authenticated */
+ 			}
+ 		}
+ 		else if( val == ELEM_DELETED ) {
+ 			DEBUG("Cache elem for %s was deleted\r\n",
+ 				authInfo->authName->strvalue);
+ 			if( spawn_flag == 0 ) {
+ #if(1)
+ 				;	/* cache_search() already deleted it */
+ #else
+ 				int stat = cache_delete(cache,
+ 					authInfo->authName->strvalue,
+ 					authInfo->authName->size);
+ 				if( stat != TRUE ) {
+ 					char	buf[128];
+ 
+ 					sprintf(buf, "Err: deleting <%s>\n",
+ 						authInfo->authName->strvalue);
+ 					log_err(buf);
+ 					DEBUG("%s", buf);
+ 				}
+ #endif
+ 			}
+ 			else {	/* child copy deleted,
+ 				   now ask parent to delete */
+ 				CacheMsg	msg;
+ 				int		n = 0;
+ 
+ 				msg.type = CACHE_DELETE;
+ 				memcpy(msg.key,
+ 					authInfo->authName->strvalue,
+ 					authInfo->authName->size);
+ 				while( n != sizeof(msg) ) {
+ 					n += write(wrCachefd, ((char *)&msg)+n,
+ 						sizeof(msg)-n);
+ 				}
+ 			}
+ 		}
+ 		else {
+ 			DEBUG("Cache elem for %s was not found\r\n",
+ 				authInfo->authName->strvalue);
+ 		}
+ 
+ 		/* token cache missed */
+ 		if( 0 ) {
+ 			;	/* because no particular token is guaranteed
+ 					to be supported */
+ 		}
+ #if defined(SAFEWORD)
+ 		/* check for SafeWord Authentication */
+        		else if( strcmp(authInfo->chkPwd->strvalue, EL_PWD) == 0) {
+ 			result = authSafewordPwd(authInfo);
+ 		}
+ #endif
+ #if defined(ACE)
+ 		/* check for Security Dynamics Authentication */
+ 		else if( strcmp(authInfo->chkPwd->strvalue, SD_PWD) == 0) {
+ 			result = authAcePwd(authInfo);
+ 		}
+ #endif
+ 	}
+ 	else {
+ 		/* TOKEN passwords without expiry not supported with CHAP */
+ 		sprintf(msg, "CHAP Token Attempt: user %s, NAS %s\n",
+ 				authInfo->authName->strvalue,
+ 				ip_hostname(authInfo->ipaddr));
+ 		log_err(msg);
+ 		DEBUG("%s", msg);
+ 		result = -1;
+ 	}
+ 	return result;
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: authChapPwd
+  *
+  *	Purpose: Process and reply to a CHAP authentication request
+  *
+  *************************************************************************/
+ 
+ int
+ authChapPwd(authInfo)
+ AuthInfo	*authInfo;
+ {
+ 	char	msg[128];
+ 	char	string[AUTH_PASS_LEN + 64];
+ 	char	*ptr;
+ 	int	result = -1;	/* init to failure */
+ 
+ 	DEBUG("authChapPwd\r\n");
+ 	if( getTokenPwdType(authInfo->chkPwd->strvalue) == PWD_SPECIAL ) {
+ 		result = authChapToken(authInfo);
+ 		if( (allow_token_caching != 0) && (result == 0) ) {
+ 			int	stat;
+ 			int	ix;
+ 			int	len;
+ 			char	clrPwd[CHAP_VALUE_LENGTH];
+ 			char	*user = (char *)NULL;
+ 			time_t	idle;
+ 
+ 			if( authInfo->chkIdle ) {
+ 				idle = authInfo->chkIdle->lvalue;
+ 			}
+ 			else {
+ 				idle = 0;
+ 			}
+ 
+ 			memcpy(clrPwd, authInfo->authPwd->strvalue,
+ 				CHAP_VALUE_LENGTH);
+ 			for( ix = 0; ix < CHAP_VALUE_LENGTH; ix++ ) {
+ 				clrPwd[ix] ^= authInfo->pw_digest[ix];
+ 			}
+ 
+ 			/* see if we got the <password><.><username> format */
+ 			user = strchr(clrPwd, '.');
+ 			if( user ) {
+ 				*user = '\0';	/* skip username */
+ 			}
+ 			len = MIN((int)strlen(clrPwd)+1, CHAP_VALUE_LENGTH);
+ 
+ 			if( authInfo->cacheAuth == TRUE ) {
+ 				/* no cache insert on cache hits */
+ 				if( !idle ) {
+ 					/* no cache update if no idle time */
+ 					return result;
+ 				}
+ 				else if( spawn_flag == 0 ) {
+ 					stat = cache_idle_update(cache,
+ 						authInfo->authName->strvalue,
+ 						authInfo->authName->size,
+ 						idle);
+ 					if( stat != TRUE ) {
+ 						log_err("authChapPwd: update failed\n");
+ 					}
+ 				}
+ 				else {
+ 					int		n = 0;
+ 					CacheMsg	msg;
+ 
+ 					msg.type = CACHE_IDLE_UPDATE;
+ 					memcpy(msg.key,
+ 						authInfo->authName->strvalue,
+ 						authInfo->authName->size);
+ #if(0)
+ 					memcpy(msg.val, clrPwd, len);
+ #endif
+ 					msg.time = 0;
+ 					msg.idle = idle;
+ 					while( n != sizeof(msg) ) {
+ 						n += write(wrCachefd,
+ 							((char *)&msg)+n,
+ 							sizeof(msg)-n);
+ 					}
+ 				}
+ 				return result;
+ 			}
+ 
+ #if defined(PWD_DEBUG)
+ 			DEBUG("clrPwd(%d): %s\r\n", len, clrPwd);
+ #endif
+ 			if( spawn_flag == 0 ) {
+ 				stat = cache_insert(cache,
+ 					authInfo->authName->strvalue,
+ 					authInfo->authName->size,
+ 					clrPwd, len,
+ 					authInfo->tokExpSecs, idle);
+ 				if( stat != TRUE ) {
+ 					log_err("authChapPwd: insert failed\n");
+ 				}
+ 			}
+ 			else {
+ 				int		n = 0;
+ 				CacheMsg	msg;
+ 
+ 				msg.type = CACHE_INSERT;
+ 				memcpy(msg.key,
+ 					authInfo->authName->strvalue,
+ 					authInfo->authName->size);
+ 				memcpy(msg.val, clrPwd, len);
+ 				msg.time = authInfo->tokExpSecs;
+ 				msg.idle = idle;
+ 				while( n != sizeof(msg) ) {
+ 					n += write(wrCachefd, ((char *)&msg)+n,
+ 						sizeof(msg)-n);
+ 				}
+ 			}
+ 		}
+ 	}
+ 	else if( getUnixPwdType(authInfo->chkPwd->strvalue) == PWD_SPECIAL ) {
+ 		/* UNIX passwords not supported with CHAP */
+ 		sprintf(msg, "CHAP Unix Attempt: user %s, NAS %s\n",
+ 				authInfo->authName->strvalue,
+ 				ip_hostname(authInfo->ipaddr));
+ 		log_err(msg);
+ 		DEBUG("%s", msg);
+ 		result = -1;
+ 	}
+ 	else {	/* normal 'static' password */
+ 		int size;
+ 
+ 		/* Use normal MD5 to verify */
+ 		ptr = string;
+ 		size = authInfo->chkPwd->size - 1;	/* skip final NUL */
+ 		*ptr++ = authInfo->authPwd->strvalue[0];	/* pkt_id */
+ 		memcpy(ptr, authInfo->chkPwd->strvalue, size);
+ 		ptr += size;
+ 		memcpy(ptr, authInfo->vector, AUTH_VECTOR_LEN);
+ 		md5_calc((u_char *)authInfo->pw_digest, (u_char *)string,
+ 			1 + AUTH_VECTOR_LEN + size);
+ 		
+ 		/* Compare them */
+ 		if( memcmp(authInfo->pw_digest,
+ 				authInfo->authPwd->strvalue + 1,
+ 				CHAP_VALUE_LENGTH) != 0)
+ 		{
+ 			result = -1;
+ 		}
+ 		else {
+ 			result = 0;
+ 		}
+ 	}
+ 	return result;
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: authPapPwd
+  *
+  *	Purpose: Process and reply to a PAP authentication request
+  *
+  *************************************************************************/
+ 
+ int
+ authPapPwd(authInfo)
+ AuthInfo	*authInfo;
+ {
+ 	int	i;
+ 	char	string[AUTH_PASS_LEN + 1];
+ 	int	result = -1;	/* init to failure */
+ 	int	len;
+ 
+ 	DEBUG("authPapPwd\r\n");
+ 	authInfo->user_msg = (char *)NULL;
+ 
+ 	/* Decrypt the password */
+ 	len = authInfo->authPwd->size;
+ 	if( len > AUTH_PASS_LEN ) {
+ 		char msg[128];
+ 
+ 		sprintf(msg,
+ 			"authPapPwd: from %s, user %s: pwd too long (%d)\n",
+ 			ip_hostname(authInfo->authreq->ipaddr), len);
+ 		log_err(msg);
+ 		len = AUTH_PASS_LEN;
+ 	}
+ 	memcpy(string, authInfo->authPwd->strvalue, len);
+ 	for(i = 0;i < len;i++) {
+ 		string[i] ^= authInfo->pw_digest[i % AUTH_VECTOR_LEN];
+ 	}
+ 	string[len] = '\0';
+ 
+ #if defined( PWD_DEBUG )
+ 	DEBUG("chkPwd->strvalue is %s\r\ndecrypted pwd is %s\r\n",
+ 		authInfo->chkPwd->strvalue, string);
+ #endif
+ 
+ 		/* check for Unix Authentication */
+ 	if( getUnixPwdType(authInfo->chkPwd->strvalue) == PWD_SPECIAL ) {
+ 		if(unix_pass(authInfo->authName->strvalue, string) == 0) {
+ 			result = 0;
+ 		}
+ 	}
+ #if defined(SAFEWORD)
+ 	/* check for SafeWord Authentication */
+        	else if( strcmp(authInfo->chkPwd->strvalue, EL_PWD) == 0) {
+ 		result = authSafewordPwd(authInfo);
+ 	}
+ #endif
+ #if defined(ACE)
+ 	/* check for Security Dynamics Authentication */
+ 	else if( strcmp(authInfo->chkPwd->strvalue, SD_PWD) == 0) {
+ 		if( authInfo->chkImmediate ) {
+ 			/* short-circuit dummy challenge */
+ 			memcpy(authInfo->authState->strvalue,
+ 				ACE_DUMMY_STATE, LEN_ACE_DUMMY_STATE+1);
+ 			authInfo->authState->size = LEN_ACE_DUMMY_STATE+1;
+ 		}
+ 		result = authAcePwd(authInfo);
+ 	}
+ #endif
+ 	/* DEFAULT Password is neither UNIX nor SAFEWORD nor ACE */
+ 	else if(strcmp(authInfo->chkPwd->strvalue, string) == 0) {
+ 		result = 0;
+ 	}
+ 
+ 	return result;
+ }
+ 
+ /*************************************************************************
+  *
   *	Function: rad_authenticate
   *
   *	Purpose: Process and reply to an authentication request
***************
*** 874,1050 ****
   *
   *************************************************************************/
  
  rad_authenticate(authreq, activefd)
  AUTH_REQ	*authreq;
  int		activefd;
  {
- 	VALUE_PAIR	*namepair;
  	VALUE_PAIR	*check_item;
  	VALUE_PAIR	*auth_item;
! 	VALUE_PAIR	*user_check;
! 	VALUE_PAIR	*user_reply;
  	int		result;
! 	char		pw_digest[16];
! 	char		string[128];
! 	int		i;
  	char		msg[128];
  	char		umsg[128];
  	char		*user_msg;
- 	char		*ip_hostname();
  	int		retval;
! 	char		*ptr;
  
  	/* Get the username from the request */
! 	namepair = authreq->request;
! 	while(namepair != (VALUE_PAIR *)NULL) {
! 		if(namepair->attribute == PW_USER_NAME) {
! 			break;
! 		}
! 		namepair = namepair->next;
! 	}
! 	if((namepair == (VALUE_PAIR *)NULL) || 
! 	   (strlen(namepair->strvalue) <= 0)) {
  		sprintf(msg, "Authenticate: from %s - No User Name\n",
  			ip_hostname(authreq->ipaddr));
  		log_err(msg);
! 		pairfree(authreq->request);
! 		memset(authreq, 0, sizeof(AUTH_REQ));
! 		free(authreq);
  		return;
  	}
  
  	/* Verify the client and Calculate the MD5 Password Digest */
! 	if(calc_digest(pw_digest, authreq) != 0) {
  		/* We dont respond when this fails */
  		sprintf(msg, "Authenticate: from %s - Security Breach: %s\n",
! 			ip_hostname(authreq->ipaddr), namepair->strvalue);
  		log_err(msg);
! 		pairfree(authreq->request);
! 		memset(authreq, 0, sizeof(AUTH_REQ));
! 		free(authreq);
  		return;
  	}
  
  	/* Get the user from the database */
! 	if(user_find(namepair->strvalue, &user_check, &user_reply) != 0) {
! 		sprintf(msg, "Authenticate: from %s - Invalid User: %s\n",
! 			ip_hostname(authreq->ipaddr), namepair->strvalue);
  		log_err(msg);
  		send_reject(authreq, (char *)NULL, activefd);
! 		pairfree(authreq->request);
! 		memset(authreq, 0, sizeof(AUTH_REQ));
! 		free(authreq);
  		return;
  	}
  
! 	/* Validate the user */
  
! 	/* Look for matching check items */
! 	result = 0;
! 	user_msg = (char *)NULL;
! 	check_item = user_check;
! 	while(result == 0 && check_item != (VALUE_PAIR *)NULL) {
  
! 		/*
! 		 * Check expiration date if we are doing password aging.
! 		 */
! 		if(check_item->attribute == PW_EXPIRATION) {
! 			/* Has this user's password expired */
! 			retval = pw_expired(check_item->lvalue);
! 			if(retval < 0) {
! 				result = -1;
! 				user_msg = "Password Has Expired\r\n";
! 			}
! 			else {
! 				if(retval > 0) {
! 					sprintf(umsg,
! 					  "Password Will Expire in %d Days\r\n",
! 					  retval);
! 					user_msg = umsg;
! 				}
! 				check_item = check_item->next;
  			}
- 			continue;
  		}
  
  		/*
  		 * Look for the matching attribute in the request.
  		 */
! 		auth_item = authreq->request;
! 		while(auth_item != (VALUE_PAIR *)NULL) {
! 			if(check_item->attribute == auth_item->attribute) {
! 				break;
! 			}
! 			if(check_item->attribute == PW_PASSWORD &&
! 				     auth_item->attribute == PW_CHAP_PASSWORD) {
! 				break;
! 			}
! 
! 			auth_item = auth_item->next;
! 		}
  		if(auth_item == (VALUE_PAIR *)NULL) {
  			result = -1;
! 			continue;
! 		}
! 
! 		/*
! 		 * Special handling for passwords which are encrypted,
! 		 * and sometimes authenticated against the UNIX passwd database.
! 		 * Also they can come using the Three-Way CHAP.
! 		 *
! 		 */
! 		if(check_item->attribute == PW_PASSWORD) {
! 			if(auth_item->attribute == PW_CHAP_PASSWORD) {
! 				/* Use MD5 to verify */
! 				ptr = string;
! 				*ptr++ = *auth_item->strvalue;
! 				strcpy(ptr, check_item->strvalue);
! 				ptr += strlen(check_item->strvalue);
! 				memcpy(ptr, authreq->vector, AUTH_VECTOR_LEN);
! 				md5_calc(pw_digest, string,
! 					1 + CHAP_VALUE_LENGTH +
! 					strlen(check_item->strvalue));
! 				/* Compare them */
! 				if(memcmp(pw_digest, auth_item->strvalue + 1,
! 						CHAP_VALUE_LENGTH) != 0) {
! 					result = -1;
! 				}
! 			}
! 			else {
! 				/* Decrypt the password */
! 				memcpy(string,
! 					auth_item->strvalue, AUTH_PASS_LEN);
! 				for(i = 0;i < AUTH_PASS_LEN;i++) {
! 					string[i] ^= pw_digest[i];
! 				}
! 				string[AUTH_PASS_LEN] = '\0';
! 				/* Test Code for Challenge */
! 				if(strcmp(string, "challenge") == 0) {
! 					send_challenge(authreq, 
! 				"You want me to challenge you??\r\nOkay I will",
! 						"1",activefd);
! 					pairfree(authreq->request);
! 					memset(authreq, 0, sizeof(AUTH_REQ));
! 					free(authreq);
! 					return;
! 				}
! 				if(strcmp(check_item->strvalue, "UNIX") == 0) {
! 					if(unix_pass(namepair->strvalue,
! 								string) != 0) {
! 						result = -1;
! 						user_msg = (char *)NULL;
! 					}
! 				}
! 				else if(strcmp(check_item->strvalue,
! 								string) != 0) {
! 					result = -1;
! 					user_msg = (char *)NULL;
! 				}
! 			}
  		}
  		else {
  			switch(check_item->type) {
- 
  			case PW_TYPE_STRING:
  				if(strcmp(check_item->strvalue,
  						auth_item->strvalue) != 0) {
--- 2331,2668 ----
   *
   *************************************************************************/
  
+ void
  rad_authenticate(authreq, activefd)
  AUTH_REQ	*authreq;
  int		activefd;
  {
  	VALUE_PAIR	*check_item;
  	VALUE_PAIR	*auth_item;
! 	VALUE_PAIR	*authList;
! 	VALUE_PAIR	*checkList;
! 	VALUE_PAIR	*replyList;
! 	VALUE_PAIR	*authName;
! 	VALUE_PAIR	*authPwd;
! 	VALUE_PAIR	*authState;
! 	VALUE_PAIR	*chkPwd;
! 	VALUE_PAIR	*chkImmediate;
! 	VALUE_PAIR	*chkIdle;
! 	VALUE_PAIR	*tokExp;
! 	VALUE_PAIR	*pwdExp;
! 	VALUE_PAIR	*cutCur;
  	int		result;
! 	char		pw_digest[AUTH_VECTOR_LEN];
  	char		msg[128];
  	char		umsg[128];
  	char		*user_msg;
  	int		retval;
! 	PasswordType	passwordType;
! 	int		passwordExpired;
! 	int		tokenExpired;
! 	AuthInfo	authInfo;
! 
! 	DEBUG("rad_authenticate()\r\n");
! 
! 		/* init the info to pass around */
! 	memset(&authInfo, 0, sizeof(authInfo));	/* paranoia */
! 	authInfo.fd		= activefd;
! 	authInfo.authreq	= authreq;
! 	authInfo.ipaddr		= authreq->ipaddr;
! 	authInfo.vector		= authreq->vector;
! 	authInfo.pw_digest	= pw_digest;
! 	authInfo.cacheAuth	= FALSE;
! 	authInfo.cutList	= (VALUE_PAIR *)NULL;
! 	authInfo.user_msg	= (char *)NULL;
! 	authInfo.tokExp		= (VALUE_PAIR *)NULL;
! 	authInfo.chkSecret	= (VALUE_PAIR *)NULL;
! 	authInfo.chkImmediate	= (VALUE_PAIR *)NULL;
! 	authInfo.chkIdle	= (VALUE_PAIR *)NULL;
! 	authInfo.authState	= (VALUE_PAIR *)NULL;
! 	authInfo.tokExpSecs	= (time_t)0;
! 
! 	/*
! 	 * Name Attribute is special:
! 	 *	- Must be present in the auth request
! 	 *	- Must match a name in the users file
! 	 * Password Attribute is special:
! 	 *	- Must be present in the users file record
! 	 *	- Must be present in the auth request as one of:
! 	 *		- PW_PASSWORD
! 	 *		- PW_CHAP_PASSWORD
! 	 *	- If PW_PASSWORD then either:
! 	 *		- static password
! 	 *		- UNIX password
! 	 *		- token password w/o token caching
! 	 *	- Else if PW_CHAP_PASSWORD then either:
! 	 *		- static password
! 	 *		- token password with token caching
! 	 *
! 	 * All other attributes:
! 	 *	- Check the auth request value against the check request value
! 	 *
! 	 * Some check attributes determine what kind of password checking we
! 	 * do rather than being checked against auth request attributes,
! 	 *
! 	 * Some reply attributes specify per-user characteristics rather
! 	 * than being returned to the authentication requestor.
! 	 *
! 	 */
  
  	/* Get the username from the request */
! 	authList = cut_attribute(authreq->request, PW_USER_NAME, &authName);
! 	if((authName == (VALUE_PAIR *)NULL) || 
! 	   ((int)strlen(authName->strvalue) <= 0)) {
  		sprintf(msg, "Authenticate: from %s - No User Name\n",
  			ip_hostname(authreq->ipaddr));
  		log_err(msg);
! 		authCleanup(&authInfo);
  		return;
  	}
+ 	else {
+ 		authInfo.authName = authName;
+ 		authInfo.cutList = authName;
+ 		cutCur = authName;
+ 	}
  
  	/* Verify the client and Calculate the MD5 Password Digest */
! 	if(calc_digest((u_char *)pw_digest, authreq) != 0) {
  		/* We dont respond when this fails */
+ 		DEBUG("rad_auth() calc_digest ret'd error\r\n");
  		sprintf(msg, "Authenticate: from %s - Security Breach: %s\n",
! 			ip_hostname(authreq->ipaddr), authName->strvalue);
  		log_err(msg);
! 		authCleanup(&authInfo);
  		return;
  	}
  
  	/* Get the user from the database */
! 	if( (retval = user_find(authName->strvalue, &checkList, &replyList))
! 	  != 0) {
! 		DEBUG("rad_auth(): user_find(%s) error = %s\r\n",
! 			authName->strvalue, get_errmsg(retval));
! 		sprintf(msg, "Authenticate: from %s - %s: %s\n",
! 			ip_hostname(authreq->ipaddr), get_errmsg(retval),
! 			authName->strvalue);
  		log_err(msg);
  		send_reject(authreq, (char *)NULL, activefd);
! 		authCleanup(&authInfo);
  		return;
  	}
  
! 	/* init the flags - we will check them later */
! 	passwordType = PWD_UNKNOWN;
! 	passwordExpired = FALSE;
! 	tokenExpired = FALSE;
! 
! 	/* start by examining the user record check list:
! 		it MUST have a password entry and MAY have other entries.
! 	*/
! 	checkList = cut_attribute(checkList, PW_PASSWORD, &chkPwd);
! 	if( !chkPwd ) {	/* MUST have password in record! */
! 		sprintf(msg, "Authenticate: from %s - No pwd in record!\n",
! 			ip_hostname(authreq->ipaddr));
! 		log_err(msg);
! 		DEBUG("%s", msg);
! 		send_reject(authreq, (char *)NULL, activefd);
! 		authCleanup(&authInfo);
! 		return;
! 	}
! 	else {
! 		authInfo.chkPwd = chkPwd;
! 		cutCur->next = chkPwd;
! 		cutCur = cutCur->next;
! 	}
! 
! 	checkList = cut_attribute(checkList, ASCEND_PW_EXPIRATION, &pwdExp);
! 	if( pwdExp ) {
! 		VALUE_PAIR *lifeTime;
! 		VALUE_PAIR *warnTime;
! 		UINT4 usr_exp_days = (UINT4)0;
! 		UINT4 usr_warn_days = (UINT4)0;
! 
! 		DEBUG("rad_auth(): check_item: ASCEND_PW_EXPIRATION\r\n");
! 
! 		cutCur->next = pwdExp;
! 		cutCur = cutCur->next;
! 
! 		/* Has this user's password expired */
! 		replyList =
! 			cut_attribute(replyList, ASCEND_PW_LIFETIME, &lifeTime);
! 		if( lifeTime ) {
! 			cutCur->next = lifeTime;
! 			cutCur = cutCur->next;
! 			usr_exp_days = lifeTime->lvalue;
! 		}
! 
! 		replyList =
! 			cut_attribute(replyList, ASCEND_PW_WARNTIME, &warnTime);
! 		if( warnTime ) {
! 			cutCur->next = warnTime;
! 			cutCur = cutCur->next;
! 			usr_warn_days = warnTime->lvalue;
! 		}
! 		retval = pw_expired(pwdExp->lvalue,
! 					usr_exp_days, usr_warn_days);
! 		if(retval < 0) {
! 			passwordExpired = TRUE;
! 			DEBUG("rad_auth(): password has EXPIRED\r\n");
! 		}
! 		else if( retval > 0 ) {
! 			DEBUG("rad_auth(): password WARNING: %d\r\n", retval);
! 			sprintf(umsg,
! 			  	"Password Will Expire in %d Days\r\n", retval);
! 			user_msg = umsg;
! 		}
! 	}
  
! 	authList = cut_attribute(authList, PW_PASSWORD, &authPwd);
! 	if( !authPwd ) {
! 		authList = cut_attribute(authList,
! 					PW_CHAP_PASSWORD, &authPwd);
! 	}
! 	if( !authPwd ) {	/* MUST have received password! */
! 		sprintf(msg, "Authenticate: from %s - No pwd in request!\n",
! 			ip_hostname(authreq->ipaddr));
! 		log_err(msg);
! 		DEBUG("%s", msg);
! 		send_reject(authreq, (char *)NULL, activefd);
! 		authCleanup(&authInfo);
! 		return;
! 	}
! 	else {
! 		authInfo.authPwd = authPwd;
! 		cutCur->next = authPwd;
! 		cutCur = cutCur->next;
! 	}
  
! 	authList = cut_attribute(authList, PW_STATE, &authState);
! 	if( authState ) {
! 		authInfo.authState = authState;
! 		cutCur->next = authState;
! 		cutCur = cutCur->next;
! 	}
! 
! 	/*
! 	 * Check token expiration time if we are doing token caching.
! 	 */
! 	checkList = cut_attribute(checkList, ASCEND_TOKEN_EXPIRY, &tokExp);
! 	if( tokExp ) {
! 		VALUE_PAIR *chkSecret;
! 		char	*sharedRcvSecret;
! 		UINT4	tokExpSecs;
! 
! 		DEBUG("rad_auth(): checkList: ASCEND_TOKEN_EXPIRY = %ld\r\n",
! 			tokExp->lvalue);
! 
! 		authInfo.tokExp = tokExp;
! 		cutCur->next = tokExp;
! 		cutCur = cutCur->next;
! 
! 			/* Paranoia for the masses */
! 		tokExpSecs = (UINT4)0;
! 		sharedRcvSecret = (char *)0;
! 
! 		/* Is token cache expiry correctly specified */
! 		tokExpSecs = tokExp->lvalue * (UINT4)SECONDS_PER_MINUTE;
! 		if( tokExpSecs ) {
! 			replyList = cut_attribute(replyList,
! 						ASCEND_RECV_SECRET, &chkSecret);
! 			if( chkSecret ) {
! 				authInfo.chkSecret = chkSecret;
! 				cutCur->next = chkSecret;
! 				cutCur = cutCur->next;
! 				sharedRcvSecret = chkSecret->strvalue;
  			}
  		}
+ 		if( tokExpSecs && sharedRcvSecret ) {
+ 			authInfo.tokExpSecs = tokExpSecs;
+ 		}
+ 	}
+ 
+ 	checkList = cut_attribute(checkList, ASCEND_TOKEN_IMMEDIATE,
+ 			&chkImmediate);
+ 	if( chkImmediate && (chkImmediate->lvalue == TOK_IMM_YES) ) {
+ 		DEBUG("rad_auth(): checkList: ASCEND_TOKEN_IMMEDIATE = %ld\r\n",
+ 			chkImmediate->lvalue);
+ 		authInfo.chkImmediate = chkImmediate;
+ 		cutCur->next = chkImmediate;
+ 		cutCur = cutCur->next;
+ 	}
+ 
+ 	checkList = cut_attribute(checkList, ASCEND_TOKEN_IDLE, &chkIdle);
+ 	if( chkIdle && (chkIdle->lvalue != 0) ) {
+ 		DEBUG("rad_auth(): checkList: ASCEND_TOKEN_IDLE = %ld\r\n",
+ 			chkIdle->lvalue);
+ 
+ 		chkIdle->lvalue *= SECONDS_PER_MINUTE;
+ 		authInfo.chkIdle = chkIdle;
+ 		cutCur->next = chkIdle;
+ 		cutCur = cutCur->next;
+ 	}
+ 
+ 	/*
+ 	 * Any future special attributes in the auth request should be
+ 	 * dealt with here and gotten from the authList.
+ 	 */
+ 
+ 
+ 	/*
+ 	 * Special handling for passwords which are encrypted,
+ 	 * and sometimes authenticated against the UNIX passwd database.
+ 	 * Also they can come using the Three-Way CHAP.
+ 	 * Or be token passwords.
+ 	 * Or be tokens with caching
+ 	 * Or ...
+ 	 */
+ 	passwordType = getPasswordType(chkPwd->strvalue);
+ 	DEBUG("User record PASSWORD type is %s\r\n",
+ 		(passwordType == PWD_SPECIAL) ? "Special" : "Normal");
+ 
+ 	result = -1;
+ 	if( authPwd->attribute == PW_CHAP_PASSWORD ) {
+ 		result = authChapPwd(&authInfo);
+ 	}
+ 	else if( authPwd->attribute == PW_PASSWORD ) {
+ 		result = authPapPwd(&authInfo);
+ 	}
+ 
+ 	/*
+ 	 * At this point all of the special attributes have been checked.
+ 	 * A result of 0 means that they have been satisfied; negative
+ 	 * result means failure, positive means special handling.
+ 	 */
+ 	if( result < 0 ) {	/* auth failure */
+ 		send_reject(authreq, authInfo.user_msg, activefd);
+ 		authCleanup(&authInfo);
+ 		return;
+ 	}
+ 	else if( result > 0 ) {	/* token stuff; neither pass nor fail */
+ 		authCleanup(&authInfo);
+ 		return;
+ 	}
  
+ 	/*
+ 	 * Look for the remaining matching check items
+ 	 */
+ 	user_msg = (char *)NULL;
+ 	check_item = checkList;
+ 	result = 0;
+ 	while(result == 0 && check_item != (VALUE_PAIR *)NULL) {
  		/*
  		 * Look for the matching attribute in the request.
  		 */
! 		auth_item = authList;
! 		authList = cut_attribute(authList,
! 					check_item->attribute,
! 					&auth_item);
  		if(auth_item == (VALUE_PAIR *)NULL) {
  			result = -1;
! 			break;
  		}
  		else {
+ 			cutCur->next = auth_item;
+ 			cutCur = cutCur->next;
  			switch(check_item->type) {
  			case PW_TYPE_STRING:
  				if(strcmp(check_item->strvalue,
  						auth_item->strvalue) != 0) {
***************
*** 1066,1083 ****
  		}
  		check_item = check_item->next;
  	}
  	if(result != 0) {
  		send_reject(authreq, user_msg, activefd);
  	}
! 	else {
! 		send_accept(authreq, user_reply, user_msg, activefd);
  	}
! 	pairfree(authreq->request);
! 	memset(authreq, 0, sizeof(AUTH_REQ));
! 	free(authreq);
! 	pairfree(user_check);
! 	pairfree(user_reply);
! 	return;
  }
  
  /*************************************************************************
--- 2684,2725 ----
  		}
  		check_item = check_item->next;
  	}
+ 
  	if(result != 0) {
  		send_reject(authreq, user_msg, activefd);
  	}
! 	else {	/* everything ok, except that the password may have expired */
! 		if( passwordExpired != FALSE ) {	/* pwd is too old */
! 			/* require that:
! 			 *	- password changing is allowed
! 			 *	- the expired pwd was given
! 			 */
! 		    if( allow_passchange == TRUE ) {
! 			switch( passwordType ) {
! 			default:
! 			case PWD_UNKNOWN:
! 			case PWD_SPECIAL:
! 				user_msg = "Password Has Expired\r\n";
! 				send_reject(authreq, user_msg, activefd);
! 				break;
! 			case PWD_NORMAL:
! 				user_msg = "Password Has Expired\r\n";
! 				send_pwexpired(authreq, user_msg, activefd);
! 				break;
! 			}
! 		    }
! 		    else {
! 			user_msg = "Password Has Expired\r\n";
! 			send_reject(authreq, user_msg, activefd);
! 		    }
! 		}
! 		else {
! 			send_accept(authreq, replyList, user_msg, activefd);
! 		}
  	}
! 	authCleanup(&authInfo);
! 	pairfree(checkList);
! 	pairfree(replyList);
  }
  
  /*************************************************************************
***************
*** 1089,1094 ****
--- 2731,2737 ----
   *
   *************************************************************************/
  
+ void
  send_reject(authreq, msg, activefd)
  AUTH_REQ	*authreq;
  char		*msg;
***************
*** 1097,1103 ****
  	AUTH_HDR		*auth;
  	struct	sockaddr	saremote;
  	struct	sockaddr_in	*sin;
- 	char			*ip_hostname();
  	char			digest[AUTH_VECTOR_LEN];
  	int			secretlen;
  	int			total_length;
--- 2740,2745 ----
***************
*** 1134,1142 ****
  	auth->length = htons(total_length);
  
  	/* Calculate the response digest */
! 	secretlen = strlen(authreq->secret);
  	memcpy(send_buffer + total_length, authreq->secret, secretlen);
! 	md5_calc(digest, (char *)auth, total_length + secretlen);
  	memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
  	memset(send_buffer + total_length, 0, secretlen);
  
--- 2776,2784 ----
  	auth->length = htons(total_length);
  
  	/* Calculate the response digest */
! 	secretlen = strlen((char *)authreq->secret);
  	memcpy(send_buffer + total_length, authreq->secret, secretlen);
! 	md5_calc((u_char *)digest, (u_char *)auth, total_length + secretlen);
  	memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
  	memset(send_buffer + total_length, 0, secretlen);
  
***************
*** 1146,1158 ****
  	sin->sin_addr.s_addr = htonl(authreq->ipaddr);
  	sin->sin_port = htons(authreq->udp_port);
  
! 	DEBUG("Sending Reject of id %d to %lx (%s)\n",
  		authreq->id, (u_long)authreq->ipaddr,
  		ip_hostname(authreq->ipaddr));
  	
  	/* Send it to the user */
  	sendto(activefd, (char *)auth, (int)total_length, (int)0,
! 			(struct sockaddr *) &saremote, sizeof(struct sockaddr_in));
  }
  
  /*************************************************************************
--- 2788,2800 ----
  	sin->sin_addr.s_addr = htonl(authreq->ipaddr);
  	sin->sin_port = htons(authreq->udp_port);
  
! 	DEBUG("Sending Reject of id %d to %lx (%s)\r\n",
  		authreq->id, (u_long)authreq->ipaddr,
  		ip_hostname(authreq->ipaddr));
  	
  	/* Send it to the user */
  	sendto(activefd, (char *)auth, (int)total_length, (int)0,
! 		(struct sockaddr *) &saremote, sizeof(struct sockaddr_in));
  }
  
  /*************************************************************************
***************
*** 1164,1223 ****
   *
   *************************************************************************/
  
! send_challenge(authreq, msg, state, activefd)
  AUTH_REQ	*authreq;
  char		*msg;
  char		*state;
  int		activefd;
  {
  	AUTH_HDR		*auth;
  	struct	sockaddr_in	saremote;
  	struct	sockaddr_in	*sin;
- 	char			*ip_hostname();
  	char			digest[AUTH_VECTOR_LEN];
  	int			secretlen;
  	int			total_length;
  	u_char			*ptr;
- 	int			len;
  
  	auth = (AUTH_HDR *)send_buffer;
  
  	/* Build standard response header */
  	auth->code = PW_ACCESS_CHALLENGE;
  	auth->id = authreq->id;
  	memcpy(auth->vector, authreq->vector, AUTH_VECTOR_LEN);
  	total_length = AUTH_HDR_LEN;
  
! 	/* Append the user message */
! 	if(msg != (char *)NULL) {
! 		len = strlen(msg);
! 		if(len > 0 && len < AUTH_STRING_LEN) {
! 			ptr = auth->data;
! 			*ptr++ = PW_PORT_MESSAGE;
! 			*ptr++ = len + 2;
! 			memcpy(ptr, msg, len);
! 			ptr += len;
! 			total_length += len + 2;
  		}
  	}
  
  	/* Append the state info */
! 	if((state != (char *)NULL) && (strlen(state) > 0)) {
! 		len = strlen(state);
  		*ptr++ = PW_STATE;
! 		*ptr++ = len + 2;
! 		memcpy(ptr, state, len);
! 		ptr += len;
! 		total_length += len + 2;
  	}
  
  	/* Set total length in the header */
  	auth->length = htons(total_length);
  
  	/* Calculate the response digest */
! 	secretlen = strlen(authreq->secret);
  	memcpy(send_buffer + total_length, authreq->secret, secretlen);
! 	md5_calc(digest, (char *)auth, total_length + secretlen);
  	memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
  	memset(send_buffer + total_length, 0, secretlen);
  
--- 2806,2887 ----
   *
   *************************************************************************/
  
! void
! send_challenge(authreq, msg, msgLen, state, stateLen, activefd)
  AUTH_REQ	*authreq;
  char		*msg;
+ int		msgLen;
  char		*state;
+ int		stateLen;
  int		activefd;
  {
  	AUTH_HDR		*auth;
  	struct	sockaddr_in	saremote;
  	struct	sockaddr_in	*sin;
  	char			digest[AUTH_VECTOR_LEN];
  	int			secretlen;
  	int			total_length;
  	u_char			*ptr;
  
  	auth = (AUTH_HDR *)send_buffer;
  
+ 	DEBUG("Entering send_challenge()\r\n");
+ 
  	/* Build standard response header */
  	auth->code = PW_ACCESS_CHALLENGE;
  	auth->id = authreq->id;
  	memcpy(auth->vector, authreq->vector, AUTH_VECTOR_LEN);
  	total_length = AUTH_HDR_LEN;
+ 	ptr = auth->data;
  
! 	/* Append the challenge */
! 	if( msgLen < AUTH_STRING_LEN ) {
! 		DEBUG("...Adding challenge, len=%d\r\n", msgLen);
! 		*ptr++ = PW_PORT_MESSAGE;
! 		*ptr++ = msgLen + 2;
! 		memcpy(ptr, msg, msgLen);
! 		if( debug_flag == 1 ) {
! 			int	i;
! 			printf("challenge before encrypt:\r\n");
! 			for( i = 0; i < msgLen; i++ ) {
! 				printf("%c ", ptr[i]);
! 			}
! 			printf("\r\n");
  		}
+ 		ptr += msgLen;
+ 		total_length += msgLen + 2;
  	}
  
  	/* Append the state info */
! 	if( state != (char *)NULL ) {
! 		DEBUG("...Adding state, len=%d\r\n", stateLen);
  		*ptr++ = PW_STATE;
! 		*ptr++ = stateLen + 2;
! 		memcpy(ptr, state, stateLen);
! 		ptr += stateLen;
! 		total_length += stateLen + 2;
  	}
  
  	/* Set total length in the header */
  	auth->length = htons(total_length);
  
+ 	DEBUG("send_chall(), auth->length = %d\r\n", total_length);
+ 
  	/* Calculate the response digest */
! 	secretlen = strlen((char *)authreq->secret);
  	memcpy(send_buffer + total_length, authreq->secret, secretlen);
! 
! 	if( debug_flag == 1 ) {
! 	    int	i;
! 
! 	    printf("sendBuf before encrypt:\r\n");
! 	    for( i = 0; i < total_length+secretlen; i++ ) {
! 		printf("%x ", (u_char)(send_buffer[i]));
! 	    }
! 	    printf("\r\n");
! 	}
! 
! 	md5_calc((u_char *)digest, (u_char *)auth, total_length + secretlen);
  	memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
  	memset(send_buffer + total_length, 0, secretlen);
  
***************
*** 1227,1239 ****
  	sin->sin_addr.s_addr = htonl(authreq->ipaddr);
  	sin->sin_port = htons(authreq->udp_port);
  
! 	DEBUG("Sending Challenge of id %d to %lx (%s)\n",
  		authreq->id, (u_long)authreq->ipaddr,
  		ip_hostname(authreq->ipaddr));
  	
  	/* Send it to the user */
  	sendto(activefd, (char *)auth, (int)total_length, (int)0,
! 			(struct sockaddr *) &saremote, sizeof(struct sockaddr_in));
  }
  
  /*************************************************************************
--- 2891,2903 ----
  	sin->sin_addr.s_addr = htonl(authreq->ipaddr);
  	sin->sin_port = htons(authreq->udp_port);
  
! 	DEBUG("Sending Challenge of id %d to %lx (%s)\r\n",
  		authreq->id, (u_long)authreq->ipaddr,
  		ip_hostname(authreq->ipaddr));
  	
  	/* Send it to the user */
  	sendto(activefd, (char *)auth, (int)total_length, (int)0,
! 	       (struct sockaddr *) &saremote, sizeof(struct sockaddr_in));
  }
  
  /*************************************************************************
***************
*** 1245,1250 ****
--- 2909,2915 ----
   *
   *************************************************************************/
  
+ void
  send_pwack(authreq, activefd)
  AUTH_REQ	*authreq;
  int		activefd;
***************
*** 1252,1258 ****
  	AUTH_HDR		*auth;
  	struct	sockaddr	saremote;
  	struct	sockaddr_in	*sin;
- 	char			*ip_hostname();
  	char			digest[AUTH_VECTOR_LEN];
  	int			secretlen;
  
--- 2917,2922 ----
***************
*** 1265,1273 ****
  	auth->length = htons(AUTH_HDR_LEN);
  
  	/* Calculate the response digest */
! 	secretlen = strlen(authreq->secret);
  	memcpy(send_buffer + AUTH_HDR_LEN, authreq->secret, secretlen);
! 	md5_calc(digest, (char *)auth, AUTH_HDR_LEN + secretlen);
  	memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
  	memset(send_buffer + AUTH_HDR_LEN, 0, secretlen);
  
--- 2929,2937 ----
  	auth->length = htons(AUTH_HDR_LEN);
  
  	/* Calculate the response digest */
! 	secretlen = strlen((char *)authreq->secret);
  	memcpy(send_buffer + AUTH_HDR_LEN, authreq->secret, secretlen);
! 	md5_calc((u_char *)digest, (u_char *)auth, AUTH_HDR_LEN + secretlen);
  	memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
  	memset(send_buffer + AUTH_HDR_LEN, 0, secretlen);
  
***************
*** 1277,1283 ****
  	sin->sin_addr.s_addr = htonl(authreq->ipaddr);
  	sin->sin_port = htons(authreq->udp_port);
  
! 	DEBUG("Sending PW Ack of id %d to %lx (%s)\n",
  		authreq->id, (u_long)authreq->ipaddr,
  		ip_hostname(authreq->ipaddr));
  	
--- 2941,2947 ----
  	sin->sin_addr.s_addr = htonl(authreq->ipaddr);
  	sin->sin_port = htons(authreq->udp_port);
  
! 	DEBUG("Sending PW Ack of id %d to %lx (%s)\r\n",
  		authreq->id, (u_long)authreq->ipaddr,
  		ip_hostname(authreq->ipaddr));
  	
***************
*** 1288,1293 ****
--- 2952,3062 ----
  
  /*************************************************************************
   *
+  *	Function: send_pwexpired
+  *
+  *	Purpose: Reply to the request with a PW_PASSWORD_EXPIRED
+  *
+  *************************************************************************/
+ 
+ void
+ send_pwexpired(authreq, msg, activefd)
+ AUTH_REQ	*authreq;
+ char		*msg;
+ int		activefd;
+ {
+ 	AUTH_HDR		*auth;
+ 	struct	sockaddr	saremote;
+ 	struct	sockaddr_in	*sin;
+ 	char			digest[AUTH_VECTOR_LEN];
+ 	int			secretlen;
+ 	int			total_length;
+ 	u_char			*ptr;
+ 
+ 	auth = (AUTH_HDR *)send_buffer;
+ 
+ 	/* Build standard response header */
+ 	auth->code = PW_PASSWORD_EXPIRED;
+ 	auth->id = authreq->id;
+ 	memcpy(auth->vector, authreq->vector, AUTH_VECTOR_LEN);
+ 
+ 	total_length = AUTH_HDR_LEN;
+ 	ptr = auth->data;
+ 
+ 	/* Append the user message */
+ 	if(msg != (char *)NULL) {
+ 		int len = strlen(msg);
+ 		if(len > 0 && len < AUTH_STRING_LEN) {
+ 			*ptr++ = PW_PORT_MESSAGE;
+ 			*ptr++ = len + 2;
+ 			memcpy(ptr, msg, len);
+ 			ptr += len;
+ 			total_length += len + 2;
+ 		}
+ 	}
+ 
+ 	auth->length = htons(total_length);
+ 
+ 	/* Calculate the response digest */
+ 	secretlen = strlen((CONST char *)authreq->secret);	/* ALWAYS 0 */
+ 	memcpy(send_buffer + total_length, authreq->secret, secretlen);
+ 	md5_calc((u_char *)digest, (u_char *)auth, total_length + secretlen);
+ 	memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
+ 	memset(send_buffer + total_length, 0, secretlen);
+ 
+ 	sin = (struct sockaddr_in *) &saremote;
+ 	memset ((char *) sin, '\0', sizeof (saremote));
+ 	sin->sin_family = AF_INET;
+ 	sin->sin_addr.s_addr = htonl(authreq->ipaddr);
+ 	sin->sin_port = htons(authreq->udp_port);
+ 
+ 	DEBUG("Sending PW Expired of id %d to %lx (%s)\r\n",
+ 		authreq->id, (u_long)authreq->ipaddr,
+ 		ip_hostname(authreq->ipaddr));
+ 	
+ 	/* Send it to the user */
+ 	sendto(activefd, (char *)auth, (int)total_length, (int)0,
+ 			&saremote, sizeof(struct sockaddr_in));
+ }
+ 
+ #if defined( ASCEND_SECRET )
+ 
+ /*************************************************************************
+  *
+  *	Function: make_secret
+  *
+  *	Purpose: Build an encrypted secret value to return in a reply
+  *		 packet.  The secret is hidden by xoring with a MD5 digest
+  *		 created from the shared secret and the authentication
+  *		 vector.  We put them into MD5 in the reverse order from
+  *		 that used when encrypting passwords to RADIUS.
+  *
+  *************************************************************************/
+ 
+ void
+ make_secret(digest, vector, secret, value)
+ u_char	*digest;
+ u_char	*vector;
+ u_char	*secret;
+ char	*value;
+ {
+     u_char	buffer[ AUTH_STRING_LEN ];
+     int		secretLen = strlen( (CONST char *)secret );
+     int		ix;
+ 
+     memcpy( buffer, vector, AUTH_VECTOR_LEN );
+     memcpy( buffer + AUTH_VECTOR_LEN, secret, secretLen );
+     md5_calc( digest, buffer, AUTH_VECTOR_LEN + secretLen );
+     memset( buffer, 0, AUTH_STRING_LEN );
+     for ( ix = 0; ix < AUTH_VECTOR_LEN; ix += 1 ) {
+ 	digest[ ix ] ^= value[ ix ];
+     }
+ }
+ 
+ #endif /* ASCEND_SECRET */
+ 
+ 
+ /*************************************************************************
+  *
   *	Function: send_accept
   *
   *	Purpose: Reply to the request with an ACKNOWLEDGE.  Also attach
***************
*** 1295,1300 ****
--- 3064,3070 ----
   *
   *************************************************************************/
  
+ void
  send_accept(authreq, reply, msg, activefd)
  AUTH_REQ	*authreq;
  VALUE_PAIR	*reply;
***************
*** 1308,1316 ****
  	u_char			*ptr;
  	int			len;
  	UINT4			lvalue;
! 	u_char			digest[16];
  	int			secretlen;
- 	char			*ip_hostname();
  
  	auth = (AUTH_HDR *)send_buffer;
  
--- 3078,3085 ----
  	u_char			*ptr;
  	int			len;
  	UINT4			lvalue;
! 	u_char			digest[AUTH_VECTOR_LEN];
  	int			secretlen;
  
  	auth = (AUTH_HDR *)send_buffer;
  
***************
*** 1319,1325 ****
  	auth->id = authreq->id;
  	memcpy(auth->vector, authreq->vector, AUTH_VECTOR_LEN);
  
! 	DEBUG("Sending Ack of id %d to %lx (%s)\n",
  		authreq->id, (u_long)authreq->ipaddr,
  		ip_hostname(authreq->ipaddr));
  
--- 3088,3094 ----
  	auth->id = authreq->id;
  	memcpy(auth->vector, authreq->vector, AUTH_VECTOR_LEN);
  
! 	DEBUG("Sending Ack of id %d to %lx (%s)\r\n",
  		authreq->id, (u_long)authreq->ipaddr,
  		ip_hostname(authreq->ipaddr));
  
***************
*** 1329,1339 ****
--- 3098,3129 ----
  	ptr = auth->data;
  	while(reply != (VALUE_PAIR *)NULL) {
  		debug_pair(stdout, reply);
+ 
+ 		/* not all reply attributes are sent to requestor */
+ 		switch( reply->attribute ) {
+ 		case ASCEND_PW_WARNTIME:
+ 		case ASCEND_PW_LIFETIME:
+ 			reply = reply->next;
+ 			continue;
+ 		}
+ 
  		*ptr++ = reply->attribute;
  
  		switch(reply->type) {
  
  		case PW_TYPE_STRING:
+ #if defined( ASCEND_SECRET )
+ 			if (( reply->attribute == ASCEND_SEND_SECRET ) ||
+ 			    ( reply->attribute == ASCEND_RECV_SECRET )) {
+ 				make_secret( digest, authreq->vector,
+ 					     authreq->secret, reply->strvalue );
+ 				*ptr++ = AUTH_VECTOR_LEN + 2;
+ 				memcpy( ptr, digest, AUTH_VECTOR_LEN );
+ 				ptr += AUTH_VECTOR_LEN;
+ 				total_length += AUTH_VECTOR_LEN + 2;
+ 				break;
+ 			}
+ #endif
  			len = strlen(reply->strvalue);
  			if (len >= AUTH_STRING_LEN) {
  				len = AUTH_STRING_LEN - 1;
***************
*** 1353,1358 ****
--- 3143,3161 ----
  			total_length += sizeof(UINT4) + 2;
  			break;
  
+ #if defined( BINARY_FILTERS )
+ 		case PW_TYPE_FILTER_BINARY:
+ 
+ 			/* The binary representation of the filter is in
+ 			   reply->strvalue.  It's length is in reply->lvalue */
+ 
+ 			*ptr++ = reply->lvalue + 2;
+ 			memcpy( ptr, reply->strvalue, reply->lvalue );
+ 			ptr += reply->lvalue;
+ 			total_length += reply->lvalue + 2;
+ 			break;
+ #endif /* BINARY_FILTERS */
+ 
  		default:
  			break;
  		}
***************
*** 1375,1383 ****
  	auth->length = htons(total_length);
  
  	/* Append secret and calculate the response digest */
! 	secretlen = strlen(authreq->secret);
  	memcpy(send_buffer + total_length, authreq->secret, secretlen);
! 	md5_calc(digest, (char *)auth, total_length + secretlen);
  	memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
  	memset(send_buffer + total_length, 0, secretlen);
  
--- 3178,3186 ----
  	auth->length = htons(total_length);
  
  	/* Append secret and calculate the response digest */
! 	secretlen = strlen((char *)authreq->secret);
  	memcpy(send_buffer + total_length, authreq->secret, secretlen);
! 	md5_calc((u_char *)digest, (u_char *)auth, total_length + secretlen);
  	memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
  	memset(send_buffer + total_length, 0, secretlen);
  
***************
*** 1401,1414 ****
   *
   *************************************************************************/
  
  unix_pass(name, passwd)
  char	*name;
  char	*passwd;
  {
  	struct passwd	*pwd;
- 	struct passwd	*getpwnam();
  	char		*encpw;
- 	char		*crypt();
  	char		*encrypted_pass;
  #if !defined(NOSHADOW)
  #if defined(M_UNIX)
--- 3204,3216 ----
   *
   *************************************************************************/
  
+ int
  unix_pass(name, passwd)
  char	*name;
  char	*passwd;
  {
  	struct passwd	*pwd;
  	char		*encpw;
  	char		*encrypted_pass;
  #if !defined(NOSHADOW)
  #if defined(M_UNIX)
***************
*** 1420,1426 ****
  	
  	/* Get encrypted password from password file */
  	if((pwd = getpwnam(name)) == NULL) {
! 		return(-1);
  	}
  
  	encrypted_pass = pwd->pw_passwd;
--- 3222,3228 ----
  	
  	/* Get encrypted password from password file */
  	if((pwd = getpwnam(name)) == NULL) {
! 		return UNIX_GETPWNAME_ERR;
  	}
  
  	encrypted_pass = pwd->pw_passwd;
***************
*** 1428,1434 ****
  #if !defined(NOSHADOW)
  	if(strcmp(pwd->pw_passwd, "x") == 0) {
  		if((spwd = getspnam(name)) == NULL) {
! 			return(-1);
  		}
  #if defined(M_UNIX)
  		encrypted_pass = spwd->pw_passwd;
--- 3230,3236 ----
  #if !defined(NOSHADOW)
  	if(strcmp(pwd->pw_passwd, "x") == 0) {
  		if((spwd = getspnam(name)) == NULL) {
! 			return UNIX_GETSHDWNAME_ERR;
  		}
  #if defined(M_UNIX)
  		encrypted_pass = spwd->pw_passwd;
***************
*** 1439,1449 ****
  #endif	/* !NOSHADOW */
  
  	/* Run encryption algorythm */
! 	encpw = crypt(passwd, encrypted_pass);
! 
  	/* Check it */
  	if(strcmp(encpw, encrypted_pass)) {
! 		return(-1);
  	}
  	return(0);
  }
--- 3241,3254 ----
  #endif	/* !NOSHADOW */
  
  	/* Run encryption algorythm */
! #if defined(SOLARIS)
! 	encpw = crypt((CONST char *)passwd, (CONST char *)encrypted_pass);
! #else
! 	encpw = crypt((u_char *)passwd, (u_char *)encrypted_pass);
! #endif
  	/* Check it */
  	if(strcmp(encpw, encrypted_pass)) {
! 		return UNIX_BAD_PASSWORD;
  	}
  	return(0);
  }
***************
*** 1450,1455 ****
--- 3255,3323 ----
  
  /*************************************************************************
   *
+  *	Function: get_client_info
+  *
+  *	Purpose: Return the IP address and secret of the given host
+  *
+  *	Input:	 rqstIpAddr
+  *
+  *	Returns: If rqstIpAddr match
+  *			set IP addr, hostname, and secret
+  *			return 0;
+  *		 else
+  *			set IP addr = 0
+  *			return error code
+  *
+  *************************************************************************/
+ 
+ int
+ get_client_info(rqstIpAddr, ipaddr, secret, hostnm)
+ UINT4	rqstIpAddr;
+ UINT4	*ipaddr;
+ u_char	*secret;
+ char	*hostnm;
+ {
+ 	FILE	*clientfd;
+ 	u_char	buf[1024];
+ 
+ 	*ipaddr = (UINT4)0;
+ 	secret[0] = hostnm[0] = '\0';
+ 
+ 	/* Find the client in the database */
+ 	sprintf((char *)buf, "%s/%s", radius_dir, RADIUS_CLIENTS);
+ 	if((clientfd = fopen((CONST char *)buf, "r")) == (FILE *)NULL) {
+ 		int error = errno;
+ 		fprintf(stderr,
+ 			"%s: err(%d): Couldn't open %s to find client\n",
+ 				progname, error, buf);
+ 		return CLIENTFILE_READ_ERR;
+ 	}
+ 	while(fgets((char *)buf, sizeof(buf), clientfd) != (char *)NULL) {
+ 		if(*buf == '#') {
+ 			continue;
+ 		}
+ 		if(sscanf((CONST char *)buf, "%s%s", hostnm, secret) != 2) {
+ 			continue;
+ 		}
+ 
+ 		/*
+ 		 * Validate the requesting IP address -
+ 		 * Not secure, but worth the check for accidental requests
+ 		 */
+ 		*ipaddr = get_ipaddr(hostnm);
+ 		if(*ipaddr == rqstIpAddr) {
+ 			break;
+ 		}
+ 		*ipaddr = (UINT4)0;
+ 		secret[0] = hostnm[0] = '\0';
+ 	}
+ 	fclose(clientfd);
+ 
+ 	return (*ipaddr) ? 0 : WRONG_NAS_ADDR;
+ }
+ 
+ /*************************************************************************
+  *
   *	Function: calc_digest
   *
   *	Purpose: Validates the requesting client NAS.  Calculates the
***************
*** 1458,1520 ****
   *
   *************************************************************************/
  
  calc_digest(digest, authreq)
  u_char		*digest;
  AUTH_REQ	*authreq;
  {
! 	FILE	*clientfd;
! 	u_char	buffer[128];
! 	u_char	secret[64];
  	char	hostnm[256];
  	char	msg[128];
- 	char	*ip_hostname();
  	int	secretlen;
  	UINT4	ipaddr;
! 	UINT4	get_ipaddr();
  
! 	/* Find the client in the database */
! 	sprintf(buffer, "%s/%s", radius_dir, RADIUS_CLIENTS);
! 	if((clientfd = fopen(buffer, "r")) == (FILE *)NULL) {
! 		fprintf(stderr, "%s: couldn't open %s to find clients\n",
! 				progname, buffer);
! 		return(-1);
! 	}
! 	ipaddr = (UINT4)0;
! 	while(fgets(buffer, sizeof(buffer), clientfd) != (char *)NULL) {
! 		if(*buffer == '#') {
! 			continue;
! 		}
! 		if(sscanf(buffer, "%s%s", hostnm, secret) != 2) {
! 			continue;
! 		}
! 		ipaddr = get_ipaddr(hostnm);
! 		if(ipaddr == authreq->ipaddr) {
! 			break;
! 		}
! 	}
! 	fclose(clientfd);
  	memset(buffer, 0, sizeof(buffer));
! 
! 	/*
! 	 * Validate the requesting IP address -
! 	 * Not secure, but worth the check for accidental requests
! 	 */
! 	if(ipaddr != authreq->ipaddr) {
! 		strcpy(hostnm,ip_hostname(ipaddr));
! 		sprintf(msg, "requester address mismatch: %s != %s\n",
! 			hostnm,
! 			ip_hostname(authreq->ipaddr));
  		log_err(msg);
  		memset(secret, 0, sizeof(secret));
! 		return(-1);
  	}
  
  	/* Use the secret to setup the decryption digest */
! 	secretlen = strlen(secret);
! 	strcpy(buffer, secret);
! 	memcpy(buffer + secretlen, authreq->vector, AUTH_VECTOR_LEN);
! 	md5_calc(digest, buffer, secretlen + AUTH_VECTOR_LEN);
! 	strcpy(authreq->secret, secret);
  	memset(buffer, 0, sizeof(buffer));
  	memset(secret, 0, sizeof(secret));
  	return(0);
--- 3326,3362 ----
   *
   *************************************************************************/
  
+ int
  calc_digest(digest, authreq)
  u_char		*digest;
  AUTH_REQ	*authreq;
  {
! 	u_char	buffer[512];
! 	u_char	secret[256];
  	char	hostnm[256];
  	char	msg[128];
  	int	secretlen;
  	UINT4	ipaddr;
! 	int	stat;
  
! 	stat = get_client_info( authreq->ipaddr, &ipaddr, secret, hostnm );
  	memset(buffer, 0, sizeof(buffer));
! 	if( stat != 0 ) {
! 		sprintf(msg, "Calc_digest: from %s, ID %d : %s\n",
! 			ip_hostname(authreq->ipaddr),
! 			authreq->id, get_errmsg(stat));
  		log_err(msg);
  		memset(secret, 0, sizeof(secret));
! 		return stat;
  	}
  
  	/* Use the secret to setup the decryption digest */
! 	secretlen = strlen((char *)secret);
! 	strcpy((char *)buffer, (char *)secret);
! 	memcpy((char *)(buffer + secretlen), (char *)authreq->vector,
! 		AUTH_VECTOR_LEN);
! 	md5_calc((u_char *)digest, buffer, secretlen + AUTH_VECTOR_LEN);
! 	strcpy((char *)authreq->secret, (char *)secret);
  	memset(buffer, 0, sizeof(buffer));
  	memset(secret, 0, sizeof(secret));
  	return(0);
***************
*** 1528,1533 ****
--- 3370,3376 ----
   *
   *************************************************************************/
  
+ void
  debug_pair(fd, pair)
  FILE		*fd;
  VALUE_PAIR	*pair;
***************
*** 1547,1555 ****
   *
   *************************************************************************/
  
  usage()
  {
! 	fprintf(stderr, "Usage: %s [ -a acct_dir ] [ -s ] [ -x ] [ -d db_dir ]\n",progname);
  	exit(-1);
  }
  
--- 3390,3401 ----
   *
   *************************************************************************/
  
+ static void
  usage()
  {
! 	fprintf(errf,
! 		"Usage: %s [ -a acct_dir ] [ -c ] [ -d db_dir ] [ -p ]\n\t[ -s ] [ -u db_file ] [ -v ] [ -w ] [ -x ] [ -A none|services|incr ]\n",
! 			progname);
  	exit(-1);
  }
  
***************
*** 1562,1567 ****
--- 3408,3414 ----
   *
   *************************************************************************/
  
+ int
  log_err(msg)
  char	*msg;
  {
***************
*** 1571,1579 ****
  
  	sprintf(buffer, "%s/%s", radius_dir, RADIUS_LOG);
  	if((msgfd = fopen(buffer, "a")) == (FILE *)NULL) {
! 		fprintf(stderr, "%s:Couldn't open %s for logging\n",
! 				progname, buffer);
! 		return(-1);
  	}
  	timeval = time(0);
  	fprintf(msgfd, "%-24.24s: %s", ctime(&timeval), msg);
--- 3418,3428 ----
  
  	sprintf(buffer, "%s/%s", radius_dir, RADIUS_LOG);
  	if((msgfd = fopen(buffer, "a")) == (FILE *)NULL) {
! 		int error = errno;
! 		fprintf(errf,
! 			"%s: err(%d): Couldn't open %s for logging\n",
! 				progname, error, buffer);
! 		return LOGFILE_APPEND_ERR;
  	}
  	timeval = time(0);
  	fprintf(msgfd, "%-24.24s: %s", ctime(&timeval), msg);
***************
*** 1590,1621 ****
   *		 expiration_seconds - When updating a user password,
   *			the amount of time to add to the current time
   *			to set the time when the password will expire.
!  *			This is stored as the VALUE Password-Expiration
   *			in the dictionary as number of days.
   *
   *		warning_seconds - When acknowledging a user authentication
   *			time remaining for valid password to notify user
   *			of password expiration.
   *
   *************************************************************************/
  
  config_init()
  {
  	DICT_VALUE	*dval;
- 	DICT_VALUE	*dict_valfind();
  
! 	if((dval = dict_valfind("Password-Expiration")) == (DICT_VALUE *)NULL) {
  		expiration_seconds = (UINT4)0;
  	}
  	else {
  		expiration_seconds = dval->value * (UINT4)SECONDS_PER_DAY;
  	}
! 	if((dval = dict_valfind("Password-Warning")) == (DICT_VALUE *)NULL) {
  		warning_seconds = (UINT4)0;
  	}
  	else {
  		warning_seconds = dval->value * (UINT4)SECONDS_PER_DAY;
  	}
  	return(0);
  }
  
--- 3439,3477 ----
   *		 expiration_seconds - When updating a user password,
   *			the amount of time to add to the current time
   *			to set the time when the password will expire.
!  *			This is stored as the VALUE Lifetime-In-Days
   *			in the dictionary as number of days.
   *
   *		warning_seconds - When acknowledging a user authentication
   *			time remaining for valid password to notify user
   *			of password expiration.
+  *			This is stored as the VALUE Days-Of-Warning
+  *			in the dictionary as number of days.
   *
   *************************************************************************/
  
+ int
  config_init()
  {
  	DICT_VALUE	*dval;
  
! 	if((dval = dict_valfind(PW_LIFETIME)) == (DICT_VALUE *)NULL) {
! 		DEBUG("config_init(): dict_valfind(%s) failed\r\n",
! 			PW_LIFETIME);
  		expiration_seconds = (UINT4)0;
  	}
  	else {
  		expiration_seconds = dval->value * (UINT4)SECONDS_PER_DAY;
  	}
! 	if((dval = dict_valfind(PW_WARNTIME)) == (DICT_VALUE *)NULL) {
  		warning_seconds = (UINT4)0;
  	}
  	else {
  		warning_seconds = dval->value * (UINT4)SECONDS_PER_DAY;
  	}
+ #if( 0 )
+ 	DEBUG("config_init(): expire-secs = %ld\r\n", expiration_seconds);
+ #endif
  	return(0);
  }
  
***************
*** 1628,1633 ****
--- 3484,3490 ----
   *
   *************************************************************************/
  
+ int
  set_expiration(user_check, expiration)
  VALUE_PAIR	*user_check;
  UINT4		expiration;
***************
*** 1635,1644 ****
  	VALUE_PAIR	*exppair;
  	VALUE_PAIR	*prev;
  	struct timeval	tp;
  	struct timezone	tzp;
  
  	if(user_check == (VALUE_PAIR *)NULL) {
! 		return(-1);
  	}
  
  	/* Look for an existing expiration entry */
--- 3492,3503 ----
  	VALUE_PAIR	*exppair;
  	VALUE_PAIR	*prev;
  	struct timeval	tp;
+ #if !defined(SOLARIS)
  	struct timezone	tzp;
+ #endif
  
  	if(user_check == (VALUE_PAIR *)NULL) {
! 		return NULL_VALUEPAIR;
  	}
  
  	/* Look for an existing expiration entry */
***************
*** 1645,1651 ****
  	exppair = user_check;
  	prev = (VALUE_PAIR *)NULL;
  	while(exppair != (VALUE_PAIR *)NULL) {
! 		if(exppair->attribute == PW_EXPIRATION) {
  			break;
  		}
  		prev = exppair;
--- 3504,3510 ----
  	exppair = user_check;
  	prev = (VALUE_PAIR *)NULL;
  	while(exppair != (VALUE_PAIR *)NULL) {
! 		if(exppair->attribute == ASCEND_PW_EXPIRATION) {
  			break;
  		}
  		prev = exppair;
***************
*** 1655,1666 ****
  		/* Add a new attr-value pair */
  		if((exppair = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) ==
  					(VALUE_PAIR *)NULL) {
! 			fprintf(stderr, "%s: no memory\n", progname);
! 			exit(-1);
  		}
  		/* Initialize it */
! 		strcpy(exppair->name, "Expiration");
! 		exppair->attribute = PW_EXPIRATION;
  		exppair->type = PW_TYPE_DATE;
  		*exppair->strvalue = '\0';
  		exppair->lvalue = (UINT4)0;
--- 3514,3525 ----
  		/* Add a new attr-value pair */
  		if((exppair = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) ==
  					(VALUE_PAIR *)NULL) {
! 			fprintf(errf, "%s: no memory\n", progname);
! 			exit(MEMORY_ERR);
  		}
  		/* Initialize it */
! 		strcpy(exppair->name, PW_EXPIRATION_NAME);
! 		exppair->attribute = ASCEND_PW_EXPIRATION;
  		exppair->type = PW_TYPE_DATE;
  		*exppair->strvalue = '\0';
  		exppair->lvalue = (UINT4)0;
***************
*** 1671,1677 ****
--- 3530,3540 ----
  	}
  
  	/* calculate a new expiration */
+ #if defined(SOLARIS) || defined(aix)
+ 	gettimeofday(&tp);
+ #else
  	gettimeofday(&tp, &tzp);
+ #endif
  	exppair->lvalue = tp.tv_sec + expiration;
  	return(0);
  }
***************
*** 1683,1710 ****
   *	Purpose: Tests to see if the users password has expired.
   *
   *	Return: Number of days before expiration if a warning is required
!  8		otherwise 0 for success and -1 for failure.
   *
   *************************************************************************/
  
! pw_expired(exptime)
  UINT4	exptime;
  {
  	struct timeval	tp;
  	struct timezone	tzp;
! 	UINT4		exp_remain;
! 	int		exp_remain_int;
  
! 	if(expiration_seconds == (UINT4)0) {
  		return(0);
  	}
  
  	gettimeofday(&tp, &tzp);
  	if(tp.tv_sec > exptime) {
! 		return(-1);
  	}
! 	if(warning_seconds != (UINT4)0) {
! 		if(tp.tv_sec > exptime - warning_seconds) {
  			exp_remain = exptime - tp.tv_sec;
  			exp_remain /= (UINT4)SECONDS_PER_DAY;
  			exp_remain_int = exp_remain;
--- 3546,3601 ----
   *	Purpose: Tests to see if the users password has expired.
   *
   *	Return: Number of days before expiration if a warning is required
!  *		otherwise 0 for success and PWD_EXPIRED for failure.
   *
   *************************************************************************/
  
! int
! pw_expired(exptime, usr_exp_days, usr_warn_days)
  UINT4	exptime;
+ UINT4	usr_exp_days;
+ UINT4	usr_warn_days;
  {
+ 	UINT4	exp_secs;
+ 	UINT4	warn_secs;
  	struct timeval	tp;
+ #if !defined(SOLARIS)
  	struct timezone	tzp;
! #endif
! 	UINT4	exp_remain;
! 	int	exp_remain_int;
! 
! #if( 0 )
! 	DEBUG("pw_expired(time=%ld, exp=%ld, warn=%ld)\r\n",
! 		exptime, usr_exp_days, usr_warn_days);
! #endif
! 	if( usr_exp_days ) {
! 		exp_secs = usr_exp_days * (UINT4)SECONDS_PER_DAY;
! 	}
! 	else {
! 		exp_secs = expiration_seconds;
! 	}
! 	if( usr_warn_days ) {
! 		warn_secs = usr_warn_days * (UINT4)SECONDS_PER_DAY;
! 	}
! 	else {
! 		warn_secs = warning_seconds;
! 	}
  
! 	if( exp_secs == (UINT4)0 ) {
  		return(0);
  	}
  
+ #if defined(SOLARIS) || defined(aix)
+ 	gettimeofday(&tp);
+ #else
  	gettimeofday(&tp, &tzp);
+ #endif
  	if(tp.tv_sec > exptime) {
! 		return PWD_EXPIRED;
  	}
! 	if(warn_secs != (UINT4)0) {
! 		if(tp.tv_sec > exptime - warn_secs) {
  			exp_remain = exptime - tp.tv_sec;
  			exp_remain /= (UINT4)SECONDS_PER_DAY;
  			exp_remain_int = exp_remain;
***************
*** 1718,1729 ****
  sig_fatal(sig)
  int	sig;
  {
  	if(acct_pid > 0) {
  		kill(acct_pid, SIGKILL);
  	}
  
! 	fprintf(stderr, "%s: exit on signal (%d)\n", progname, sig);
! 	fflush(stderr);
  	exit(1);
  }
  
--- 3609,3621 ----
  sig_fatal(sig)
  int	sig;
  {
+ 
  	if(acct_pid > 0) {
  		kill(acct_pid, SIGKILL);
  	}
  
! 	fprintf(errf, "%s: exit on signal (%d)\n", progname, sig);
! 	fflush(errf);
  	exit(1);
  }
  
***************
*** 1733,1735 ****
--- 3625,4330 ----
  {
  	return;
  }
+ 
+ /*************************************************************************
+  *
+  *	Function: send_nextcode
+  *
+  *	Purpose: Reply to the request with a Next Code request.  Append
+  *		any message given, and also attach a state value.
+  *
+  *************************************************************************/
+ 
+ void
+ send_nextcode(authreq, msg, msgLen, state, stateLen, activefd)
+ AUTH_REQ	*authreq;
+ char		*msg;
+ int		msgLen;
+ char		*state;
+ int		stateLen;
+ int		activefd;
+ {
+ 	AUTH_HDR		*auth;
+ 	struct	sockaddr_in	saremote;
+ 	struct	sockaddr_in	*sin;
+ 	char			digest[AUTH_VECTOR_LEN];
+ 	int			secretlen;
+ 	int			total_length;
+ 	u_char			*ptr;
+ 
+ 	auth = (AUTH_HDR *)send_buffer;
+ 
+ 	DEBUG("Entering send_nextcode()\r\n");
+ 
+ 	/* Build standard response header */
+ 	auth->code = PW_NEXT_PASSCODE;
+ 	auth->id = authreq->id;
+ 	memcpy(auth->vector, authreq->vector, AUTH_VECTOR_LEN);
+ 	total_length = AUTH_HDR_LEN;
+ 
+ 	ptr = auth->data;
+ 
+ 	/* Append the nextcode msg */
+ 	if( msgLen < AUTH_STRING_LEN ) {
+ 		DEBUG("...Adding nextcode msg, len=%d\r\n", msgLen);
+ 		*ptr++ = PW_PORT_MESSAGE;
+ 		*ptr++ = msgLen + 2;
+ 		memcpy(ptr, msg, msgLen);
+ 		if( debug_flag == 1 ) {
+ 			int	i;
+ 			printf("nextcode msg before encrypt:\r\n");
+ 			for( i = 0; i < msgLen; i++ ) {
+ 				printf("%c", ptr[i]);
+ 			}
+ 			printf("\r\n");
+ 		}
+ 		ptr += msgLen;
+ 		total_length += msgLen + 2;
+ 	}
+ 
+ 	/* Append the state info */
+ 	if( state != (char *)NULL ) {
+ 	    DEBUG("...Adding state <%s>, len=%d\r\n", state, stateLen);
+ 	    *ptr++ = PW_STATE;
+ 	    *ptr++ = stateLen + 2;
+ 	    memcpy(ptr, state, stateLen);
+ 	    ptr += stateLen;
+ 	    total_length += stateLen + 2;
+ 	}
+ 
+ 	/* Set total length in the header */
+ 	auth->length = htons(total_length);
+ 
+ 	DEBUG("send_nextcode(), auth->length = %d\r\n", total_length);
+ 
+ 	/* Calculate the response digest */
+ 	secretlen = strlen((char *)authreq->secret);
+ 	memcpy(send_buffer + total_length, authreq->secret, secretlen);
+ 
+ 	if( debug_flag == 1 ) {
+ 	    int	i;
+ 	    printf("sendBuf before encrypt:\r\n");
+ 	    for( i = 0; i < total_length+secretlen; i++ ) {
+ 		printf("%x ", (u_char)(send_buffer[i]));
+ 	    }
+ 	    printf("\r\n");
+ 	}
+ 
+ 	md5_calc((u_char *)digest, (u_char *)auth, total_length + secretlen);
+ 	memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
+ 	memset(send_buffer + total_length, 0, secretlen);
+ 
+ 	sin = (struct sockaddr_in *) &saremote;
+         memset ((char *) sin, '\0', sizeof (saremote));
+ 	sin->sin_family = AF_INET;
+ 	sin->sin_addr.s_addr = htonl(authreq->ipaddr);
+ 	sin->sin_port = htons(authreq->udp_port);
+ 
+ 	DEBUG("Sending NextCode of id %d to %lx (%s)\r\n",
+ 		authreq->id, (u_long)authreq->ipaddr,
+ 		ip_hostname(authreq->ipaddr));
+ 	
+ 	/* Send it to the user */
+ 	sendto(activefd, (char *)auth, (int)total_length, (int)0,
+ 		(struct sockaddr *) &saremote, sizeof(struct sockaddr_in));
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: send_newpin
+  *
+  *	Purpose: Reply to the request with a Next Code request.  Also
+  *		attach a state value.
+  *
+  *************************************************************************/
+ 
+ 	/* not implemented yet */
+ void
+ send_newpin(authreq, state, stateLen, activefd)
+ AUTH_REQ	*authreq;
+ char		*state;
+ int		stateLen;
+ int		activefd;
+ {
+ 	AUTH_HDR		*auth;
+ #if(0)
+ 	struct	sockaddr_in	saremote;
+ 	struct	sockaddr_in	*sin;
+ 	char			digest[AUTH_VECTOR_LEN];
+ 	int			secretlen;
+ 	int			total_length;
+ 	u_char			*ptr;
+ #endif
+ 
+ 	auth = (AUTH_HDR *)send_buffer;
+ 
+ 	(void)authreq;
+ 	(void)state;
+ 	(void)stateLen;
+ 	(void)activefd;
+ 
+ 	DEBUG("Entering send_newpin(): NOT IMPLEMENTED\r\n");
+ 
+ }
+ 
+ /************************************************************************/
+ /*									*/
+ /*		Map error codes to messages				*/
+ /*									*/
+ /************************************************************************/
+ 
+ char *
+ get_errmsg(errcode)
+ int errcode;
+ {
+     char *emsg = (char *)0;
+     char logbuf[128];
+ 
+     if( (errcode > FIRST_DBASE_ERROR) && (errcode < LAST_DBASE_ERROR) ) {
+         int index = (errcode - FIRST_DBASE_ERROR) - 1;
+ 	if( db_errmsgs[index].ecode == errcode ) {
+             emsg = db_errmsgs[index].emsg;
+ 	} else {
+             emsg = "INTERNAL: ErrMsgTbl out of order";
+ 	    sprintf(logbuf, "INTERNAL: ErrMsgs out of order for errcode %d\n",
+ 	    	errcode);
+ 	    log_err(logbuf);
+ 	}
+     }
+     else {
+         emsg = "INTERNAL: Unknown error";
+         sprintf(logbuf, "INTERNAL: Unknown error code %d\n", errcode);
+ 	log_err(logbuf);
+     }
+     return emsg;
+ }
+ 
+ 
+ #if defined(SAFEWORD)
+ /************************************************************************/
+ /*									*/
+ /*		Enigma Safeword Interface routines			*/
+ /*									*/
+ /************************************************************************/
+ 
+ 
+ 	/* simple debug output */
+ void dbgPblk(pb)
+ struct pblk	*pb;
+ {
+     if( debug_flag ) {
+ 	printf("PBLK: uport    = <%s>\r\n", pb->uport);
+ 	printf("PBLK: id       = <%s>\r\n", pb->id);
+ 	printf("PBLK: chal     = <%s>\r\n", pb->chal);
+ 	printf("PBLK: dynpwd   = <%s>\r\n", pb->dynpwd);
+ 	printf("PBLK: fixpwd   = <%s>\r\n", pb->fixpwd);
+ 	printf("PBLK: nfixpwd  = <%s>\r\n", pb->nfixpwd);
+ 	printf("PBLK: errcode  = <%d>\r\n", pb->errcode);
+ 	printf("PBLK: lastmode = <%d>\r\n", pb->lastmode);
+ 	printf("PBLK: mode     = <%d>\r\n", pb->mode);
+ 	printf("PBLK: fixmin   = <%d>\r\n", pb->fixmin);
+ 	printf("PBLK: dynpwdf  = <%d>\r\n", pb->dynpwdf);
+ 	printf("PBLK: fixpwdf  = <%d>\r\n", pb->fixpwdf);
+ 	printf("PBLK: echodyn  = <%d>\r\n", pb->echodyn);
+ 	printf("PBLK: echofix  = <%d>\r\n", pb->echofix);
+ 	printf("PBLK: status   = <%d>\r\n", pb->status);
+     }
+ }
+ 
+ 
+ /*************************************************************************
+  *
+  *	Function: safeword_chall
+  *
+  *	Purpose: Obtain a (possibly NUL) challenge
+  *
+  *************************************************************************/
+ 
+ int
+ safeword_chall(authInfo, pb)
+ AuthInfo	*authInfo;
+ struct pblk	*pb;
+ {
+ 	DEBUG("safeword_chall()\r\n");
+ 
+ 	/*
+ 	 *
+ 	 *  Fill in param block id field for use by the external
+ 	 *  authentication server:
+ 	 *
+ 	 */
+ 	initpb (pb);
+        	strncpy(pb->id, authInfo->authName->strvalue, sizeof(pb->id));
+ 	pb->id[sizeof(pb->id)-1] = 0;	/* ensure NUL-termimation */
+ 
+ 	/*
+ 	 * Invoke the SafeWord API
+ 	 */
+ 	pb->mode = CHALLENGE;
+ 	pbmain(pb);
+ 
+ 	/* diagnostic */
+ 	DEBUG("after safeword {challenge}\r\n");
+ 	dbgPblk(pb);
+ 
+ 	switch( pb->status ) {
+ 	case GOOD_USER:
+         	DEBUG("safeword_chall: SafeWord Challenging(%s).\r\n",
+ 			pb->chal);
+ 		return SAFEWORD_CHALLENGING;
+ 	default:
+         	DEBUG("safeword_chall: SafeWord failed = %d.\r\n", pb->status);
+ 		return SAFEWORD_FAILED;
+ 	}
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: safeword_eval
+  *
+  *	Purpose: Check the users password against the Safeword
+  *		 password info.
+  *
+  *************************************************************************/
+ int
+ safeword_eval(authInfo, pb)
+ AuthInfo	*authInfo;
+ struct pblk	*pb;
+ {
+ 	VALUE_PAIR	*authPwd = authInfo->authPwd;
+ 	VALUE_PAIR	*authState = authInfo->authState;
+ 	char		*pw_digest = authInfo->pw_digest;
+ 	char		string[AUTH_PASS_LEN + 1];
+ 	int		pwdlen;
+ 	int		i;
+ 	char		*fixed;
+ 
+ 	DEBUG("safeword_eval()\r\n");
+ 
+ 
+ 	memset(string, 0, sizeof(string));
+ 	pwdlen = authPwd->size;
+ 	if( pwdlen > sizeof(string) ) {
+ 		pwdlen = sizeof(string);
+ 	}
+         strncpy(string, authPwd->strvalue, pwdlen);
+ 	string[sizeof(string)-1] = 0;
+ 
+         for( i = 0; i < AUTH_PASS_LEN; i++ ) {
+                 /*
+                  * xor each char of string with corresponding char of pw_digest
+                  */
+ 		string[i] ^= pw_digest[i];
+         }
+ 	string[AUTH_PASS_LEN] = '\0';
+ 
+ 	/* see if we have the <dynamic><,><fixed> format given to us */
+ 	fixed = strchr(string, ',');
+ 	if( fixed ) {
+ 		*fixed = '\0';	/* NUL-terminate dynamic password */
+ 		fixed++;
+ 		DEBUG("received fixed pwd %s\r\n", fixed);
+ 	}
+ 
+ 	memcpy(BEG_PB_1ST(pb), authState->strvalue, LEN_PB_1ST(pb));
+ 	memcpy(BEG_PB_2ND(pb),
+ 		authState->strvalue + LEN_PB_1ST(pb),
+ 		LEN_PB_2ND(pb));
+ 	for( i = 0; i < AUTH_PASS_LEN; i++ ) {
+ 		if( (pb->chal[i] < ' ') || (pb->chal[i] > 0x7e) ) {
+ 			pb->chal[i] = 0;
+ 			break;
+ 		}
+ 	}
+ 	DEBUG("Old challenge is <%s>\r\n", pb->chal);
+ 
+ 	/* copy new dynamic password to the SafeWord param block */
+ 	pb->dynpwd[0] = 0;
+ 	if( pb->dynpwdf ) {
+     		strncpy(pb->dynpwd, string, sizeof(pb->dynpwd));
+ 		pb->dynpwd[sizeof(pb->dynpwd)-1] = 0;
+ 	}
+ 	else {
+ 		char *dynfMsg = "safeword_eval(): dynamic pwd flag not set!\n";
+ 		DEBUG("%s\r\n", dynfMsg);
+ 		log_err(dynfMsg);
+ 		return SAFEWORD_FAILED;
+ 	}
+ 
+ 	pb->fixpwd[0] = 0;
+ 	if( fixed ) {
+ 		/* copy fixed pwd *always* but bitch if the flag is clear */
+     		strncpy(pb->fixpwd, fixed, sizeof(pb->fixpwd));
+ 		pb->fixpwd[sizeof(pb->fixpwd)-1] = 0;
+ 		if( !pb->fixpwdf ) {
+ 			char	buf[128];
+ 
+ 			sprintf(buf,
+ 				"user %s, fixed pwd w/o fixpwdf, NAS %s\n",
+ 					authInfo->authName->strvalue,
+ 					ip_hostname(authInfo->authreq->ipaddr));
+ 			DEBUG("%s\r\n", buf);
+ 			log_err(buf);
+ 		}
+ 	}
+ 
+ 	pb->mode = EVALUATE_ALL;
+ 	pbmain(pb);
+ 
+ 	/* diagnostic */
+ 	DEBUG("after safeword {eval}\r\n");
+ 	dbgPblk(pb);
+ 
+ 	switch( pb->status ) {
+ 	case PASS:
+         	DEBUG("safeword_eval: SafeWord PASSED.\r\n");
+ 		return SAFEWORD_PASSED;
+ 	default:
+         	DEBUG("safeword_eval: SafeWord FAILED, = %d.\r\n", pb->status);
+ 		return SAFEWORD_FAILED;
+ 	}
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: safeword_pass
+  *
+  *	Purpose: Check the users password against the Safeword
+  *		 password info.
+  *
+  *************************************************************************/
+ 	/*
+ 	 * Since the Radius database has detected a default keyword as the
+ 	 * special "SAFEWORD" flag, it is now appropriate to ask SafeWord
+ 	 * if it has any data on him (or her). We check the given STATE;
+ 	 * if NUL, then this is a challenge request, else it is
+ 	 * an evaluation request
+ 	 */
+ int
+ safeword_pass(authInfo, pb)
+ AuthInfo	*authInfo;
+ struct pblk	*pb;
+ {
+ 	DEBUG("safeword_pass()\r\n");
+ 	if( authInfo->authState != (VALUE_PAIR *)NULL ) {
+ 		if( authInfo->authState->attribute == PW_STATE ) {
+ 			if( authInfo->authState->size ) {
+ 				return safeword_eval(authInfo, pb);
+ 			}
+ 			else {
+ 				return safeword_chall(authInfo, pb);
+ 			}
+ 		}
+ 	}
+ 	DEBUG("safeword_pass(): FAILED: no state attribute\r\n");
+ 	return SAFEWORD_FAILED;
+ }
+ 
+ 
+ /* ---------------------------- initpb () ---------------------------- */
+ 
+ 	/* initialize parameter block */
+ void
+ initpb(pb)
+ struct pblk	*pb;
+ {
+ 	memset(pb, 0, sizeof(*pb));
+ 
+ 	strcpy (pb->uport, "custpb");
+ 	pb->status = NO_STATUS;
+ }
+ #endif
+ 
+ #if defined(ACE)
+ /************************************************************************/
+ /*									*/
+ /*		Security Dynamics ACE/Server Interface routines		*/
+ /*									*/
+ /************************************************************************/
+ 
+ 
+ 	/* simple debug output */
+ void dbgSdClient(sd)
+ struct SD_CLIENT	*sd;
+ {
+     if( debug_flag ) {
+ 	printf("SD_CLIENT: appId    = <%d>\r\n", sd->application_id);
+ 	printf("SD_CLIENT: name     = <%s>\r\n", sd->username);
+ 
+ #if defined(UINT4_IS_UINT)
+ 	printf("SD_CLIENT: pc_time  = <%d>\r\n", sd->passcode_time);
+ #else
+ 	printf("SD_CLIENT: pc_time  = <%ld>\r\n", sd->passcode_time);
+ #endif
+ 	printf("SD_CLIENT: passcode = <%s>\r\n", sd->validated_passcode);
+     }
+ }
+ 
+ 
+ /*************************************************************************
+  *
+  *	Function: ace_eval
+  *
+  *	Purpose: Check the users password against the ACE
+  *		 password info.
+  *
+  *************************************************************************/
+ int
+ ace_eval(authInfo, sd)
+ AuthInfo		*authInfo;
+ struct SD_CLIENT	*sd;
+ {
+ 	VALUE_PAIR	*authName = authInfo->authName;
+ 	VALUE_PAIR	*authPwd = authInfo->authPwd;
+ 	char		*pw_digest = authInfo->pw_digest;
+ 	int		status;
+ 	char		acePwd[AUTH_PASS_LEN + 1];
+ 	int		i;
+ 	int		pwdlen;
+ 	char		*user;
+ 	char		username[LENACMNAME];
+ 				/* N.B.: sdi_ath.h uses LENACMNAME although
+ 				   one would think that LENUSERNAME would
+ 				   be more appropriate */
+ 
+ 	DEBUG("ace_eval()\r\n");
+ 
+ 	/*
+ 	 * Establish communications with the server
+ 	 */
+ 	memset(sd, 0, sizeof(*sd));	/* clear shared param block */
+ 	creadcfg();			/* accesses sdconf.rec */
+ 	if( sd_init(sd) ) {
+ 		DEBUG("ace_eval(): Comm Server init failed!\r\n");
+ 		return ACE_FAILED;
+ 	}
+ 
+ 	DEBUG("ace_eval(): ace_username: %s\r\n", authName->strvalue);
+         strncpy(username, authName->strvalue, sizeof(username));
+ 	username[sizeof(username)-1] = 0;	/* ensure final NUL */
+ 	user = (char *)NULL;
+ 
+ 	memset(acePwd, 0, sizeof(acePwd));
+ 	pwdlen = authPwd->size;
+ 	    if( pwdlen > LENPRNST ) {
+ 		pwdlen = LENPRNST;
+ 	    }
+ 	strncpy(acePwd, authPwd->strvalue, pwdlen);
+ 
+ 	for( i = 0; i < AUTH_PASS_LEN; i++ ) {
+ 		/*
+ 		 * xor each char of string with corresponding char of pw_digest
+ 		 */
+ 		acePwd[i] ^= pw_digest[i];
+ 	}
+ 	acePwd[AUTH_PASS_LEN] = '\0';
+ #if defined( PWD_DEBUG )
+ 	DEBUG("ace_eval(): rad_pwd: %s\r\n", acePwd);
+ #endif
+ 
+ 	/* see if we have the <password><.><username> format given to us */
+ 	user = strchr(acePwd, '.');
+ 	if( user ) {
+ 		*user = '\0';	/* NUL-terminate dynamic password */
+ 		user++;
+ 		DEBUG("received username %s\r\n", user);
+ 	}
+ 
+ 	/* copy the username to the ACE param block */
+ 	sd->username[0] = 0;
+ 	if( !user ) {
+ 		strcpy(sd->username, username);
+ 	} else {
+ 		strcpy(sd->username, user);
+ 	}
+ 
+ #if defined( PWD_DEBUG )
+ 	DEBUG("Ready to try user %s with pwd %s\r\n", sd->username, acePwd);
+ #endif
+ 	status = sd_check(acePwd, sd->username, sd);
+ 	switch( status ) {
+ 	case ACM_OK:
+ 		DEBUG("user %s authenticated with pwd %s\r\n",
+ 			sd->username, acePwd);
+ 		status = ACE_PASSED;
+ 		break;
+ 	case ACM_ACCESS_DENIED:
+ 		DEBUG("user %s with pwd %s NOT AUTHENTICATED!\r\n",
+ 			sd->username, acePwd);
+ 		status = ACE_FAILED;
+ 		break;
+ 	case ACM_NEXT_CODE_REQUIRED:
+ 		DEBUG("user %s with pwd %s requires next code\r\n",
+ 			sd->username, acePwd);
+ 		status = ACE_NEXT_PASSCODE;
+ 		break;
+ 	case ACM_NEW_PIN_REQUIRED:
+ 		DEBUG("user %s with pwd %s requires new pin\r\n",
+ 			sd->username, acePwd);
+ 		status = ACE_NEW_PIN;
+ 		break;
+ 	default:
+ 		DEBUG("user %s with pwd %s : ERROR %d\r\n",
+ 			sd->username, acePwd, status);
+ 		status = ACE_FAILED;
+ 		break;
+ 	}
+ 
+ 	/* diagnostic */
+ 	DEBUG("after ace {eval}\r\n");
+ 	dbgSdClient(sd);
+ 
+ 	return status;
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: ace_next
+  *
+  *	Purpose: Check the users password against the ACE
+  *		 password info.
+  *
+  *************************************************************************/
+ int
+ ace_next(authInfo, sd)
+ AuthInfo		*authInfo;
+ struct SD_CLIENT	*sd;
+ {
+ 	VALUE_PAIR	*authName = authInfo->authName;
+ 	VALUE_PAIR	*authPwd = authInfo->authPwd;
+ 	VALUE_PAIR	*authState = authInfo->authState;
+ 	char		*pw_digest = authInfo->pw_digest;
+ 	int		status;
+ 	char		acePwd[AUTH_PASS_LEN + 1];
+ 	int		i;
+ 	int		pwdlen;
+ 	char		*src;
+ 	char		*user;
+ 	char		username[LENACMNAME];
+ 				/* N.B.: sdi_ath.h uses LENACMNAME although
+ 				   one would think that LENUSERNAME would
+ 				   be more appropriate */
+ 
+ 	DEBUG("ace_next()\r\n");
+ 
+ 	DEBUG("ace_next(): ace_username: %s\r\n", authName->strvalue);
+         strncpy(username, authName->strvalue, sizeof(username));
+ 	username[sizeof(username)-1] = 0;	/* ensure final NUL */
+ 	user = (char *)NULL;
+ 
+ 	memset(acePwd, 0, sizeof(acePwd));
+ 	pwdlen = strlen(authPwd->strvalue);
+ 	if( pwdlen > LENPRNST ) {
+ 		pwdlen = LENPRNST;
+ 	}
+         strncpy(acePwd, authPwd->strvalue, pwdlen);
+ 
+ 	for( i = 0; i < AUTH_PASS_LEN; i++ ) {
+ 		/*
+ 		 * xor each char of string with corresponding char of pw_digest
+ 		 */
+ 		acePwd[i] ^= pw_digest[i];
+ 	}
+ 	acePwd[AUTH_PASS_LEN] = '\0';
+ 	DEBUG("ace_next(): rad_pwd: %s\r\n", acePwd);
+ 
+ 	/* see if we have the <password>.<username> format given to us */
+ 	user = strchr(acePwd, '.');
+ 	if( user ) {
+ 		*user = '\0';	/* NUL-terminate dynamic password */
+ 		user++;
+ 		DEBUG("received username %s\r\n", user);
+ 	}
+ 
+ 	src = &authState->strvalue[1];	/* skip length field */
+ 	memcpy(BEG_SD_1ST(sd), src, LEN_SD_1ST(sd));
+ 	memcpy(BEG_SD_2ND(sd), src + LEN_SD_1ST(sd), LEN_SD_2ND(sd));
+ 	memcpy(BEG_SD_3RD(sd), src + LEN_SD_1ST(sd) + LEN_SD_2ND(sd),
+ 			LEN_SD_3RD(sd));
+ 
+ 	/* copy the username to the ACE param block */
+ 	sd->username[0] = 0;
+ 	if( !user ) {
+ 		strcpy(sd->username, username);
+ 	} else {
+ 		strcpy(sd->username, user);
+ 	}
+ 
+ 	DEBUG("Ready to try user %s with pwd %s\r\n", sd->username, acePwd);
+ 	status = sd_next(acePwd, sd);
+ 	switch( status ) {
+ 	case ACM_OK:
+ 		DEBUG("user %s authenticated with pwd %s\r\n",
+ 			sd->username, acePwd);
+ 		status = ACE_PASSED;
+ 		break;
+ 	case ACM_ACCESS_DENIED:
+ 		DEBUG("user %s with pwd %s NOT AUTHENTICATED!\r\n",
+ 			sd->username, acePwd);
+ 		status = ACE_FAILED;
+ 		break;
+ 	default:
+ 		DEBUG("user %s with pwd %s : ERROR %d\r\n",
+ 			sd->username, acePwd, status);
+ 		break;
+ 	}
+ 
+ 	/* diagnostic */
+ 	DEBUG("after ace {nextcode}\r\n");
+ 	dbgSdClient(sd);
+ 
+ 	return status;
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: ace_pass
+  *
+  *	Purpose: Check the users password against the ACE
+  *		 password info.
+  *
+  *************************************************************************/
+ 	/*
+ 	 * Since the Radius database has detected a default keyword as the
+ 	 * special "ACE" flag, it is now appropriate to ask Ace
+ 	 * if it has any data on him (or her). We check the STATE;
+ 	 * if STATE == DUMMY,
+ 	 * then this is a challenge request,
+ 	 * else if the contained STATE length == NEXTCODE STATE length
+ 	 *	then this is a response to a NEXTCODE request
+ 	 * else it is an evaluation request
+ 	 */
+ int
+ ace_pass(authInfo, sd)
+ AuthInfo		*authInfo;
+ struct SD_CLIENT	*sd;
+ {
+ 	VALUE_PAIR	*authState = authInfo->authState;
+ 
+ 	DEBUG("ace_pass()\r\n");
+ 	if( authState != (VALUE_PAIR *)NULL ) {
+ 		if( !strcmp(authState->strvalue, ACE_DUMMY_STATE) ) {
+ 			DEBUG("ace_pass(eval): state len = %d\r\n",
+ 				(u_char)authState->strvalue[0]);
+ 			return ace_eval(authInfo, sd);
+ 		}
+ 		else if( (u_char)(authState->strvalue[0])
+ 			== (u_char)(LEN_SD_TOTAL(sd) + 1) )
+ 		{
+ 			DEBUG("ace_pass(next): state len = %u\r\n",
+ 				(u_char)authState->strvalue[0]);
+ 	        	return ace_next(authInfo, sd);
+ 		}
+ 		else {
+ 			DEBUG("ace_pass(chall): state len = %u\r\n",
+ 				(u_char)authState->strvalue[0]);
+ 			return ACE_CHALLENGING;
+ 		}
+ 	}
+ 
+ 	DEBUG("ace_pass(): FAILED: no state attribute\r\n");
+ 	return ACE_FAILED;
+ }
+ 
+ #endif	/* ACE */
+ 
diff -c -N radiusd//radpass.c ascendd//radpass.c
*** radiusd//radpass.c	Tue Dec 27 09:32:30 1994
--- ascendd//radpass.c	Wed Dec 20 09:43:44 1995
***************
*** 3,9 ****
--- 3,11 ----
   *	RADIUS
   *	Remote Authentication Dial In User Service
   *
+  * ASCEND: @(#)radpass.c	1.2 (95/07/25 00:55:38)
   *
+  *
   *	Livingston Enterprises, Inc.
   *	6920 Koll Center Parkway
   *	Pleasanton, CA   94566
***************
*** 36,43 ****
--- 38,48 ----
  #include	<unistd.h>
  #include	<netdb.h>
  #include	<pwd.h>
+ #include	<stdlib.h>
+ #include	<sys/time.h>	/* gettimeofday() */
  
  #include	"radius.h"
+ #include	"protos.h"
  
  #define MAXPWNAM	8
  #define MAXPASS		16
***************
*** 49,57 ****
  u_char		vector[AUTH_VECTOR_LEN];
  u_char		oldpass[AUTH_PASS_LEN];
  
  main(argc, argv)
  int	argc;
! u_char	*argv[];
  {
  	int			salen;
  	int			result;
--- 54,70 ----
  u_char		vector[AUTH_VECTOR_LEN];
  u_char		oldpass[AUTH_PASS_LEN];
  
+ static void random_vector P__((u_char *vector));
+ static void usage P__((void));
+         /* udp_port promoted due to old-style function definition */
+ static void result_recv P__((UINT4 host, int udp_port, u_char *buffer, int length));
+ static void usage P__((void));
+ int main P__((int argc, u_char **argv));
+ 
+ int
  main(argc, argv)
  int	argc;
! u_char	**argv;
  {
  	int			salen;
  	int			result;
***************
*** 67,73 ****
  	u_char			passbuf[AUTH_PASS_LEN];
  	u_char			md5buf[256];
  	u_char			*oldvector;
- 	UINT4			get_ipaddr();
  	UINT4			auth_ipaddr;
  	u_short			local_port;
  	int			total_length;
--- 80,85 ----
***************
*** 75,81 ****
  	int			length;
  	int			secretlen;
  	int			i;
! 	char			*getpass();
  
  	progname = argv[0];
  
--- 87,93 ----
  	int			length;
  	int			secretlen;
  	int			i;
! 	char			*getpass(CONST char *);
  
  	progname = argv[0];
  
***************
*** 137,143 ****
  
  	/* Get their new password again */
  	strcpy((char *)newpass2, getpass("Re-type New Password:"));
! 	if(strcmp(newpass1, newpass2) != 0) {
  		printf("New Passwords didn't match\n");
  		exit(-1);
  	}
--- 149,155 ----
  
  	/* Get their new password again */
  	strcpy((char *)newpass2, getpass("Re-type New Password:"));
! 	if(strcmp((char *)newpass1, (char *)newpass2) != 0) {
  		printf("New Passwords didn't match\n");
  		exit(-1);
  	}
***************
*** 153,159 ****
  
  	/* User Name */
  	*ptr++ = PW_USER_NAME;
! 	length = strlen(username);
  	if(length > MAXPWNAM) {
  		length = MAXPWNAM;
  	}
--- 165,171 ----
  
  	/* User Name */
  	*ptr++ = PW_USER_NAME;
! 	length = strlen((char *)username);
  	if(length > MAXPWNAM) {
  		length = MAXPWNAM;
  	}
***************
*** 167,173 ****
  	*ptr++ = AUTH_PASS_LEN + 2;
  
  	/* Encrypt the Password */
! 	length = strlen(newpass1);
  	if(length > MAXPASS) {
  		length = MAXPASS;
  	}
--- 179,185 ----
  	*ptr++ = AUTH_PASS_LEN + 2;
  
  	/* Encrypt the Password */
! 	length = strlen((char *)newpass1);
  	if(length > MAXPASS) {
  		length = MAXPASS;
  	}
***************
*** 174,181 ****
  	memset(passbuf, 0, AUTH_PASS_LEN);
  	memcpy(passbuf, newpass1, length);
  	/* Calculate the MD5 Digest */
! 	secretlen = strlen(oldpass);
! 	strcpy(md5buf, oldpass);
  	memcpy(md5buf + secretlen, auth->vector, AUTH_VECTOR_LEN);
  	md5_calc(ptr, md5buf, secretlen + AUTH_VECTOR_LEN);
  	oldvector = ptr;
--- 186,193 ----
  	memset(passbuf, 0, AUTH_PASS_LEN);
  	memcpy(passbuf, newpass1, length);
  	/* Calculate the MD5 Digest */
! 	secretlen = strlen((char *)oldpass);
! 	strcpy((char *)md5buf, (char *)oldpass);
  	memcpy(md5buf + secretlen, auth->vector, AUTH_VECTOR_LEN);
  	md5_calc(ptr, md5buf, secretlen + AUTH_VECTOR_LEN);
  	oldvector = ptr;
***************
*** 190,196 ****
  	*ptr++ = AUTH_PASS_LEN + 2;
  
  	/* Encrypt the Password */
! 	length = strlen(oldpass);
  	if(length > MAXPASS) {
  		length = MAXPASS;
  	}
--- 202,208 ----
  	*ptr++ = AUTH_PASS_LEN + 2;
  
  	/* Encrypt the Password */
! 	length = strlen((char *)oldpass);
  	if(length > MAXPASS) {
  		length = MAXPASS;
  	}
***************
*** 197,204 ****
  	memset(passbuf, 0, AUTH_PASS_LEN);
  	memcpy(passbuf, oldpass, length);
  	/* Calculate the MD5 Digest */
! 	secretlen = strlen(oldpass);
! 	strcpy(md5buf, oldpass);
  	memcpy(md5buf + secretlen, oldvector, AUTH_VECTOR_LEN);
  	md5_calc(ptr, md5buf, secretlen + AUTH_VECTOR_LEN);
  
--- 209,216 ----
  	memset(passbuf, 0, AUTH_PASS_LEN);
  	memcpy(passbuf, oldpass, length);
  	/* Calculate the MD5 Digest */
! 	secretlen = strlen((char *)oldpass);
! 	strcpy((char *)md5buf, (char *)oldpass);
  	memcpy(md5buf + secretlen, oldvector, AUTH_VECTOR_LEN);
  	md5_calc(ptr, md5buf, secretlen + AUTH_VECTOR_LEN);
  
***************
*** 231,239 ****
  	}
  	(void) perror ("recv");
  	close(sockfd);
! 	exit(0);
  }
  
  result_recv(host, udp_port, buffer, length)
  UINT4	host;
  u_short	udp_port;
--- 243,252 ----
  	}
  	(void) perror ("recv");
  	close(sockfd);
! 	return 0;
  }
  
+ void
  result_recv(host, udp_port, buffer, length)
  UINT4	host;
  u_short	udp_port;
***************
*** 242,248 ****
  {
  	AUTH_HDR	*auth;
  	int		totallen;
- 	char		*ip_hostname();
  	u_char		reply_digest[AUTH_VECTOR_LEN];
  	u_char		calc_digest[AUTH_VECTOR_LEN];
  	int		secretlen;
--- 255,260 ----
***************
*** 258,266 ****
  	/* Verify the reply digest */
  	memcpy(reply_digest, auth->vector, AUTH_VECTOR_LEN);
  	memcpy(auth->vector, vector, AUTH_VECTOR_LEN);
! 	secretlen = strlen(oldpass);
  	memcpy(buffer + AUTH_HDR_LEN, oldpass, secretlen);
! 	md5_calc(calc_digest, (char *)auth, AUTH_HDR_LEN);
  
  	if(memcmp(reply_digest, calc_digest, AUTH_VECTOR_LEN) != 0) {
  		printf("Warning: Received invalid reply digest from server\n");
--- 270,278 ----
  	/* Verify the reply digest */
  	memcpy(reply_digest, auth->vector, AUTH_VECTOR_LEN);
  	memcpy(auth->vector, vector, AUTH_VECTOR_LEN);
! 	secretlen = strlen((char *)oldpass);
  	memcpy(buffer + AUTH_HDR_LEN, oldpass, secretlen);
! 	md5_calc(calc_digest, (u_char *)auth, AUTH_HDR_LEN);
  
  	if(memcmp(reply_digest, calc_digest, AUTH_VECTOR_LEN) != 0) {
  		printf("Warning: Received invalid reply digest from server\n");
***************
*** 274,279 ****
--- 286,292 ----
  	}
  }
  
+ void
  usage()
  {
  	printf("Usage: %s username\n", progname);
***************
*** 280,285 ****
--- 293,299 ----
  	exit(-1);
  }
  
+ void
  random_vector(vector)
  u_char	*vector;
  {
diff -c -N radiusd//users.c ascendd//users.c
*** radiusd//users.c	Fri Jan  6 13:58:16 1995
--- ascendd//users.c	Wed Dec 20 09:39:05 1995
***************
*** 3,9 ****
--- 3,11 ----
   *	RADIUS
   *	Remote Authentication Dial In User Service
   *
+  * ASCEND: @(#)users.c	1.2 (95/07/25 00:55:40)
   *
+  *
   *	Livingston Enterprises, Inc.
   *	6920 Koll Center Parkway
   *	Pleasanton, CA   94566
***************
*** 38,59 ****
  #include	<pwd.h>
  #include	<time.h>
  #include	<ctype.h>
! 
! #ifdef DBM
! 
! #include	<dbm.h>
! 
! #endif /* DBM */
  
  #include	"radius.h"
  
  extern char		*progname;
  extern int		debug_flag;
  extern char		*radius_dir;
  
! static	void fieldcpy();
! static	int  userparse();
  
  #define FIND_MODE_NAME	0
  #define FIND_MODE_REPLY	1
  #define FIND_MODE_SKIP	2
--- 40,75 ----
  #include	<pwd.h>
  #include	<time.h>
  #include	<ctype.h>
! #include	<string.h>
! #include	<unistd.h>
! #include	<stdlib.h>
! 
! #if defined(DBM_MODE)
! #	if defined(SOLARIS)
! #		include	</usr/ucbinclude/dbm.h>
! #	else
! #		include	<dbm.h>
! #	endif	/* SOLARIS */
! #endif /* DBM_MODE */
  
  #include	"radius.h"
+ #include	"protos.h"
  
  extern char		*progname;
  extern int		debug_flag;
  extern char		*radius_dir;
+ extern char		*radius_users;
+ extern FILE		*errf;
  
! static int parse_record P__((char *name, char *linep, FILE *userfd,
! 	VALUE_PAIR **check_first, VALUE_PAIR **reply_first));
! extern int user_read P__((FILE **userfd, char *name, char *content));
! static int userparse P__((char **buf, VALUE_PAIR **first_pair));
! static void fieldcpy P__((char *string, char **uptr));
! static void user_gettime P__((char *valstr, struct tm *tm));
! extern int curParseLine;	/* -- current line in file being parsed */
  
+ 
  #define FIND_MODE_NAME	0
  #define FIND_MODE_REPLY	1
  #define FIND_MODE_SKIP	2
***************
*** 61,66 ****
--- 77,192 ----
  
  /*************************************************************************
   *
+  *	Function: userinfo_open
+  *
+  *	Purpose: Opens the users information file. Do different things
+  *		 different ways depending on whether we are using
+  *		 a flat file or a dbm database.
+  *
+  *	Returns: zero upon success, non-zero upon failure
+  *
+  *************************************************************************/
+ 
+ static int
+ userinfo_open(userfd, infoname)
+ FILE	**userfd;
+ char	*infoname;
+ {
+ #if defined(DBM_MODE)
+ 	(void)userfd;
+ 	return dbminit(infoname);
+ #else
+ 	*userfd = fopen(infoname, "r");
+ 	return *userfd == (FILE *)NULL;
+ #endif
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: userinfo_close
+  *
+  *	Purpose: Close the users information file. Do different things
+  *		 different ways depending on whether we are using
+  *		 a flat file or a dbm database.
+  *
+  *************************************************************************/
+ 
+ static void
+ userinfo_close(userfd)
+ FILE	*userfd;
+ {
+ #if defined(DBM_MODE)
+ 	(void)userfd;
+ 	dbmclose();
+ #else
+ 	fclose(userfd);
+ #endif
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: parse_record
+  *
+  *	Purpose: Given a record for the requested user, parse the record
+  *		 into the required attributes (check_first) and the
+  *		 attributes to return (reply_first).
+  *		 Ensure that all is fine with the record.
+  *
+  *		 Perform parsing identically for flat-file and for
+  *		 dbm databases.
+  *
+  *************************************************************************/
+ 
+ static int
+ parse_record(name, linep, userfd, check_first, reply_first)
+ char		*name;
+ char		*linep;
+ FILE		*userfd;
+ VALUE_PAIR	**check_first;
+ VALUE_PAIR	**reply_first;
+ {
+ 	int stat;
+ 	char		msg[128];
+ 
+ 	/*
+ 	 * Parse the check values
+ 	 */
+ 	if( (stat = userparse(&linep, check_first)) != 0) {
+ 		sprintf(msg, "%s: Parse.check error %d for user %s\n",
+ 				progname, stat, name);
+ 		fprintf(errf, msg);
+ 		log_err(msg);
+ 		pairfree(*check_first);
+ 		userinfo_close(userfd);
+ 		return(stat);
+ 	}
+ 	while(*linep != '\n' && *linep != '\0') {
+ 		linep++;
+ 	}
+ 	if(*linep != '\n') {
+ 		pairfree(*check_first);
+ 		userinfo_close(userfd);
+ 		fprintf(errf, "%s: Missing NL for user %s\n",
+ 				progname, name);
+ 		return(MISSING_NEWLINE);
+ 	}
+ 	linep++;
+ 	/*
+ 	 * Parse the reply values
+ 	 */
+ 	if( (stat = userparse(&linep, reply_first)) != 0) {
+ 		fprintf(errf, "%s: Parse.reply error %d for user %s\n",
+ 			progname, stat, name);
+ 		pairfree(*check_first);
+ 		pairfree(*reply_first);
+ 		userinfo_close(userfd);
+ 		return(stat);
+ 	}
+ 	return 0;
+ }
+ 
+ /*************************************************************************
+  *
   *	Function: user_find
   *
   *	Purpose: Find the named user in the database.  Create the
***************
*** 69,91 ****
   *
   *************************************************************************/
  
  user_find(name, check_pairs, reply_pairs)
! char	*name;
  VALUE_PAIR	**check_pairs;
  VALUE_PAIR	**reply_pairs;
  {
  	FILE		*userfd;
! 	char		buffer[256];
! 	char		msg[128];
  	char		*ptr;
  	int		namelen;
  	int		mode;
  	VALUE_PAIR	*check_first;
  	VALUE_PAIR	*reply_first;
! #ifdef DBM
  	datum		named;
  	datum		contentd;
! #endif /* DBM */
  
  	/* 
  	 * Check for valid input, zero length names not permitted 
--- 195,221 ----
   *
   *************************************************************************/
  
+ int
  user_find(name, check_pairs, reply_pairs)
! char		*name;
  VALUE_PAIR	**check_pairs;
  VALUE_PAIR	**reply_pairs;
  {
  	FILE		*userfd;
! 	char		buf[256];
  	char		*ptr;
  	int		namelen;
  	int		mode;
  	VALUE_PAIR	*check_first;
  	VALUE_PAIR	*reply_first;
! #ifdef DBM_MODE
  	datum		named;
  	datum		contentd;
! #else
! 	char		curname[512];
! 	char		line[4 * 1024];
! #endif /* DBM_MODE */
! 	int		stat;
  
  	/* 
  	 * Check for valid input, zero length names not permitted 
***************
*** 105,112 ****
  	namelen=strlen(name);
  
  	if (namelen < 1) {
! 		fprintf(stderr, "%s: zero length username not permitted\n",progname);
! 		return(-1);
  	}
  
  
--- 235,243 ----
  	namelen=strlen(name);
  
  	if (namelen < 1) {
! 		fprintf(errf, "%s: zero length username not permitted\n",
! 			progname);
! 		return(ZERO_LENGTH_NAME);
  	}
  
  
***************
*** 113,127 ****
  	/*
  	 * Open the user table
  	 */
! 	sprintf(buffer, "%s/%s", radius_dir, RADIUS_USERS);
! #ifdef DBM
! 	if(dbminit(buffer) != 0) {
! #else /* DBM */
! 	if((userfd = fopen(buffer, "r")) == (FILE *)NULL) {
! #endif /* DBM */
! 		fprintf(stderr, "%s:Couldn't open %s for reading\n",
! 				progname, buffer);
! 		return(-1);
  	}
  
  	check_first = (VALUE_PAIR *)NULL;
--- 244,254 ----
  	/*
  	 * Open the user table
  	 */
! 	sprintf(buf, "%s/%s", radius_dir, radius_users);
! 	if( userinfo_open(&userfd, buf) != 0 ) {
! 		fprintf(errf, "%s:Couldn't open %s for reading\n",
! 				progname, buf);
! 		return(NO_USER_FILE);
  	}
  
  	check_first = (VALUE_PAIR *)NULL;
***************
*** 128,242 ****
  	reply_first = (VALUE_PAIR *)NULL;
  
  
! #ifdef DBM
  	named.dptr = name;
! 	named.dsize = strlen(name);
  	contentd = fetch(named);
  
! 	if(contentd.dsize == 0) {
  		named.dptr = "DEFAULT";
! 		named.dsize = strlen("DEFAULT");
  		contentd = fetch(named);
! 		if(contentd.dsize == 0) {
  			dbmclose();
! 			return(-1);
  		}
  	}
! 
! 	/*
! 	 * Parse the check values
! 	 */
! 	ptr = contentd.dptr;
! 	contentd.dptr[contentd.dsize] = '\0';
! 
! 	if(userparse(ptr, &check_first) != 0) {
! 		sprintf(msg, "%s: Parse error for user %s\n",
! 				progname, name);
! 		fprintf(stderr, msg);
! 		log_err(msg);
! 		pairfree(check_first);
! 		dbmclose();
! 		return(-1);
! 	}
! 	while(*ptr != '\n' && *ptr != '\0') {
! 		ptr++;
! 	}
! 	if(*ptr != '\n') {
! 		pairfree(check_first);
! 		dbmclose();
! 		return(-1);
! 	}
! 	ptr++;
! 	/*
! 	 * Parse the reply values
! 	 */
! 	if(userparse(ptr, &reply_first) != 0) {
! 		fprintf(stderr, "%s: Parse error for user %s\n",
! 			progname, name);
! 		pairfree(check_first);
! 		pairfree(reply_first);
! 		dbmclose();
! 		return(-1);
  	}
- 	dbmclose();
  
! #else /* DBM */
  
! 	while(fgets(buffer, sizeof(buffer), userfd) != (char *)NULL) {
! 		if(mode == FIND_MODE_NAME) {
! 			/*
! 			 * Find the entry starting with the users name
! 			 */
! 			if((strncmp(buffer, name, namelen) == 0 &&
! 		 	 (buffer[namelen] == ' ' || buffer[namelen] == '\t')) ||
! 					 strncmp(buffer, "DEFAULT", 7) == 0) {
! 				if(strncmp(buffer, "DEFAULT", 7) == 0) {
! 					ptr = &buffer[7];
! 				}
! 				else {
! 					ptr = &buffer[namelen];
! 				}
! 				/*
! 				 * Parse the check values
! 				 */
! 				if(userparse(ptr, &check_first) != 0) {
! 					sprintf(msg,"%s: Parse error for user %s\n",
! 						progname, name);
! 					fprintf(stderr,msg);
! 					log_err(msg);
! 					pairfree(check_first);
! 					fclose(userfd);
! 					return(-1);
! 				}
! 				mode = FIND_MODE_REPLY;
! 			}
! 		}
! 		else {
! 			if(*buffer == ' ' || *buffer == '\t') {
! 				/*
! 				 * Parse the reply values
! 				 */
! 				if(userparse(buffer, &reply_first) != 0) {
! 					fprintf(stderr,
! 						"%s: Parse error for user %s\n",
! 						progname, name);
! 					pairfree(check_first);
! 					pairfree(reply_first);
! 					fclose(userfd);
! 					return(-1);
! 				}
! 			}
! 			else {
! 				/* We are done */
! 				fclose(userfd);
! 				*check_pairs = check_first;
! 				*reply_pairs = reply_first;
! 				return(0);
! 			}
! 		}
  	}
- 	fclose(userfd);
- #endif /* DBM */
  
  	/* Update the callers pointers */
  	if(reply_first != (VALUE_PAIR *)NULL) {
--- 255,299 ----
  	reply_first = (VALUE_PAIR *)NULL;
  
  
! #ifdef DBM_MODE
  	named.dptr = name;
! 	named.dsize = strlen(name)+1;
  	contentd = fetch(named);
  
! 	if(contentd.dsize == 0) {	/* name not found */
  		named.dptr = "DEFAULT";
! 		named.dsize = strlen("DEFAULT")+1;
  		contentd = fetch(named);
! 		if(contentd.dsize == 0) {	/* default not found */
  			dbmclose();
! 			fprintf(errf, "%s:users %s and %s not found\n",
! 				progname, name, "DEFAULT");
! 			return(NO_USER_OR_DEFAULT_NAME);
  		}
  	}
! 	stat = parse_record(name, contentd.dptr, userfd,
! 				&check_first, &reply_first);
! 
! #else /* DBM_MODE */
! 	curParseLine = 0;
! 	while( (stat = user_read(&userfd, curname, line)) == 0 ) {
! 		if( (strcmp(name, curname) != 0)
! 		 && (strcmp("DEFAULT", curname) != 0) ) {
! 			continue;
! 		}
! 		stat = parse_record(name, line, userfd,
! 				&check_first, &reply_first);
! 		break;
  	}
  
! 	if( stat == END_OF_USERS_LIST ) {
! 	    stat = NO_USER_OR_DEFAULT_NAME;
! 	}
! #endif /* DBM_MODE */
  
! 	if( stat ) {
! 		return stat;
  	}
  
  	/* Update the callers pointers */
  	if(reply_first != (VALUE_PAIR *)NULL) {
***************
*** 244,250 ****
  		*reply_pairs = reply_first;
  		return(0);
  	}
! 	return(-1);
  }
  
  #define PARSE_MODE_NAME		0
--- 301,307 ----
  		*reply_pairs = reply_first;
  		return(0);
  	}
! 	return(REPLY_FIRST_IS_NULL);
  }
  
  #define PARSE_MODE_NAME		0
***************
*** 261,284 ****
   *************************************************************************/
  
  static int
! userparse(buffer, first_pair)
! char		*buffer;
  VALUE_PAIR	**first_pair;
  {
  	int		mode;
  	char		attrstr[64];
  	char		valstr[64];
  	DICT_ATTR	*attr;
- 	DICT_ATTR	*dict_attrfind();
  	DICT_VALUE	*dval;
- 	DICT_VALUE	*dict_valfind();
  	VALUE_PAIR	*pair;
  	VALUE_PAIR	*link;
- 	UINT4		ipstr2long();
- 	UINT4		get_ipaddr();
  	struct tm	*tm;
  	time_t		timeval;
  
  	mode = PARSE_MODE_NAME;
  	while(*buffer != '\n' && *buffer != '\0') {
  
--- 318,343 ----
   *************************************************************************/
  
  static int
! userparse(buf, first_pair)
! char		**buf;
  VALUE_PAIR	**first_pair;
  {
  	int		mode;
  	char		attrstr[64];
+ #ifdef ORIG
  	char		valstr[64];
+ #else
+ 	char		valstr[256];
+ #endif
  	DICT_ATTR	*attr;
  	DICT_VALUE	*dval;
  	VALUE_PAIR	*pair;
  	VALUE_PAIR	*link;
  	struct tm	*tm;
  	time_t		timeval;
+ 	char		*buffer;
  
+ 	buffer = *buf;
  	mode = PARSE_MODE_NAME;
  	while(*buffer != '\n' && *buffer != '\0') {
  
***************
*** 294,300 ****
  			fieldcpy(attrstr, &buffer);
  			if((attr = dict_attrfind(attrstr)) ==
  						(DICT_ATTR *)NULL) {
! 				return(-1);
  			}
  			mode = PARSE_MODE_EQUAL;
  			break;
--- 353,362 ----
  			fieldcpy(attrstr, &buffer);
  			if((attr = dict_attrfind(attrstr)) ==
  						(DICT_ATTR *)NULL) {
! 				*buf = buffer;
! 			fprintf(errf, "%s: attribute name %s not found\n",
! 					progname, attrstr);
! 				return(DICT_ATTRFIND_ERR);
  			}
  			mode = PARSE_MODE_EQUAL;
  			break;
***************
*** 306,312 ****
  				buffer++;
  			}
  			else {
! 				return(-1);
  			}
  			break;
  
--- 368,375 ----
  				buffer++;
  			}
  			else {
! 				*buf = buffer;
! 				return(MISSING_EQUALS);
  			}
  			break;
  
***************
*** 316,324 ****
  
  			if((pair = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) ==
  						(VALUE_PAIR *)NULL) {
! 				fprintf(stderr, "%s: no memory\n",
  						progname);
! 				exit(-1);
  			}
  			strcpy(pair->name, attr->name);
  			pair->attribute = attr->value;
--- 379,387 ----
  
  			if((pair = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) ==
  						(VALUE_PAIR *)NULL) {
! 				fprintf(errf, "%s: no memory\n",
  						progname);
! 				exit(MEMORY_ERR);
  			}
  			strcpy(pair->name, attr->name);
  			pair->attribute = attr->value;
***************
*** 325,333 ****
--- 388,410 ----
  			pair->type = attr->type;
  
  			switch(pair->type) {
+ #if defined( BINARY_FILTERS )
+                         case PW_TYPE_FILTER_BINARY:
+                                 /*
+                                  * special case to convert filter to binary
+                                  */
+                                 if( filterBinary( pair, valstr ) == -1 ) {
+                                     free(pair);
+ 				    *buf = buffer;
+                                     return(BINARY_FILTER_ERR);
+                                 }
+ 				pair->size = pair->lvalue;
+                                 break;
+ #endif /* BINARY_FILTERS */
  
  			case PW_TYPE_STRING:
  				strcpy(pair->strvalue, valstr);
+ 				pair->size = strlen(valstr) + 1;
  				break;
  
  			case PW_TYPE_INTEGER:
***************
*** 337,356 ****
  				else if((dval = dict_valfind(valstr)) ==
  							(DICT_VALUE *)NULL) {
  					free(pair);
! 					return(-1);
  				}
  				else {
  					pair->lvalue = dval->value;
  				}
  				break;
  
  			case PW_TYPE_IPADDR:
  				pair->lvalue = get_ipaddr(valstr);
  				break;
  
  			case PW_TYPE_DATE:
! 				timeval = time(0);
  				tm = localtime(&timeval);
  				user_gettime(valstr, tm);
  #ifdef TIMELOCAL
  				pair->lvalue = (UINT4)timelocal(tm);
--- 414,442 ----
  				else if((dval = dict_valfind(valstr)) ==
  							(DICT_VALUE *)NULL) {
  					free(pair);
! 					*buf = buffer;
! 					return(DICT_VALFIND_ERR);
  				}
  				else {
  					pair->lvalue = dval->value;
  				}
+ 				pair->size = sizeof(UINT4);
  				break;
  
  			case PW_TYPE_IPADDR:
  				pair->lvalue = get_ipaddr(valstr);
+ 				pair->size = sizeof(UINT4);
  				break;
  
  			case PW_TYPE_DATE:
! 				timeval = time((time_t *)0);
! 				if( timeval == -1 ) {
! 					log_err("userparse(): time() err\n");
! 					pair->lvalue = 0;
! 					break;
! 				}
  				tm = localtime(&timeval);
+ 
  				user_gettime(valstr, tm);
  #ifdef TIMELOCAL
  				pair->lvalue = (UINT4)timelocal(tm);
***************
*** 357,367 ****
  #else /* TIMELOCAL */
  				pair->lvalue = (UINT4)mktime(tm);
  #endif /* TIMELOCAL */
  				break;
  
  			default:
  				free(pair);
! 				return(-1);
  			}
  			pair->next = (VALUE_PAIR *)NULL;
  			if(*first_pair == (VALUE_PAIR *)NULL) {
--- 443,455 ----
  #else /* TIMELOCAL */
  				pair->lvalue = (UINT4)mktime(tm);
  #endif /* TIMELOCAL */
+ 				pair->size = sizeof(UINT4);
  				break;
  
  			default:
  				free(pair);
! 				*buf = buffer;
! 				return(DEFAULT_PARSE_ERR);
  			}
  			pair->next = (VALUE_PAIR *)NULL;
  			if(*first_pair == (VALUE_PAIR *)NULL) {
***************
*** 382,387 ****
--- 470,476 ----
  			break;
  		}
  	}
+ 	*buf = buffer;
  	return(0);
  }
  
***************
*** 394,400 ****
   *
   *************************************************************************/
  
! static	void
  fieldcpy(string, uptr)
  char	*string;
  char	**uptr;
--- 483,489 ----
   *
   *************************************************************************/
  
! static void
  fieldcpy(string, uptr)
  char	*string;
  char	**uptr;
***************
*** 433,439 ****
   *		 list of reply items which are supplied.
   *
   *************************************************************************/
! 
  user_update(name, user_check, user_reply)
  char		*name;
  VALUE_PAIR	*user_check;
--- 522,528 ----
   *		 list of reply items which are supplied.
   *
   *************************************************************************/
! int
  user_update(name, user_check, user_reply)
  char		*name;
  VALUE_PAIR	*user_check;
***************
*** 441,473 ****
  {
  	FILE		*oldfd;
  	FILE		*userfd;
! 	char		buffer[256];
  	char		buffer1[256];
  	int		namelen;
  	int		mode;
  
! 	sprintf(buffer, "%s/%s", radius_dir, RADIUS_USERS);
  	sprintf(buffer1, "%s/%s", radius_dir, RADIUS_HOLD);
  
  	/* Move the user table to a temporary location */
  	if(rename(buffer, buffer1) != 0) {
! 		fprintf(stderr, "%s: Couldn't rename %s\n",
  				progname, buffer);
! 		return(-1);
  	}
  
! 	/* Open the old user file (using the temporary name */
  	if((oldfd = fopen(buffer1, "r")) == (FILE *)NULL) {
! 		fprintf(stderr, "%s: Couldn't open %s for reading\n",
  				progname, buffer1);
! 		exit(-1);
  	}
  
  	/* Open the new user file */
  	if((userfd = fopen(buffer, "w")) == (FILE *)NULL) {
! 		fprintf(stderr, "%s: Couldn't open %s for writing\n",
  				progname, buffer);
! 		exit(-1);
  	}
  
  	mode = FIND_MODE_NAME;
--- 530,562 ----
  {
  	FILE		*oldfd;
  	FILE		*userfd;
! 	char		buffer[1024];
  	char		buffer1[256];
  	int		namelen;
  	int		mode;
  
! 	sprintf(buffer, "%s/%s", radius_dir, radius_users);
  	sprintf(buffer1, "%s/%s", radius_dir, RADIUS_HOLD);
  
  	/* Move the user table to a temporary location */
  	if(rename(buffer, buffer1) != 0) {
! 		fprintf(errf, "%s: Couldn't rename %s\n",
  				progname, buffer);
! 		return(USERFILE_RENAME_FAILED);
  	}
  
! 	/* Open the old user file (using the temporary name) */
  	if((oldfd = fopen(buffer1, "r")) == (FILE *)NULL) {
! 		fprintf(errf, "%s: Couldn't open %s for reading\n",
  				progname, buffer1);
! 		exit(USERFILE_READ_ERR);
  	}
  
  	/* Open the new user file */
  	if((userfd = fopen(buffer, "w")) == (FILE *)NULL) {
! 		fprintf(errf, "%s: Couldn't open %s for writing\n",
  				progname, buffer);
! 		exit(USERFILE_WRITE_ERR);
  	}
  
  	mode = FIND_MODE_NAME;
***************
*** 532,542 ****
  	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
  
  user_gettime(valstr, tm)
  char		*valstr;
  struct tm	*tm;
  {
! 	char	buffer[48];
  	int	i;
  
  	/* Get the month */
--- 621,637 ----
  	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
  
+ static void
  user_gettime(valstr, tm)
  char		*valstr;
  struct tm	*tm;
  {
! #if(0)
! 	/* Use this code only if strtok() is not available */
! 
! 	/*
! 	 * Date format: "Mmm.dd.yyyy"
! 	 */
  	int	i;
  
  	/* Get the month */
***************
*** 552,555 ****
--- 647,688 ----
  
  	/* Now the year */
  	tm->tm_year = atoi(&valstr[7]) - 1900;
+ #else
+ 	/*
+ 	 * Date format: "Mmm+[ \t,]+d+[ \t,]+yyyy"
+ 	 */
+ 	int	i;
+ 	char	datestr[80];
+ 	char	*str;
+ 
+ 	strncpy(datestr, valstr, 79);
+ 	datestr[79] = '\0';
+ 
+ 	/* Get the month */
+ 	str = strtok(datestr, " \t,");
+ 	if( !str ) {
+ 		return;
+ 	}
+ 	for(i = 0;i < 12;i++) {
+ 		if(strncmp(months[i], str, 3) == 0) {
+ 			tm->tm_mon = i;
+ 			break;
+ 		}
+ 	}
+ 
+ 	/* Get the Day */
+ 	str = strtok((char *)0, " \t,");
+ 	if( !str ) {
+ 		return;
+ 	}
+ 
+ 	tm->tm_mday = atoi(str);
+ 
+ 	/* Now the year */
+ 	str = strtok((char *)0, " \t,");
+ 	if( !str ) {
+ 		return;
+ 	}
+ 	tm->tm_year = atoi(str) - 1900;
+ #endif
  }
diff -c -N radiusd//usr_read.c ascendd//usr_read.c
*** radiusd//usr_read.c
--- ascendd//usr_read.c	Wed Dec 20 11:02:26 1995
***************
*** 0 ****
--- 1,364 ----
+ /*
+  *
+  *	RADIUS
+  *	Remote Authentication Dial In User Service
+  *
+  * ASCEND: @(#)usr_read.c	1.5 (95/07/25 00:55:42)
+  *
+  *	Livingston Enterprises, Inc.
+  *	6920 Koll Center Parkway
+  *	Pleasanton, CA   94566
+  *
+  *	Copyright 1992 Livingston Enterprises, 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 Livingston Enterprises, 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 Livingston Enterprises, Inc.   
+  *
+  *	Livingston Enterprises, 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 Ascend Communications, Inc.
+  *      All rights reserved.
+  *
+  *	Permission to copy all or part of this material for any purpose is
+  *	granted provided that the above copyright notice and this paragraph
+  *	are duplicated in all copies.  THIS SOFTWARE IS PROVIDED ``AS IS''
+  *	AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+  *	LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+  *	FOR A PARTICULAR PURPOSE.
+  */
+ 
+ #include	<sys/types.h>
+ #include	<sys/socket.h>
+ #include	<sys/time.h>
+ #include	<sys/file.h>
+ #include	<netinet/in.h>
+ 
+ #include	<stdio.h>
+ #include	<unistd.h>
+ #include	<netdb.h>
+ #include	<string.h>
+ #include	<pwd.h>
+ #include	<time.h>
+ #include	<ctype.h>
+ 
+ #include	"radius.h"
+ 
+ extern char	*progname;
+ extern char	*radius_dir;
+ extern char	*radius_users;
+ extern FILE	*errf;
+ int		curParseLine;	/* current line being parsed */
+ 
+ #define FIND_MODE_NAME	0
+ #define FIND_MODE_REPLY	1
+ #define FIND_MODE_SKIP	2
+ #define FIND_MODE_FLUSH	3
+ 
+ #if defined(__STDC__) && (__STDC__ == 1)
+ #	define	P__(s)	s
+ #else
+ #	define	P__(s)	(/* s */)
+ #endif
+ 
+ extern void warn P__((char *msg));
+ static int test_eof P__((FILE *userfd));
+ static int probably_eor P__((FILE *userfd));
+ extern int user_read P__((FILE **userfd, char *name, char *content));
+ 
+ int	warning;
+ 
+ /*************************************************************************
+  *
+  *	Function: test_eof
+  *
+  *	Purpose: See if we are at the end of file (before we actually
+  *		 get there).
+  *
+  *************************************************************************/
+ 
+ static int
+ test_eof(userfd)
+ FILE	*userfd;
+ {
+ 	int	c;
+ 	int	status;
+ 
+ 	c = fgetc(userfd);
+ 	if( c == EOF ) {
+ 		status = TRUE;
+ 	}
+ 	else {
+ 		if( ungetc(c, userfd) != c ) {
+ 			perror("test_eof");
+ 			warn("Problem with ungetc");
+ 		}
+ 		status = FALSE;
+ 	}
+ 	return status;
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: probably_eor
+  *
+  *	Purpose: Simple heuristic to see if the missing comma really
+  *		 indicates the end of the record or if the user simply
+  *		 forgot to put one in.
+  *
+  *		 If the next line starts with a space or a tab, assume
+  *		 the user forgot the comma, else it's really the end.
+  *		 If there is no next line, then it's also the end of the
+  *		 record.
+  *
+  *		NOTE: missing commas followed by comment lines, followed
+  *			by additional lines of the record will NOT be
+  *			so interpreted; the next non-comment line will be
+  *			assumed to be the start of a new record.
+  *
+  *************************************************************************/
+ 
+ static int
+ probably_eor(userfd)
+ FILE	*userfd;
+ {
+ 	int	c;
+ 	int	status;
+ 
+ 	c = fgetc(userfd);
+ 	if( c == EOF ) {
+ 		status = TRUE;
+ 	}
+ 	else if( (c == ' ') || (c == '\t') ) {
+ 		if( ungetc(c, userfd) != c ) {
+ 			perror("probably_eor");
+ 			warn("Problem with ungetc");
+ 		}
+ 		status = FALSE;
+ 	}
+ 	else {
+ 		if( ungetc(c, userfd) != c ) {
+ 			perror("probably_eor");
+ 			warn("Problem with ungetc");
+ 		}
+ 		status = TRUE;
+ 	}
+ 	return status;
+ }
+ 
+ /*************************************************************************
+  *
+  *	Function: user_read
+  *
+  *	Purpose: Return the next user in the database - name is key content
+  *		 is 2 strings - check values, and reply values seperated
+  *		 by a newline.
+  *
+  *************************************************************************/
+ 
+ int
+ user_read(userfd, name, content)
+ FILE	**userfd;
+ char	*name;
+ char	*content;
+ {
+ 	char		buf[4 * 1024];
+ 	char		*ptr;
+ 	int		mode;
+ 	int		submode;
+ 	long		fpos;
+ 	int		replyCount = 0;
+ 
+ 	/*
+ 	 * Open the user table
+ 	 */
+ 	if(*userfd == (FILE *)NULL) {
+ 		sprintf(buf, "%s/%s", radius_dir, radius_users);
+ 		if((*userfd = fopen(buf, "r")) == (FILE *)NULL) {
+ 			fprintf(errf, "%s: Couldn't open %s for reading\n",
+ 					progname, buf);
+ 			exit(USERFILE_READ_ERR);
+ 		}
+ 		curParseLine = 0;
+ 	}
+ 
+ 	mode = FIND_MODE_NAME;
+ 	submode = FIND_MODE_NAME;
+ 	fpos = ftell(*userfd);
+ 	while(fgets(buf, sizeof(buf), *userfd) != (char *)NULL) {
+ 		curParseLine++;
+ 		/* skip lines starting with '#' or newline
+ 			name is the string until the first
+ 				blank, tab, newline, or NUL
+ 			if no name, skip to next record
+ 			if name, but no password on same line,
+ 				start over on next line 
+ 			Alert the user about missing names or passwords,
+ 			and commas at the end of the first record line
+ 		*/
+ 
+ 		if(mode == FIND_MODE_NAME) {
+ 			/*
+ 			 * Find the entry starting with the users name
+ 			 */
+ 			if( (*buf != '#') && (*buf != '\n') ) {
+ 				char *origname = name;
+ 
+ 				*name = '\0';	/* name found flag */
+ 				ptr = buf;
+ 				while( (*ptr != ' ') && (*ptr != '\t')
+ 				    && (*ptr != '\n') && (*ptr != '\0') ) {
+ 					*name++ = *ptr++;
+ 				}
+ 				if( *origname == '\0' ) {
+ 					name = origname;
+ 					if( submode == FIND_MODE_SKIP ) {
+ 						continue;
+ 					}
+ 					while( *ptr == ' ' || *ptr == '\t') {
+ 						ptr++;
+ 					}
+ 					if( *ptr == '\n' || *ptr == '\0') {
+ 						warn("No name or attributes\n\t- skipping blank line");
+ 					}
+ 					else {
+ 						warn("No name found\n\t- possible missing comma on a previous line\n\t... skipping to next record");
+ 						submode = FIND_MODE_SKIP;
+ 					}
+ 					continue;	/* no name found */
+ 				}
+ 				if( (*ptr == '\n') || (*ptr == '\0') ) {
+ 					name = origname;
+ 					sprintf(buf,
+ 						"Missing mandatory password\n\tfor user '%s'", name);
+ 					warn(buf);
+ 					submode = FIND_MODE_SKIP;
+ 					continue;	/* no pwd on line */
+ 				}
+ 				*name = '\0';	/* NUL-terminate name */
+ 				ptr++;
+ 				while(*ptr == ' ' || *ptr == '\t') {
+ 					ptr++;
+ 				}
+ 				*content = 0;
+ 				if( (*ptr == '\n') || (*ptr == '\0') ) {
+ 					name = origname;
+ 					sprintf(buf,
+ 						"Missing mandatory password\n\tfor user '%s'", name);
+ 					warn(buf);
+ 					submode = FIND_MODE_SKIP;
+ 					continue;	/* no pwd on line */
+ 				}
+ 				submode = FIND_MODE_NAME;
+ 				strcpy(content, ptr);
+ 				content += strlen(content);
+ 
+ 				/* if line ends with ",\n" then whine */
+ 				if( content[-2] == ',' ) {
+ 					warn("Trailing comma on name-pwd line");
+ 				}
+ 				mode = FIND_MODE_REPLY;
+ 				replyCount = 0;	/* no reply attributes yet */
+ 				if( test_eof(*userfd) ) {
+ 					warn("Premature end of file");
+ 					return 0;
+ 				}
+ 			}
+ 		}
+ 		else {	/* not first line of record */
+ 			/* line must start with tab or blank
+ 			   if it starts with a '#' skip it, but warn the
+ 			     user since previously, flat file searches would
+ 			     terminate at comment lines inside a record.
+ 			   if there is a comma on the last line of the
+ 			     record warn the user.
+ 			   if there is no comma but it is not the last
+ 			     line of the record then insert one
+ 			*/
+ 			replyCount++;
+ 			if(*buf == ' ' || *buf == '\t') {
+ 				ptr = buf;
+ 				while(*ptr == ' ' || *ptr == '\t') {
+ 					ptr++;
+ 				}
+ 				if( *ptr == '\n' || *ptr == '\0' ) {
+ 					warn("No attributes on line\n\t- assuming end of record");
+ 					return 0;
+ 				}
+ 				strcpy(content, ptr);
+ 				content += strlen(content);
+ 				content -= 2;
+ 				while(*content == ' ' || *content == '\t' ) {
+ 					content--;
+ 				}
+ 				content++;
+ 				*content = '\0';
+ 
+ 				/* check for end of record */
+ 				if(*(content - 1) != ',') {
+ 					/* double-check */
+ 					if( probably_eor(*userfd) ) {
+ 						return(0);
+ 					}
+ 					else {
+ 						warn("Missing comma at eol");
+ 						/* force a comma */
+ 						*content++ = ',';
+ 						*content = '\0';
+ 					}
+ 				}
+ 				if( test_eof(*userfd) ) {
+ 					warn("Premature end of file");
+ 					return 0;
+ 				}
+ 			}
+ 			else if( *buf == '#' ) {
+ 				warn("Comment in record");
+ 				if( test_eof(*userfd) ) {
+ 					warn("Premature end of file");
+ 					return 0;
+ 				}
+ 				else {
+ 					continue;
+ 				}
+ 			}
+ 			else if( *buf == '\n' ) {
+ 				if( replyCount > 1 ) {
+ 					warn("Trailing comma on last record");
+ 				}
+ 				return(0);
+ 			}
+ 			else {
+ 				/* We are done */
+ 				warn("No tab before attribute\n\t- assuming end of record and rescanning");
+ 				fseek(*userfd, fpos, SEEK_SET);
+ 				curParseLine--;
+ 				replyCount--;
+ 				return(0);
+ 			}
+ 		}
+ 		fpos = ftell(*userfd);
+ 	}
+ 	fclose(*userfd);
+ 	*userfd = (FILE *)NULL;
+ 	return(END_OF_USERS_LIST);
+ }
+ 
+ void
+ warn(msg)
+ char	*msg;
+ {
+ 	if( !warning ) {
+ 		return;
+ 	}
+ 	fprintf(errf, "%s: %s/%s: line %d: Warning: %s\n",
+ 		progname, radius_dir, radius_users, curParseLine, msg);
+ }
+ 
diff -c -N radiusd//util.c ascendd//util.c
*** radiusd//util.c	Tue Dec 27 09:32:30 1994
--- ascendd//util.c	Wed Dec 20 09:39:05 1995
***************
*** 3,9 ****
--- 3,11 ----
   *	RADIUS
   *	Remote Authentication Dial In User Service
   *
+  * ASCEND: @(#)util.c	1.2 (95/07/25 00:55:43)
   *
+  *
   *	Livingston Enterprises, Inc.
   *	6920 Koll Center Parkway
   *	Pleasanton, CA   94566
***************
*** 38,45 ****
--- 40,49 ----
  #include	<pwd.h>
  #include	<time.h>
  #include	<ctype.h>
+ #include	<stdlib.h>
  
  #include	"radius.h"
+ #include	"protos.h"
  
  /*************************************************************************
   *
***************
*** 64,70 ****
  		ipaddr2str(hstname, ipaddr);
  		return(hstname);
  	}
! 	return(hp->h_name);
  }
  
  /*************************************************************************
--- 68,74 ----
  		ipaddr2str(hstname, ipaddr);
  		return(hstname);
  	}
! 	return (char *)(hp->h_name);
  }
  
  /*************************************************************************
***************
*** 81,88 ****
  char	*host;
  {
  	struct hostent *hp;
- 	static char	buffer[32];
- 	UINT4		ipstr2long();
  
  	if(good_ipaddr(host) == 0) {
  		return(ipstr2long(host));
--- 85,90 ----
***************
*** 101,106 ****
--- 103,109 ----
   *
   *************************************************************************/
  
+ int
  good_ipaddr(addr)
  char	*addr;
  {
***************
*** 142,147 ****
--- 145,151 ----
   *
   *************************************************************************/
  
+ void
  ipaddr2str(buffer, ipaddr)
  char	*buffer;
  UINT4	ipaddr;
***************
*** 168,173 ****
--- 172,178 ----
   *
   *************************************************************************/
  
+ void
  pairfree(pair)
  VALUE_PAIR	*pair;
  {
diff -c -N radiusd//version.c ascendd//version.c
*** radiusd//version.c	Fri Jan  6 13:58:16 1995
--- ascendd//version.c	Wed Dec 20 11:10:30 1995
***************
*** 3,9 ****
--- 3,11 ----
   *	RADIUS
   *	Remote Authentication Dial In User Service
   *
+  * ASCEND: @(#)version.c	1.4 (95/12/19 13:24:45)
   *
+  *
   *	Livingston Enterprises, Inc.
   *	6920 Koll Center Parkway
   *	Pleasanton, CA   94566
***************
*** 29,34 ****
--- 31,37 ----
  "@(#)version.c	1.2 Copyright 1992 Livingston Enterprises Inc";
  
  #include        <sys/types.h>
+ #include	<unistd.h>
  #include	<stdio.h>
  #include	"radius.h"
  
***************
*** 39,45 ****
   *  would like a range of versions allocated for your use.
   */
  
! #define		VERSION		"1.16 95/01/06"
  
  /*************************************************************************
   *
--- 42,56 ----
   *  would like a range of versions allocated for your use.
   */
  
! #define		VERSION		"1.16 (plus Ascend extensions) 95/12/20"
! 
! #if defined(__STDC__) && (__STDC__ == 1)
! #	define	P__(s)	s
! #else
! #	define	P__(s)	(/* s */)
! #endif
! 
! extern void radversion P__((void));
  
  /*************************************************************************
   *
***************
*** 49,66 ****
   *
   *************************************************************************/
  
! version()
  {
- 
  	fprintf(stderr, "%s: RADIUS version %s\n", progname, VERSION);
  
  	/* here are all the conditional feature flags */
! #if defined(DBM)
! 	fprintf(stderr," DBM");
  #endif
  #if defined(NOSHADOW)
  	fprintf(stderr," NOSHADOW");
  #endif
  
  	/* here are all the system definitions compilation uses */
  #if defined(__alpha)
--- 60,92 ----
   *
   *************************************************************************/
  
! void
! radversion()
  {
  	fprintf(stderr, "%s: RADIUS version %s\n", progname, VERSION);
  
  	/* here are all the conditional feature flags */
! #if defined(DBM_MODE)
! 	fprintf(stderr," DBM_MODE");
  #endif
  #if defined(NOSHADOW)
  	fprintf(stderr," NOSHADOW");
  #endif
+ #if defined(BINARY_FILTERS)
+ 	fprintf(stderr," BINARY_FILTERS");
+ #endif
+ #if defined( ASCEND_SECRET )
+ 	fprintf(stderr," ASCEND_SECRET");
+ #endif
+ #if defined(ASCEND_LOGOUT)
+ 	fprintf(stderr," ASCEND_LOGOUT");
+ #endif
+ #if defined(SAFEWORD)
+ 	fprintf(stderr, " SafeWord");
+ #endif
+ #if defined(ACE)
+ 	fprintf(stderr, " ACE");
+ #endif
  
  	/* here are all the system definitions compilation uses */
  #if defined(__alpha)
***************
*** 72,84 ****
  #if defined(aix)
  	fprintf(stderr," aix");
  #endif
! #if defined(bsdi)
  	fprintf(stderr," bsdi");
  #endif
! #if defined(sun)
  	fprintf(stderr," sun");
  #endif
! #if defined(sys5)
  	fprintf(stderr," sys5");
  #endif
  #if defined(unixware)
--- 98,112 ----
  #if defined(aix)
  	fprintf(stderr," aix");
  #endif
! #if defined(BSDI)
  	fprintf(stderr," bsdi");
  #endif
! #if defined(sun) || defined(OSUN)
  	fprintf(stderr," sun");
  #endif
! #if defined(SOLARIS)
! 	fprintf(stderr," SOLARIS");
! #elif defined(sys5)
  	fprintf(stderr," sys5");
  #endif
  #if defined(unixware)
