Initial "gts1" commit. rel_F4_0_3_alpha_8_gts1
authorshort <>
Sat, 28 Apr 2001 13:13:08 +0000 (13:13 +0000)
committershort <>
Sat, 28 Apr 2001 13:13:08 +0000 (13:13 +0000)
114 files changed:
.exrc [new file with mode: 0644]
CHANGES
INSTALL
Makefile.am [new file with mode: 0644]
Makefile.in [deleted file]
README.LDAP [new file with mode: 0644]
README.PAM
acconfig.h [new file with mode: 0644]
acct.c
acct.h [new file with mode: 0644]
authen.c
authen.h [new file with mode: 0644]
author.c
author.h [new file with mode: 0644]
autogen [new file with mode: 0755]
autogen-body [new file with mode: 0644]
cfgeval.c [new file with mode: 0644]
cfgeval.h [new file with mode: 0644]
cfgfile.c
cfgfile.h [new file with mode: 0644]
choose_authen.c
choose_authen.h [new file with mode: 0644]
config.c [deleted file]
config.guess [deleted file]
config.h.in [deleted file]
config.sub [deleted file]
configure [deleted file]
configure.in
convert.pl
db.c
db.h [new file with mode: 0644]
db_mysql.c
db_mysql.h [new file with mode: 0644]
db_null.c
db_null.h [new file with mode: 0644]
db_pgsql.c
db_pgsql.h [new file with mode: 0644]
default_fn.c
default_fn.h [new file with mode: 0644]
default_v0_fn.c
default_v0_fn.h [new file with mode: 0644]
do_acct.c
do_acct.h [new file with mode: 0644]
do_author.c
do_author.h [new file with mode: 0644]
dump.c
dump.h [new file with mode: 0644]
enable.c
enable.h [new file with mode: 0644]
encrypt.c
encrypt.h [new file with mode: 0644]
expire.c
expire.h
generate_passwd.c
hash.c
hash.h [new file with mode: 0644]
install-sh [deleted file]
ldap.c [deleted file]
ldap.h [deleted file]
ldap_author.c
ldap_author.h
main.c
main.h [new file with mode: 0644]
maxsess.c
maxsess.h [new file with mode: 0644]
md4.c
md4.h
md5.c
md5.h
mschap.h
packet.c
packet.h [new file with mode: 0644]
parse.c
parse.h
programs.c
programs.h [new file with mode: 0644]
pw.c
pw.h [new file with mode: 0644]
pwlib.c
pwlib.h [new file with mode: 0644]
regexp.3 [deleted file]
regexp.c [deleted file]
regexp.h [deleted file]
regmagic.h [deleted file]
report.c
report.h [new file with mode: 0644]
sendauth.c
sendauth.h [new file with mode: 0644]
sendpass.c
sendpass.h [new file with mode: 0644]
skey_fn.c
skey_fn.h [new file with mode: 0644]
stamp-h [deleted file]
tac_pam.c
tac_pam.h [new file with mode: 0644]
tac_plus.1
tac_plus.c [deleted file]
tac_plus.cfg
tac_plus.h
tac_plus.init
tac_plus.pam [new file with mode: 0644]
tac_plus.rotate
tac_plus.spec.in [new file with mode: 0644]
tac_plus.sql
tac_regexp.c
tac_regexp.h
tac_regmagic.h
tcpwrap.c
tcpwrap.h [new file with mode: 0644]
time_limit.c
time_limit.h
users_guide
utils.c
utils.h [new file with mode: 0644]

diff --git a/.exrc b/.exrc
new file mode 100644 (file)
index 0000000..d51ef7d
--- /dev/null
+++ b/.exrc
@@ -0,0 +1,2 @@
+set tabstop=8
+set shiftwidth=4
diff --git a/CHANGES b/CHANGES
index fdab6d2..4fc866b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,7 +1,7 @@
 >Changes from Release 0.0 to release 0.1
 ---------------------------------------
 
-You must now say "default attribute = permit" instead of 
+You must now say "default attribute = permit" instead of
 default authorization = permit" when configuring service
 defaults
 
@@ -81,7 +81,7 @@ Updated the users guide.
 
 Changes from Release 1.0 to release 1.1
 ---------------------------------------
-Release 1.1 corresponds to RCS version 1.64 of tac_plus 
+Release 1.1 corresponds to RCS version 1.64 of tac_plus
 (see tac_plus -v)
 
 A typo in the Solaris section of the Makefile has been fixed.
@@ -143,7 +143,7 @@ deprecated in favour of "default authorization = permit".
 A bug in the handling of substring AV pairs which caused the attribute
 "addr" to erroneously match "addr-pool" has been fixed.
 
-Added new files: enable.c generate_passwd.c skey_fn.c 
+Added new files: enable.c generate_passwd.c skey_fn.c
 
 New #defines have been added to make it easier to port tacacs+ to new
 systems.
@@ -197,7 +197,7 @@ have (see MAXSESS in the user's guide).
 The accounting "more" bit is gone (It was deprecated from the spec).
 
 Hooks are now in so that if you have DES code, you can do ARAP more
-securely, per the new protocol. 
+securely, per the new protocol.
 
 The packet read/write routines now handle exceptions more gracefully.
 
diff --git a/INSTALL b/INSTALL
index 3884e10..a379cd0 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -3,15 +3,15 @@ The installation is very basic.
 just type :
 ./configure
 (if you like to learn the configure parameters try --help option with configure )
-make install 
+make install
 
 Thats all.
 
 This packet consist some helper file  to using tacacs+ easly.
 tac_plus.cfg: Example tacacs+ config file
-README.PAM: For PAM supported systems 
+README.PAM: For PAM supported systems
 tac_plus.init: For starting and stoping tacacs+
-tac_plus.sql: table description (Mysql) 
+tac_plus.sql: table description (Mysql)
 
 Sorry for this short description.:(
 
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..8d609b1
--- /dev/null
@@ -0,0 +1,126 @@
+# Please NOTE:  None of the TACACS code available here comes with any
+# warranty or support.
+# Copyright (c) 1995-1998 by Cisco systems, 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 of the software and
+# supporting documentation, the name of Cisco Systems, 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 modification, copying and distribution is by
+# permission of Cisco Systems, Inc.
+#
+# Cisco Systems, Inc. makes no representations about the suitability of this
+# software for any purpose.  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.
+
+
+AUTOMAKE_OPTIONS       = foreign
+
+sbin_PROGRAMS          = tac_plus
+bin_PROGRAMS           = generate_passwd
+man_MANS               = tac_plus.1
+noinst_MANS            = tac_regexp.3
+tacacssysconfdir       = $(sysconfdir)/tacacs
+tacacssysconf_DATA     = tac_plus.cfg
+EXTRA_DIST             = \
+       CHANGES                 \
+       README.LDAP             \
+       README.PAM              \
+       users_guide             \
+       tac_plus.spec.in        \
+       convert.pl              \
+       tac_plus.cfg            \
+       tac_plus.init           \
+       tac_plus.rotate         \
+       tac_plus.sql            \
+       tac_plus.pam            \
+       $(tacacssysconf_DATA)   \
+       $(man_MANS)             \
+       $(noinst_MANS)
+
+generate_passwd_SOURCES        = generate_passwd.c
+
+tac_plus_SOURCES       = \
+       acct.c          acct.h          \
+       authen.c        authen.h        \
+       author.c        author.h        \
+       cfgfile.c       cfgfile.h       \
+       cfgeval.c       cfgeval.h       \
+       choose_authen.c choose_authen.h \
+       default_fn.c    default_fn.h    \
+       default_v0_fn.c default_v0_fn.h \
+       do_acct.c       do_acct.h       \
+       do_author.c     do_author.h     \
+       dump.c          dump.h          \
+       enable.c        enable.h        \
+       encrypt.c       encrypt.h       \
+       expire.c        expire.h        \
+       hash.c          hash.h          \
+       main.c          main.h          \
+       md5.c           md5.h           \
+       packet.c        packet.h        \
+       parse.c         parse.h         \
+       programs.c      programs.h      \
+       pw.c            pw.h            \
+       pwlib.c         pwlib.h         \
+       report.c        report.h        \
+       sendauth.c      sendauth.h      \
+       sendpass.c      sendpass.h      \
+       time_limit.c    time_limit.h    \
+       utils.c         utils.h         \
+       mschap.h        \
+       tac_regmagic.h  \
+       tac_plus.h
+
+EXTRA_tac_plus_SOURCES = $(cond)
+tac_plus_LDFLAGS       = $(conf_LDFLAGS)
+# $(use_o) has to be BEFORE $(conf_LDADD)!  (for library dependencies)
+tac_plus_LDADD         = $(use_o) $(conf_LDADD)
+tac_plus_DEPENDENCIES  = $(use_o)
+use                    = @COND_USE@
+use_o                  = $(filter %.o,$(use:.c=.o))
+
+cond_DB                = db.c          db.h
+cond_DB_MYSQL  = db_mysql.c    db_mysql.h
+cond_DB_NULL   = db_null.c     db_null.h
+cond_DB_PGSQL  = db_pgsql.c    db_pgsql.h
+cond_USE_LDAP  = ldap_author.c ldap_author.h
+cond_MAXSESS   = maxsess.c     maxsess.h
+cond_MSCHAP    = md4.c         md4.h
+cond_SKEY      = skey_fn.c     skey_fn.h
+cond_USE_PAM   = tac_pam.c     tac_pam.h
+cond_TCPWRAPPER        = tcpwrap.c     tcpwrap.h
+cond_WITH_INCLUDED_REGEX = \
+                 tac_regexp.c  tac_regexp.h
+
+cond   = \
+       $(cond_DB)              \
+       $(cond_DB_MYSQL)        \
+       $(cond_DB_NULL)         \
+       $(cond_DB_PGSQL)        \
+       $(cond_USE_LDAP)        \
+       $(cond_MAXSESS)         \
+       $(cond_MSCHAP)          \
+       $(cond_SKEY)            \
+       $(cond_USE_PAM)         \
+       $(cond_TCPWRAPPER)      \
+       $(cond_WITH_INCLUDED_REGEX)
+
+
+# These rules were not migrated from Makefile.in as I don't have
+# (and I don't know) 'purify' tool:
+#
+# purecov: $(OBJS) $(LIBS)
+#      purecov -follow-child-processes -handle-signals=SIGTERM \
+#          -append-logfile -log-file=purecov.log \
+#          -cache-dir=`pwd` \
+#          $(CC) -o tac_plus $(CFLAGS) $(OBJS) $(LIBS) $(OSLIBS)
+# 
+# purify: $(OBJS) $(LIBS)
+#      purify -follow-child-processes=yes -log-file=./tac_plus_purify.log \
+#          -handle-signals=SIGTERM -cache-dir=. \
+#          $(CC) -o tac_plus $(CFLAGS) $(OBJS) $(LIBS) $(OSLIBS)
diff --git a/Makefile.in b/Makefile.in
deleted file mode 100644 (file)
index b5af4b6..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-# Please NOTE:  None of the TACACS code available here comes with any
-# warranty or support.
-# Copyright (c) 1995-1998 by Cisco systems, 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 of the software and
-# supporting documentation, the name of Cisco Systems, 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 modification, copying and distribution is by
-# permission of Cisco Systems, Inc.   
-# 
-# Cisco Systems, Inc. makes no representations about the suitability of this
-# software for any purpose.  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. 
-
-SHELL = /bin/sh
-VPATH = @srcdir@
-
-top_srcdir = @top_srcdir@
-srcdir = @srcdir@
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-bindir = $(exec_prefix)/bin
-sbindir = $(exec_prefix)/sbin
-infodir = $(prefix)/info
-libdir = $(prefix)/lib/gnudl
-mandir = $(prefix)/man/man1
-
-CC = @CC@
-CPPFLAGS = @CPPFLAGS@ 
-FLAGS = $(CPPFLAGS) @CFLAGS@
-LDFLAGS = @LDFLAGS@
-OSLIBS = @LIBS@
-DEFINES = @DEFINES@
-OS = @OS@
-PIDFILE = @PIDFILE@
-DB = @DB@
-
-# For AIX
-# See /usr/lpp/bos/bsdport on your system for details of how to define bsdcc
-# CC=bsdcc
-# OS=-DAIX
-
-# For HP/UX uncomment the following line
-# OS=-DHPUX
-
-# For MIPS, uncomment the following line
-# OS=-DMIPS
-
-# For Solaris (SUNOS 5.3, 5.4, 5.5, 5.6) uncomment the following two lines
-#OS=-DSOLARIS
-#OSLIBS=-lsocket -lnsl
-
-# For FreeBSD
-# OS=-DFREEBSD
-# You may also need to add:
-# OSLIBS=-lcrypt
-# NOTE: If you want your password encryption to be compatible with
-# e.g. SunOS, you may need to instead use:
-# OSLIBS=-ldescrypt
-
-# For LINUX
-# OS=-DLINUX
-#
-# On REDHAT 5.0 systems, or systems that use the new glibc,
-# you might instead need the following:
-#OS=-DLINUX -DGLIBC
-#OSLIBS=-lcrypt
-
-# Athough invoked as root, most of the time you don't want tac_plus to
-# be running as root. If USERID and GROUPID are set, tac_plus will
-# attempt change to run as that user & group after reading the
-# configuration file and obtaining a privileged socket. If you always
-# want tac_plus to run as root, then just comment out the FLAGS line.
-
-# USERID  = 1500
-# GROUPID = 25
-# FLAGS   = -DTAC_PLUS_USERID=$(USERID) -DTAC_PLUS_GROUPID=$(GROUPID)
-
-# Definitions for SKEY functionality
-# DEFINES = -DSKEY
-# LIBS = ../crimelab/skey/src/libskey.a
-# INCLUDES = -I../crimelab/skey/src
-
-# Debugging flags
-DEBUG = 
-
-# Opt flags
-OPT_FLAGS = 
-
-# Enforce a limit on maximum sessions per user. See the user's guide
-# for more information.
-#MAXSESS = -DMAXSESS
-
-# Microsoft CHAP extension support. See the user's guide for more
-# information.
-# MSCHAP = -DMSCHAP
-# MSCHAP_DES = -DMSCHAP_DES
-# MSCHAP_MD4_SRC = md4.c
-
-# On startup, tac_plus creates the file /etc/tac_plus.pid (if
-# possible), containing its process id. Uncomment and modify the
-# following line to change this filename
-
-#PIDFILE = -DTAC_PLUS_PIDFILE=\"/var/run/tac_plus.pid\" 
-
-#
-# End of customisable section of Makefile
-#
-
-CFLAGS = $(DEBUG) $(OPT_FLAGS) $(DEFINES) $(INCLUDES) $(FLAGS) $(OS) $(PIDFILE) $(LDFLAGS) $(DB) 
-
-HFILES = expire.h parse.h regmagic.h md5.h regexp.h tac_plus.h 
-
-SRCS = acct.c authen.c author.c choose_authen.c config.c do_acct.c \
-       do_author.c dump.c encrypt.c expire.c $(MSCHAP_MD4_SRC) md5.c \
-       packet.c report.c sendauth.c tac_plus.c utils.c pw.c hash.c \
-       parse.c regexp.c programs.c enable.c pwlib.c default_fn.c \
-       skey_fn.c default_v0_fn.c sendpass.c maxsess.c tac_pam.c \
-       db.c db_null.c db_mysql.c db_pgsql.c tcpwrap.c ldap.c time_limit.c
-
-OBJS = $(SRCS:.c=.o)
-
-all:
-       @echo "Please edit the Makefile and then make tac_plus"
-
-tac_plus: $(OBJS) $(LIBS) generate_passwd
-       $(CC) -o tac_plus $(CFLAGS) $(OBJS) $(LIBS) $(OSLIBS) 
-       strip tac_plus
-
-purecov: $(OBJS) $(LIBS)
-       purecov -follow-child-processes -handle-signals=SIGTERM \
-           -append-logfile -log-file=purecov.log \
-           -cache-dir=`pwd` \
-           $(CC) -o tac_plus $(CFLAGS) $(OBJS) $(LIBS) $(OSLIBS)
-
-purify: $(OBJS) $(LIBS)
-       purify -follow-child-processes=yes -log-file=./tac_plus_purify.log \
-           -handle-signals=SIGTERM -cache-dir=. \
-           $(CC) -o tac_plus $(CFLAGS) $(OBJS) $(LIBS) $(OSLIBS)
-
-generate_passwd:
-       $(CC) $(CFLAGS) -o generate_passwd generate_passwd.c $(OSLIBS)
-
-clean:
-       -rm -f *.o *~ *.BAK core tac_plus generate_passwd
-
-distclean: clean
-       -rm -f Makefile config.h config.status config.cache config.log
-
-clean_obj:
-       -rm -f *.o *~ *.BAK
-
-make_dir:
-       mkdir -p  $(bindir)
-       mkdir -p  $(sbindir)
-       mkdir -p  $(mandir)
-install: make_dir
-       cp tac_plus $(sbindir)/
-       cp generate_passwd $(bindir)/
-       cp tac_plus.1 $(mandir)/
-
-rpm_install: make_dir
-       install -c -m 0755 tac_plus $(sbindir)/
-       install -c -m 0755 generate_passwd $(sbindir)/
-       install -c -m 0644 tac_plus.1 $(mandir)/
-
-depend:
-       makedepend $(CFLAGS) $(SRCS)
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
-
diff --git a/README.LDAP b/README.LDAP
new file mode 100644 (file)
index 0000000..755b19e
--- /dev/null
@@ -0,0 +1,146 @@
+                   LDAP Authentification with Tacacs+
+                   ----------------------------------
+
+
+Author : Harpes Patrick (patrick.harpes@tudor.lu)
+         Jahnen Andreas (andreas.jahnen@tudor.lu)
+Date   : 16.03.2001
+
+License: 
+--------
+
+   tac_ldap is free software; you can redistribute it
+   and/or modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2,
+   or (at your option) any later version.     
+
+
+This document aim to describe how to perform LDAP authentification for tacacs+.
+
+
+Requirements:
+-------------
+
+1) tac_plus.F4.0.3-v8.alpha.tar.gz
+   This package includes the original CISCO tacacs+ package from http://www.gazi.edu.tr/tacacs/
+2) openldap package
+   This package has been developped using the openldap libraries version 2.0.7
+   OpenLDAP is available from www.openldap.org
+3) GCC and other GNU developpment tools (make...)
+4) A running LDAP server (test has been made using Lotus Domino LDAP server version 5.0.x and 
+   OpenLDAP)
+
+Overview:
+---------
+                                            ------------            ----------------
+                                            - Server   -            - Notes DOMINO -
+              ----------------              - running  -____LDAP____- LDAP Server  -
+              - CISCO Dialup -__tacacs+_____- tacacs+  -            -    or        -
+              -   Router     -              -          -            - other LDAP   -
+              ----------------              ------------            - Server       -
+                                                                    ---------------
+
+The CISCO router sends tacacs+ request to the tacacs+ server. This one uses the LDAP
+server to authentificate the user.
+
+
+HowTo configure the CISCO router?
+---------------------------------
+
+There are good documentations available on how to set up the CISCO router for using 
+tacacs+. This documents can be found on the tacacs+ homepage http://www.gazi.edu.tr/tacacs/
+
+HowTo install the tacacs+ package with LDAP support?
+----------------------------------------------------
+
+To enable the LDAP support on the tacacs+ package, you have to perform the following steps:
+
+   1. Install the Open LDAP package (version 2.0.7) (www.openldap.org)
+      Refer to the INSTALL document to build this package.
+
+   2. Unpack the tacacs+ package in /usr/local/src
+      # tar -zxvf  tac_plus.F4.0.3-v8.alpha.tar.gz  
+
+   3. Use the configure script to create the Makefiles
+
+      # cd /usr/local/src/tac_plus.F5.0.0.alpha/   
+      # ./configure --with-ldap
+
+      You can use ./configure --help to get more options
+
+   4. Compile the package
+
+      # make tac_plus
+
+   5. Set your LD_LIBRARY_PATH to include the LDAP libraries
+
+      # LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH
+
+
+HowTo configure tacacs+ for using the LDAP support
+--------------------------------------------------
+
+To use the LDAP authentification, use the following simple tacacs+ configuration file
+
+   key = "your tacacs key"
+   accounting file = /var/log/tac-plus/tac_plus.log
+   default authentification = ldap "ldap://<Hostname of your LDAP server>"
+   user=DEFAULT {
+          service = ppp protocol = ip {
+          }
+   }
+
+
+For more information on the configuration file please use the complete tacacs+ documentation.
+
+
+How to start the tacacs+ daemon
+-------------------------------
+
+Make sure your LD_LIBRARY_PATH includes the LDAP libraries.
+As root, start the tacacs daemon:
+   # /usr/local/src/tac_plus.F4.0.3-v8.alpha/tac_plus -C tac_plus.cfg
+
+
+How to configure the LDAP server
+--------------------------------
+
+a) Notes Domino LDAP server
+---------------------------
+
+You have to enable the Domino server task "LDAP" with the Administration Tool. You 
+can do this with the command "laod ldap" at the server console or with the help of 
+the Tools Menu of the server tab (Tools -> Task -> Start "LDAP Server"). 
+
+You can define which attributes of your Domino Directory are accessible by 
+anonymous users and if it is allowed to write to your Domino Directory using LDAP in 
+a Configuration document. You have to specify "Use these settings as the default 
+settings for all servers" in the Basic tab of the Configuration document to display 
+the LDAP options tab. There you are able to adjust the settings for a your LDAP server.
+
+For additional information see the IBM Red Book "Getting the most from your Domino 
+Directory" (11/2000), which you can downlaod from http://www.redbooks.ibm.com.
+
+
+b) Open LDAP
+------------
+
+It is also possible to use OpenLDAP for this kind of authentification. Please look at 
+the documentation at http://www.openldap.org for details how to install the server.
+
+
+Security
+---------
+
+The here described tacacs+ queries are not quering any of the fields stored in your LDAP 
+server. We only try to log in and this is the "test" we perform here. 
+
+Pleae note that the passwords are not send encrypted. You have to make sure that it is 
+not possible to sniff them. In general is there no support from tacacs+ to support encrypted 
+passwords. 
+It is maybe possible to use OpenLDAP with TLS support to encrypt the passwords and use a 
+secure LDAP server. This is also supported by Domino and OpenLDAP. But this is not implemented.
+
+Good luck,
+       Harpes Patrick (patrick.harpes@tudor.lu) and Jahnen Andreas (andreas.jahnen@tudor.lu)
index 0c1d468..7cbd4b4 100644 (file)
@@ -1,9 +1,9 @@
 Tacacs+ with PAM Authentication and Authorization support.
 
 patch version 0.4 (7 February 2000)
-Now Tacacs+ PAM Authorization Working.. 
-I am add some function to do it and also rename tac_pam_acct.c file to  tam_pam.c 
-But we must do more test ..:p 
+Now Tacacs+ PAM Authorization Working..
+I am add some function to do it and also rename tac_pam_acct.c file to  tam_pam.c
+But we must do more test ..:p
 devrim(devrim@tef.gazi.edu.tr)
 
 patch version 0.3  (17 November 1999)
@@ -36,5 +36,3 @@ into tac_plus.conf.
 
 
 Max Liccardo <ravel@tiscalinet.it>
-
-
diff --git a/acconfig.h b/acconfig.h
new file mode 100644 (file)
index 0000000..72e7998
--- /dev/null
@@ -0,0 +1,97 @@
+/*     acconfig.h
+ *
+ *     $Id$
+ */
+
+#ifndef TAC_PLUS_CONFIG_H
+#define TAC_PLUS_CONFIG_H 1
+
+@TOP@
+
+
+/* --maintainer-mode
+ * Sets "/etc/tacacs/tac_plus.cfg" as default config file
+ */
+#undef MAINTAINER_MODE
+
+/* Missing socklen_t in <sys/socket.h>
+ * We don't use 'typedef' to not to yet require <stddef.h> included here.
+ */
+#undef socklen_t
+
+/* Define this if you have shadow passwords in /etc/passwd and
+ * /etc/shadow. Note that you usually need to be root to read
+ * /etc/shadow */
+#undef SHADOW_PASSWORDS
+
+/* Check for some fields in <pwd.h>/struct passwd and <utmp.h>/struct utmp
+ */
+#undef HAVE_PASSWD_PW_AGE
+#undef HAVE_PASSWD_PW_COMMENT
+#undef HAVE_UTMP_UT_HOST
+
+/* All OSes detected by configure.in:
+ */
+#undef LINUX
+#undef GLIBC
+#undef SOLARIS
+#undef FREEBSD
+#undef HPUX
+#undef AIX
+#undef MIPS
+
+/* --with-pam */
+#undef USE_PAM
+/* --with-ldap */
+#undef USE_LDAP
+/* --with-db */
+#undef DB
+/* --with-db */
+#undef DB_NULL
+/* --with-mysql */
+#undef DB_MYSQL
+/* --with-pgsql */
+#undef DB_PGSQL
+/* --enable-maxsess */
+#undef MAXSESS
+/* --with-libwrap */
+#undef TCPWRAPPER
+/* --with-skey */
+#undef SKEY
+/* --with-mschap[=des] */
+#undef MSCHAP
+#undef MSCHAP_DES
+/* --with-tac[ug]id */
+#undef TACPLUS_USERID
+#undef TACPLUS_GROUPID
+/* --with-tacplus_pid */
+#undef TACPLUS_PIDFILE
+/* --with-included-regex */
+#undef WITH_INCLUDED_REGEX
+
+
+@BOTTOM@
+
+/* Keep in sync with configure.in */
+#define _XOPEN_SOURCE 1                        /* for unistd.h/crypt() */
+#define _XOPEN_SOURCE_EXTENDED 1       /* for pwd.h/{set,end}pwent(), sys/wait.h/wait3() */
+#define _BSD_SOURCE 1                  /* for u_{char,short,int} & string.h/bcopy() */
+#define _OSF_SOURCE 1                  /* for u_{char,short,int} (on Alpha OSF1) */
+#define __EXTENSIONS__ 1               /* for u_{char,short,int} (on Sparc Solaris) */
+
+#if SIZEOF_UNSIGNED_SHORT == 4
+typedef unsigned short tac_uint32;
+#else
+#if SIZEOF_UNSIGNED_INT == 4
+typedef unsigned int tac_uint32;
+#else
+#if SIZEOF_UNSIGNED_LONG == 4
+typedef unsigned long tac_uint32;
+#else
+#error "Unable to find 32-bit unsigned int for TAC_UINT32 type"
+#endif /* SIZEOF_UNSIGNED_LONG */
+#endif /* SIZEOF_UNSIGNED_INT */
+#endif /* SIZEOF_UNSIGNED_SHORT */
+
+
+#endif /* TAC_PLUS_CONFIG_H */
diff --git a/acct.c b/acct.c
index 315064f..2145cef 100644 (file)
--- a/acct.c
+++ b/acct.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
 
+#include <stdlib.h>
+#include <netinet/in.h>                /* for ntohl() */
+
+#include "acct.h"
+#include "report.h"
+#include "packet.h"
+#include "utils.h"
+#include "do_acct.h"
+#include "main.h"
+#include "do_author.h"                 /* for "struct identity" */
+#include "cfgfile.h"
+
+#ifdef MAXSESS
+#include "maxsess.h"
+#endif
+#ifdef DB
+#include "db.h"
+#endif
+
+
+static void account TAC_ARGS((u_char *pak));
+
+
 /*
  *  Come here when we receive an Start Accounting packet
  */
 
-void account();
-
-/* For  DB accounting */
-#ifdef DB
-int db_acct();
-#endif /* DB */
+void accounting TAC_ARGS((u_char *pak));
 
 void
 accounting(pak)
@@ -37,8 +56,8 @@ u_char *pak;
     struct acct *acct_pak;
     u_char *p;
     HDR *hdr;
-    u_char *read_packet();
-    int i, len;
+    int i;
+    unsigned long len;
 
     if (debug & DEBUG_ACCT_FLAG)
        report(LOG_DEBUG, "Start accounting request");
@@ -53,13 +72,13 @@ u_char *pak;
 
     /* Length checks */
     len = TAC_ACCT_REQ_FIXED_FIELDS_SIZE;
-    len += acct_pak->user_len + acct_pak->port_len + 
+    len += acct_pak->user_len + acct_pak->port_len +
        acct_pak->rem_addr_len + acct_pak->arg_cnt;
     for (i = 0; i < (int)acct_pak->arg_cnt; i++) {
        len += p[i];
     }
 
-    if (len != ntohl(hdr->datalength)) {
+    if (len != (unsigned long) ntohl(hdr->datalength)) {
        send_error_reply(TAC_PLUS_ACCT, NULL);
        return;
     }
@@ -69,7 +88,9 @@ u_char *pak;
     free(pak);
 }
 
-void
+static void account TAC_ARGS((u_char *pak));
+
+static void
 account(pak)
 u_char *pak;
 {
@@ -123,6 +144,8 @@ u_char *pak;
 
     identity.priv_lvl = acct_pak->priv_lvl;
 
+    cfg_request_identity(&identity);
+
     rec.identity = &identity;
 
     /* Now process cmd args */
@@ -152,7 +175,7 @@ u_char *pak;
        errors = do_wtmp(&rec);
     } else {
        errors = do_acct(&rec);
-#ifdef DB 
+#ifdef DB
     if (session.db_acct && rec.acct_type==ACCT_TYPE_STOP )
        db_acct(&rec);
 #endif
@@ -172,9 +195,9 @@ u_char *pak;
 
     for (i = 0; i < (int)acct_pak->arg_cnt; i++) {
        free(cmd_argp[i]);
-    }    
+    }
     free(cmd_argp);
-    
+
     if (rec.msg)
        free(rec.msg);
     if (rec.admin_msg)
diff --git a/acct.h b/acct.h
new file mode 100644 (file)
index 0000000..0640ae6
--- /dev/null
+++ b/acct.h
@@ -0,0 +1,12 @@
+#ifndef ACCT_H
+#define ACCT_H 1
+
+#include "tac_plus.h"
+
+#include <sys/types.h>         /* for u_* */
+
+
+extern void accounting TAC_ARGS((u_char *pak));
+
+
+#endif /* ACCT_H */
index a12745e..7c873fe 100644 (file)
--- a/authen.c
+++ b/authen.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
 
-static int choose();
-static void authenticate();
-static void do_start();
+#include <stdlib.h>
+#include <netinet/in.h>                /* for ntohl() */
+
+#include "authen.h"
+#include "packet.h"
+#include "report.h"
+#include "utils.h"
+#include "choose_authen.h"
+#include "do_author.h"         /* for "struct identity" */
+#include "main.h"
+#include "cfgfile.h"
+
+#ifdef TCPWRAPPER
+#include "tcpwrap.h"
+#endif
+
+
+static void do_start TAC_ARGS((u_char *pak));
+static int choose TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
+static void authenticate TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
+
+
+/* Configurable:
+ */
+
+#define TAC_PLUS_MAX_ITERATIONS 50
+
 
 /*
  *  Come here when we receive an authentication START packet
  */
 
+void authen TAC_ARGS((u_char *pak));
+
 void
 authen(pak)
 u_char *pak;
@@ -39,9 +66,9 @@ u_char *pak;
     start = (struct authen_start *) (pak + TAC_PLUS_HDR_SIZE);
 
     if ((hdr->seq_no != 1) ||
-       (ntohl(hdr->datalength) != TAC_AUTHEN_START_FIXED_FIELDS_SIZE + 
+       ((unsigned long) ntohl(hdr->datalength) != (unsigned long)(TAC_AUTHEN_START_FIXED_FIELDS_SIZE +
         start->user_len + start->port_len + start->rem_addr_len +
-        start->data_len)) {
+        start->data_len))) {
        send_authen_error("Invalid AUTHEN/START packet (check keys)");
        return;
     }
@@ -65,6 +92,8 @@ u_char *pak;
  * attempt to authenticate.
  */
 
+static void do_start TAC_ARGS((u_char *pak));
+
 static void
 do_start(pak)
 u_char *pak;
@@ -109,6 +138,8 @@ u_char *pak;
 
     identity.priv_lvl = start->priv_lvl;
 
+    cfg_request_identity(&identity);
+
     /* The authen_data structure */
 
     bzero(&authen_data, sizeof(struct authen_data));
@@ -133,7 +164,7 @@ u_char *pak;
      * authentication function to call to actually do the work. */
 
 #ifdef TCPWRAPPER
-if (check_from_wrap(&identity)) {   
+if (check_from_wrap(&identity)) {
 #endif
     ret = choose(&authen_data, &authen_type);
 
@@ -170,7 +201,7 @@ send_authen_error("You are not allowed to access here");
        authen_data.client_data = NULL;
     }
     if (authen_data.method_data) {
-       report(LOG_ERR, 
+       report(LOG_ERR,
               "%s: Method data not set to NULL after authentication",
               session.peer);
     }
@@ -184,7 +215,9 @@ send_authen_error("You are not allowed to access here");
 /* Choose an authentication function. Return 1 if we successfully
    chose a function.  0 if we couldn't make a choice for some reason */
 
-static int 
+static int choose TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
+
+static int
 choose(datap, typep)
 struct authen_data *datap;
 struct authen_type *typep;
@@ -203,7 +236,7 @@ struct authen_type *typep;
 
        if (++iterations >= TAC_PLUS_MAX_ITERATIONS) {
            report(LOG_ERR, "%s: %s Too many iterations for choose_authen",
-                  session.peer, 
+                  session.peer,
                   session.port);
            return (0);
        }
@@ -267,13 +300,13 @@ struct authen_type *typep;
 
                if (cont->user_data_len) {
                    /* An abort message exists. Log it */
-                   p = reply + TAC_PLUS_HDR_SIZE + 
+                   p = reply + TAC_PLUS_HDR_SIZE +
                        TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE + cont->user_msg_len;
 
                    bcopy(p, buf, cont->user_data_len);
                    buf[cont->user_data_len] = '\0';
                }
-               report(LOG_INFO, "%s %s: Login aborted by request -- msg: %s", 
+               report(LOG_INFO, "%s %s: Login aborted by request -- msg: %s",
                       session.peer, session.port, buf);
                free(reply);
                return(0);
@@ -293,6 +326,8 @@ struct authen_type *typep;
     /* NOTREACHED */
 }
 
+static void authenticate TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
+
 /* Perform authentication assuming we have successfully chosen an
    authentication method */
 static void
@@ -303,7 +338,7 @@ struct authen_type *typep;
     int iterations = 0;
     u_char *reply, *p;
     struct authen_cont *cont;
-    int (*func) ();
+    int (*func) TAC_ARGS((struct authen_data *data));
 
     if (debug & DEBUG_PACKET_FLAG)
        report(LOG_DEBUG, "Calling authentication function");
@@ -429,7 +464,7 @@ struct authen_type *typep;
                    /* An abort message exists. Create a
                       null-terminated string for authen_data */
 
-                   datap->client_data = (char *) 
+                   datap->client_data = (char *)
                        tac_malloc(cont->user_data_len + 1);
 
                    p = reply + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE +
@@ -469,4 +504,3 @@ struct authen_type *typep;
        /* NOTREACHED */
     }
 }
-
diff --git a/authen.h b/authen.h
new file mode 100644 (file)
index 0000000..d89d9cc
--- /dev/null
+++ b/authen.h
@@ -0,0 +1,12 @@
+#ifndef AUTHEN_H
+#define AUTHEN_H 1
+
+#include "tac_plus.h"
+
+#include <sys/types.h>         /* for u_* */
+
+
+extern void authen TAC_ARGS((u_char *pak));
+
+
+#endif /* AUTHEN_H */
index a9f2277..7a05db5 100644 (file)
--- a/author.c
+++ b/author.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
 
+#include <stdlib.h>
+#include <netinet/in.h>                /* for ntohl() */
+
+#include "author.h"
+#include "report.h"
+#include "packet.h"
+#include "utils.h"
+#include "do_author.h"
+#include "main.h"
+#include "cfgfile.h"
+
+
 /*
  *  Come here when we receive an authorization START packet
  */
 
+void author TAC_ARGS((u_char *pak));
+
 void
 author(pak)
 u_char *pak;
@@ -34,7 +49,8 @@ u_char *pak;
     u_char *p;
     u_char *argsizep;
     char **cmd_argp;
-    int i, len;
+    int i;
+    unsigned long len;
 
     if (debug & DEBUG_AUTHOR_FLAG)
        report(LOG_DEBUG, "Start authorization request");
@@ -58,7 +74,7 @@ u_char *pak;
        len += p[i];
     }
 
-    if (len != ntohl(hdr->datalength)) {
+    if (len != (unsigned long) ntohl(hdr->datalength)) {
        send_error_reply(TAC_PLUS_AUTHOR, NULL);
        return;
     }
@@ -95,6 +111,8 @@ u_char *pak;
 
     identity.priv_lvl = apak->priv_lvl;
 
+    cfg_request_identity(&identity);
+
     /* The author_data structure */
 
     author_data.id = &identity;        /* user id */
@@ -148,7 +166,7 @@ u_char *pak;
     if (author_data.input_args) {
        for (i = 0; i < author_data.num_in_args; i++)
            free(author_data.input_args[i]);
-       
+
        free(author_data.input_args);
        author_data.input_args = NULL;
     }
diff --git a/author.h b/author.h
new file mode 100644 (file)
index 0000000..0e3a2ce
--- /dev/null
+++ b/author.h
@@ -0,0 +1,12 @@
+#ifndef AUTHOR_H
+#define AUTHOR_H 1
+
+#include "tac_plus.h"
+
+#include <sys/types.h>         /* for u_* */
+
+
+extern void author TAC_ARGS((u_char *pak));
+
+
+#endif /* AUTHOR_H */
diff --git a/autogen b/autogen
new file mode 100755 (executable)
index 0000000..83862fd
--- /dev/null
+++ b/autogen
@@ -0,0 +1,47 @@
+#! /bin/sh
+#
+#      autogen
+#
+#      Copyright (C) 1999, 2000, 2001
+#      Partition Surprise Team <surprise-dev@lists.sourceforge.net>
+#
+#      $Id$
+#
+
+
+# Run this to generate all the initial makefiles, etc.
+
+set -e
+if test "x$1" = "xBASH" ;then
+  shift
+else if test "x$BASH" = "x" ;then
+  for trypath in `echo "$PATH"|tr : ' '` /usr/local/bin;do
+    if test -x "$trypath/bash";then
+      "$trypath/bash" "$0" BASH "$@"
+      exit $?
+    fi
+  done
+  echo "ERROR: Unable to find 'bash' interpreter needed for self-execution!"
+  exit 1
+fi;fi
+
+defaultCONFDEFS="" # --enable-debug --without-efence
+project="tac_plus"
+automake_gnu=false
+want_tarZ=false
+want_gettext=false
+want_libtool=false
+#upload="vellum.cz:WWW/sw/"
+docdir=""
+subdirs=""
+
+CLEAN_LOCAL="
+  .print_userprogs
+  tac_plus
+  generate_passwd
+"
+
+ARGS_HELP_LOCAL="\
+"
+
+source ./autogen-body
diff --git a/autogen-body b/autogen-body
new file mode 100644 (file)
index 0000000..6856444
--- /dev/null
@@ -0,0 +1,259 @@
+#
+#      autogen-body
+#
+#      Placed into the public domain by
+#      Partition Surprise Team <surprise-dev@lists.sourceforge.net>
+#
+#      $Id$
+#
+
+
+# Executable code to be included from ./autogen script
+
+# Expected variables:
+# defaultCONFDEFS, project, want_tarZ, upload, docdir, subdirs, CLEAN_LOCAL
+# function PREP_LOCAL
+
+set -e
+t=/tmp/autogen.$$
+autogen_failed=true
+cleaup_dir="$PWD"
+automake_reqd=""
+function cleanup
+{
+  cd "$cleanup_dir"
+  rm -f "$t.*"
+  if $automake_gnu;then for i in $automake_reqd;do if [ '!' -s "$i" ];then rm -f "$i";fi;done;fi
+}
+EXITmsg_do=true
+trap '
+  cleanup
+  if $autogen_failed;then
+    if $EXITmsg_do;then
+      echo -e "\n$0 failed! Try the following command to debug it: set -x"
+      EXITmsg_do=false
+      fi
+    exit 1
+    fi
+  ' EXIT
+
+if [ "$1" = help -o "$1" = -h -o "$1" = --help ];then cat <<EOHELP
+Beware!: "autogen" is a tool only for maintainers.
+
+Supported parameters:
+    rpm: Build RPM packages locally (needs /usr/src/(redhat|packages)/ access)
+    rpmtest: Build RPM like "rpm" but w/o gpg/pgp signing
+    rpmup: Like rpm target but also uploads the result
+    tar: Build tar file (its basename dir-based) with only vital files incl. CVS dirs
+    clean: Standard cleanup method
+    fullclean: Like clean but even the .cvsignore files are removed
+    sym: Like clean but don't remove symbolic links, should be equal (check!)
+    copy: Behave exactly like in default mode but copy all instead of symlinks
+$ARGS_HELP_LOCAL
+EOHELP
+  autogen_failed=false
+  exit
+  fi
+
+
+if [ -f "$HOME/.$project.autogen" ];then
+  . "$HOME/.$project.autogen"
+  fi
+CONFDEFS="$defaultCONFDEFS $CONFDEFS"
+
+function funcdo
+{
+local func="$1";
+
+  shift
+  if declare -f "$func" >/dev/null;then
+local func_exit=false
+
+    "$func" "$@"
+    if $func_exit;then exit;fi
+  fi
+}
+funcdo ARGS_LOCAL "$@"
+
+if expr match "$1" "rpm" >/dev/null;then
+  builds="/usr/src/redhat /usr/src/packages"
+  for b in $builds X;do
+    if test -d $b;then break;fi
+    done
+  if [ $b = X ];then
+    echo Build directory not reachable, searched: $builds
+    exit 1
+    fi
+  rm -r -f /var/tmp/$project-*-root $b/BUILD/$project-*
+  specsrc="$project.spec.m4.in"
+  if [ '!' -f "$specsrc" ];then specsrc="$project.spec.in";fi
+  CONFDEFS="`awk '/^(.*)\\$/{x=x$1" ";next}{print x$0;x=""}' <$specsrc \
+            |sed -n 's/^.*\.\/configure \(.*\)$/\1/p'`" ./autogen copy
+  make dist $project.spec
+  cp $project-*.tar.gz $b/SOURCES
+  if [ "$1" = "rpmtest" ];then SIGNIT=;else SIGNIT=--sign;fi
+  rpm -ba $SIGNIT $project.spec
+  if $want_tarZ;then make dist-tarZ;fi
+  rm $b/SOURCES/$project-*.tar.gz
+  mv $b/SRPMS/$project-*.src.rpm .
+  mv $b/RPMS/i386/$project-*.i386.rpm .
+  ls -l $project-*
+  if [ "$1" = rpmup ];then
+    echo "Uploading $[`cat $project-*|wc -c`] bytes..."
+    if [ -n "$upload" ];then
+      scp -v $project-* "$upload"
+    else
+      echo "Upload not done."
+    fi
+  fi
+  autogen_failed=false
+  exit
+fi
+
+function subdo
+{
+  for i in _ $subdirs;do
+    if [ -d $i ];then
+      cd "$i"
+      ./autogen $subdir_args
+      cd ..
+      fi
+    done
+}
+subdir_args="${*:-dist}"
+if [ "$subdir_args" = "copy" ];then
+  subdir_args="copy dist"
+  fi
+
+# maintainer-clean hack is not safe, please list all files for 'rm'.
+# When the filename doesn't contain '/', it is applied to ALL directories.
+# Please note that files exactly in root dir MUST have ./ in the front
+#   (to not to be considered as ALL-directories files).
+
+CLEANFILES="
+  *~ .#*
+  *.orig *.rej
+  core
+  Makefile Makefile.in
+  TAGS tags ID
+  .deps .libs
+  *.[oa] *.l[oa]
+
+  ./errs*
+  ./intl
+  ./configure ./configure.scan
+  ./config.guess ./config.status ./config.sub ./config.log ./config.cache
+  ./config.h ./config.h.in
+  ./confdefs.h ./conftest* ./autoh[0-9]* ./confcache
+  ./stamp-h ./stamp-h.in
+  ./install-sh
+  ./aclocal.m4
+  ./missing
+  ./mkinstalldirs
+  ./libtool ./ltconfig ./ltmain.sh
+  ./ChangeLog
+  ./ABOUT-NLS ./COPYING
+  ./$project-[0-9]* ./$project-devel-[0-9]*
+  ./$project.spec ./$project.m4 ./$project.spec.m4
+  macros/macros.dep
+  po/Makefile.in.in po/POTFILES* po/cat-id-tbl.c po/cat-id-tbl.tmp po/*.gmo po/*.mo po/stamp-cat-id po/$project.pot
+
+  $CLEAN_LOCAL
+  "
+if [ -n "$docdir" ];then
+CLEANFILES="
+  $docdir/*.html
+  $docdir/*.info*
+  $docdir/*.txt
+  $docdir/*.tex
+  $docdir/*.sgml
+  $CLEANFILES"
+  fi
+if [ "$1" != sym ];then CLEANFILES="$CLEANFILES `find . -type l`";fi
+CLEANFILES="`echo "$CLEANFILES"|tr ' ' '\n'|sed 's,^\./\(.*/.*\)$,\1,'|sort|uniq|grep -v '^ *$'`"
+true >"$t.find"
+rm -f "$t.discard"
+echo "$CLEANFILES"|while read -r fi;do
+  if [ "$fi" != "${fi#*/}" ];then
+       echo "$fi" >>"$t.discard"
+  else echo "-o -name $fi" >>"$t.find"
+  fi;done
+for dirpatt in `(find . -type d '!' \( -name CVS $(sed 's,[]*?[],\\&,g' <"$t.find") \)|sort|uniq;cat "$t.discard")|sort|uniq -u`;do
+  for dir in $dirpatt;do if test -d $dir;then
+    (cd $dir
+     (echo "$CLEANFILES"                                                #ALL-dir files
+      echo "$CLEANFILES"|sed -n "s,^\\$(echo $dir|sed 's,^\./,,')/,,p"  #THIS-dir files
+      echo .cvsignore                                                   #MUST be last!
+      )|grep -v / >.cvsignore
+     if [ "$1" = "${1#tar}" ];then
+       rm -rf `
+         if [ "$1" = fullclean ];then cat .cvsignore
+         else grep -v '^\.cvsignore' <.cvsignore
+         fi`
+       fi
+     )
+    fi;done
+  done
+rm -f "$t.find" "$t.discard"
+if [ "$1" = tarprep ];then
+  autogen_failed=false
+  exit
+  fi
+if [ "$1" = tar ];then
+  subdir_args=tarprep
+  subdo
+  mydir="$(basename `pwd`)"
+  cd ..
+  tar cf - \
+    $(for fi in `find "$mydir" -name .cvsignore`;do sed "s,^,--exclude=`dirname $fi`/," <$fi;done) \
+    "$mydir"
+  autogen_failed=false
+  exit
+  fi
+if [ "$1" != "${1#*clean}" ];then
+  subdo
+  autogen_failed=false
+  exit 0
+  fi
+
+funcdo PREP_LOCAL "$@"
+subdo
+
+if [ "$1" = copy ];then COPY=--copy;shift
+else unset COPY|cat  # |cat construction is used to not fail in "set -e" state
+fi
+
+if test -d po;then
+  touch po/POTFILES.in
+fi
+aclocal_opts=""
+if test -d macros;then
+  aclocal_opts="-I macros $aclocal_opts"
+fi
+aclocal $aclocal_opts
+if $want_gettext;then
+  gettextize $COPY
+  rm -f aclocal.m4       # We delete created aclocal.m4 as it's just bug in gettextize. It shouldn't link that file here
+  aclocal $aclocal_opts  # gettextize made some changes of files which need to be reflected
+fi
+if $want_libtool;then
+  libtoolize $COPY
+fi
+autoheader
+automake_opts=""
+if $automake_gnu;then
+  automake_reqd="$automake_reqd ChangeLog README"
+  automake_opts="$automake_opts --gnu"
+  for i in $automake_reqd;do if [ '!' -f "$i" ];then touch "$i";fi;done
+fi
+automake --add-missing $COPY $automake_opts
+cleanup
+autoheader
+autoconf
+
+if [ "$1" != dist ];then
+  # shared/static switching cannot be based on maintainer-mode in configure
+  ./configure --enable-maintainer-mode --enable-shared --disable-static $CONFDEFS
+  fi
+
+autogen_failed=false
diff --git a/cfgeval.c b/cfgeval.c
new file mode 100644 (file)
index 0000000..e49b078
--- /dev/null
+++ b/cfgeval.c
@@ -0,0 +1,1874 @@
+/*
+ * ???():
+ *   If you belong to the group where do you belong only in the case you belong
+ *   in that group, do you in fact belong to that group or don't?
+ *   I've decided it is safer to decide that you DON'T belong to such group.
+ *
+ * expr_eval_notify_expr_remove():
+ *   If someone was interested in what am I like but she is no longer
+ *   interested in what am I like, because she already knows what is she like,
+ *   then she should tell it me, as although I still may not know what am I
+ *   like then in the case she was the last who wanted to know what am I like,
+ *   I should tell everyone who I didn't know what they are like and I wanted
+ *   to know what they are like that I no longer want to know what they are
+ *   like, because it is no longer needed to know what am I like about myself.
+ *
+ * membership_eval_immediate():
+ *   It is important to not only know, what do you want to know, but it is also
+ *   important to know what do you now know but you still didn't utilize it.
+ */
+
+
+#include "tac_plus.h"
+
+#include <stdlib.h>
+
+#include "cfgeval.h"
+#include "cfgfile.h"
+#include "main.h"
+#include "parse.h"
+#include "report.h"
+#include "hash.h"
+
+
+/* Configurable:
+ */
+
+/* Whether to do sanity checks */
+#define SCAN_PARANOIA 1
+
+/* report even no-op scan up-to-date checks */
+#define REPORT_CHECK_SCAN_VERBOSE 0
+
+
+static void check_request_scan_membership TAC_ARGS((struct membership *membership, int flush));
+static void check_eval_scan_membership TAC_ARGS((struct membership *membership, int flush));
+static void check_eval_scan_entity TAC_ARGS((ENTITY *entity, int flush));
+static void check_request_scan_expr TAC_ARGS((struct expr *expr, int flush));
+static void check_eval_scan_expr TAC_ARGS((struct expr *expr, int flush));
+
+
+static unsigned request_scan_seq = 0;
+static unsigned value_scan_seq = 0;
+static unsigned eval_scan_seq = 0;
+int request_scan_user_known;
+static struct tac_list eval_kicked_entity_list;
+static struct tac_list eval_destroy_entity_list;
+static struct tac_list eval_notified_expr_list;
+static struct tac_list request_virtual_membership_list;
+
+
+/* 'P[FA]_*' object printing section:
+ */
+
+static const char *eval_result_to_string TAC_ARGS((int valid, enum eval_result er));
+
+const char *
+eval_result_to_string(valid, er)
+int valid;
+enum eval_result er;
+{
+    if (!valid)
+       return ("!UPDATED");
+
+    switch (er) {
+    case ER_TRUE:    return ("ER_TRUE"        );
+    case ER_FALSE:   return ("ER_FALSE"       );
+    case ER_UNKNOWN: return ("ER_UNKNOWN"     );
+    default:         return ("*** INVALID ***");
+    }
+    /* NOTREACHED */
+}
+
+static const char *value_scan_func_result_to_string TAC_ARGS((enum value_scan_func_result vsfr));
+
+const char *
+value_scan_func_result_to_string(vsfr)
+enum value_scan_func_result vsfr;
+{
+    switch (vsfr) {
+    case VSFR_CONTINUE: return ("VSFR_CONTINUE");
+    case VSFR_FOUND:    return ("VSFR_FOUND"   );
+    case VSFR_STOP:     return ("VSFR_STOP"    );
+    default:            return ("*** INVALID ***");
+    }
+    /* NOTREACHED */
+}
+
+/* These macros are VERY big overhead but it's primary negative effect
+ * is the size of executable. I've considered it as not much interesting,
+ * CPU overhead is hit only when DEBUG_CFGEVAL_FLAG (also not interesting).
+ */
+
+#define PF_VSFR       "%s"
+#define PA_VSFR(vsfr) (value_scan_func_result_to_string((vsfr)))
+
+#define PF_RESULT         "%s"
+#define PA_RESULT(result) (eval_result_to_string(1 /* valid */, (result)))
+
+#define PF_ERESULT_struct         PF_RESULT
+#define PA_ERESULT_struct(entity, field) \
+       (!(entity) ? "*NULL*(=ER_TRUE)" : \
+               (eval_result_to_string((entity)->request_scan.seq == request_scan_seq, (entity)->request_scan.field)))
+#define PA_ERESULT_struct_NULL    "*NULL*"
+
+#define PF_ERESULT_EXPR       PF_ERESULT_struct
+#define PA_ERESULT_EXPR(expr) PA_ERESULT_struct((expr), result)
+#define PF_ERESULT_ENTITY         PF_ERESULT_struct
+#define PA_ERESULT_ENTITY(entity) PA_ERESULT_struct((entity), belongs)
+#define PF_ERESULT_MEMBERSHIP             PF_ERESULT_struct
+#define PA_ERESULT_MEMBERSHIP(membership) (!(membership) ? PA_ERESULT_struct_NULL : PA_ERESULT_EXPR((membership)->when))
+
+#define PF_EXPR_       "expr@%d{%s " PF_MEMBERSHIP "}"
+#define PA_EXPR_(expr) (!(expr) ? 0        : (expr)->line), \
+                       (!(expr) ? "*NULL*" : "of"), \
+                       PA_MEMBERSHIP((!(expr) ? NULL : (expr)->membership))
+
+#define PF_MEMBERSHIP_             "membership{child=" PF_ENTITY ",parent=" PF_ENTITY "}"
+#define PA_MEMBERSHIP_(membership) PA_ENTITY((!(membership) ? NULL : MEMBERSHIP_TO_CHILD_ENTITY( (membership)))), \
+                                   PA_ENTITY((!(membership) ? NULL : MEMBERSHIP_TO_PARENT_ENTITY((membership))))
+
+#define PF_ENTITY_         "{%s@%d \"%s\"}"
+#define PA_ENTITY_(entity) (!(entity) ? "*NULL* entity" : entity_type_to_string((entity)->type)), \
+                           (!(entity) ? 0               : (entity)->line), \
+                           (!(entity) ? "*NULL*"        : (entity)->name)
+
+#define PF_EXPR       PF_EXPR_ "=" PF_ERESULT_EXPR
+#define PA_EXPR(expr) PA_EXPR_(expr), PA_ERESULT_EXPR(expr)
+#define PF_MEMBERSHIP             PF_MEMBERSHIP_ "=" PF_ERESULT_MEMBERSHIP
+#define PA_MEMBERSHIP(membership) PA_MEMBERSHIP_(membership), PA_ERESULT_MEMBERSHIP(membership)
+#define PF_ENTITY         PF_ENTITY_ "=" PF_ERESULT_ENTITY
+#define PA_ENTITY(entity) PA_ENTITY_(entity), PA_ERESULT_ENTITY(entity)
+
+
+/* '{unlink,free}_*()' section:
+ */
+
+void unlink_expr TAC_ARGS((struct expr *expr));
+
+/* never depend on "->parent" as it may not yet been filled! */
+void
+unlink_expr(expr)
+struct expr *expr;
+{
+    if (!expr)
+       return;         /* prevent possible DEBUG_CLEAN_FLAG report */
+
+    if (debug & DEBUG_CLEAN_FLAG) {
+       if (expr->membership)
+           report(LOG_DEBUG, "unlink_expr: (of membership): " PF_EXPR,
+                   PA_EXPR(expr));
+       else
+           report(LOG_DEBUG, "unlink_expr: (standalone)");
+    }
+
+    while (expr) {
+
+       /* We need to at least unlink "eval_scan->u.entity.notify_expr_node": */
+       check_request_scan_expr(expr, 1);       /* invalidate */
+       check_eval_scan_expr(expr, 1);          /* invalidate */
+
+       switch (expr->type) {
+
+       case S_not:
+           unlink_expr(expr->u.not.child);
+           break;
+
+       case S_and:
+       case S_or:
+           unlink_expr(expr->u.and_or.child_first);
+           break;
+
+       case S_user:
+       case S_host:
+       case S_group:
+           break;
+
+       default:
+           report(LOG_ERR, "Illegal node type %d for unlink_expr", expr->type);
+           return;
+       }
+
+       expr = expr->next;
+    }
+}
+
+void free_expr TAC_ARGS((struct expr *expr));
+
+/* given 'expr' memory WILL be freed! */
+/* never depend on "->parent" as it may not yet been filled! */
+void
+free_expr(expr)
+struct expr *expr;
+{
+struct expr *expr_next;
+
+    if (!expr)
+       return;         /* prevent possible DEBUG_CLEAN_FLAG report */
+
+    if (debug & DEBUG_CLEAN_FLAG)
+       report(LOG_DEBUG, "free_expr: (may be unlinked)");
+
+    while (expr) {
+       expr_next = expr->next;
+       switch (expr->type) {
+
+       case S_not:
+           free_expr(expr->u.not.child);
+           break;
+
+       case S_and:
+       case S_or:
+           free_expr(expr->u.and_or.child_first);
+           break;
+
+       case S_user:
+       case S_host:
+       case S_group:
+           if (expr->u.entity.name)
+               free((/* de-const */ char *)expr->u.entity.name);
+           /* "expr->u.entity.entity" will be freed from elsewhere */
+           break;
+
+       default:
+           report(LOG_ERR, "Illegal node type %d for free_expr", expr->type);
+           return;
+       }
+
+       free(expr);
+       expr=expr_next;
+    }
+}
+
+static void unlink_membership TAC_ARGS((struct membership *membership));
+
+static void
+unlink_membership(membership)
+struct membership *membership;
+{
+    ENTITY *parent_entity;
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "unlink_membership: " PF_MEMBERSHIP,
+               PA_MEMBERSHIP(membership));
+
+    parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
+
+    /* 'unlink_expr()' may want a lot of existing (linked) resources */
+    unlink_expr(membership->when);
+
+    check_request_scan_membership(membership, 1);      /* invalidate */
+    check_eval_scan_membership(membership, 1);         /* invalidate */
+
+#ifdef SCAN_PARANOIA
+    if (!parent_entity->to_child_membership_num) {
+       report(LOG_ERR, "INTERNAL: to_child_membership_num-- == 0 in unlink_membership");
+       parent_entity->to_child_membership_num++;
+    }
+#endif
+    parent_entity->to_child_membership_num--;
+
+    tac_list_node_remove(&membership->parent_node);
+    tac_list_node_remove(&membership-> child_node);
+}
+
+/* given 'membership' memory WILL be freed! */
+
+static void free_membership TAC_ARGS((struct membership *membership));
+
+static void
+free_membership(membership)
+struct membership *membership;
+{
+    if (debug & DEBUG_CLEAN_FLAG)
+       report(LOG_DEBUG, "free_membership: (may be unlinked)");
+
+    free_expr(membership->when);
+    free(membership);
+}
+
+/* we are not allowed to free memory here, we are only 'scan_' additional 'free' */
+
+void scan_free_entity TAC_ARGS((ENTITY *entity));
+
+void
+scan_free_entity(entity)
+ENTITY *entity;
+{
+    struct tac_list_node *parent_membership_node, *next_parent_membership_node;
+    struct membership *parent_membership;
+    struct tac_list_node *child_membership_node, *next_child_membership_node;
+    struct membership *child_membership;
+
+    if (debug & DEBUG_CLEAN_FLAG)
+       report(LOG_DEBUG, "scan_free_entity: " PF_ENTITY,
+               PA_ENTITY(entity));
+
+    /* Be careful to keep '->next' ptr before we destroy the structure! */
+
+    for (
+           parent_membership_node = tac_list_first_node(&entity->to_child_membership_list);
+           parent_membership_node;
+           parent_membership_node = next_parent_membership_node
+           ) {
+       parent_membership = PARENT_NODE_TO_MEMBERSHIP(parent_membership_node);
+       next_parent_membership_node = tac_list_node_next(parent_membership_node);
+       unlink_membership(parent_membership);
+       free_membership(parent_membership);
+    }
+    for (
+           child_membership_node = tac_list_first_node(&entity->to_parent_membership_list);
+           child_membership_node;
+           child_membership_node = next_child_membership_node
+           ) {
+       child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
+       next_child_membership_node = tac_list_node_next(child_membership_node);
+       unlink_membership(child_membership);
+       free_membership(child_membership);
+    }
+}
+
+struct expr *new_expr TAC_ARGS((int type));
+
+struct expr *
+new_expr(type)
+int type;
+{
+    struct expr *expr;
+
+    expr = (struct expr *) tac_malloc(sizeof(struct expr));
+    expr->next = NULL;
+    expr->type = type;
+    switch (expr->type) {
+
+    case S_not:
+       expr->u.not.child = NULL;
+       break;
+
+    case S_and:
+    case S_or:
+       expr->u.and_or.child_first = NULL;
+       break;
+
+    case S_user:
+    case S_host:
+    case S_group:
+       expr->u.entity.entity = NULL;
+       break;
+
+    default:
+       report(LOG_ERR, "Illegal node type %d for new_expr", expr->type);
+       return (expr);  /* it would be probably lethal to return NULL */
+    }
+    return (expr);
+}
+
+static int expr_sink_internal TAC_ARGS((struct expr *expr, struct membership *membership, struct expr *parent));
+
+static int
+expr_sink_internal(expr, membership, parent)
+struct expr *expr;
+struct membership *membership;
+struct expr *parent;
+{
+    for (;expr; expr=expr->next) {
+       expr->membership = membership;
+       expr->parent = parent;
+       expr->request_scan.seq = request_scan_seq-1;
+       expr->   eval_scan.seq =    eval_scan_seq-1;
+       switch (expr->type) {
+
+       case S_not:
+           expr_sink_internal(expr->u.not.child, membership, expr /* parent */);
+           break;
+
+       case S_and:
+       case S_or:
+           expr_sink_internal(expr->u.and_or.child_first, membership, expr /* parent */);
+           break;
+
+       case S_user:
+       case S_host:
+       case S_group:
+           tac_list_node_init(&expr->eval_scan.u.entity.notify_expr_node);
+           expr->u.entity.entity = entity_lookup(expr->type, expr->u.entity.name);
+           if (!expr->u.entity.entity) {
+               report(LOG_ERR, "referenced entity %s %s not found on line %d",
+                       entity_type_to_string(expr->type), expr->u.entity.name, expr->line);
+               return (1);
+               }
+           free((char *) expr->u.entity.name);
+           expr->u.entity.name = NULL;
+           break;
+
+       default:
+           report(LOG_ERR, "Illegal node type %d for expr_sink", expr->type);
+           return (1);
+       }
+    }
+    return (0);
+}
+
+static int expr_sink TAC_ARGS((struct expr *expr, struct membership *membership));
+
+static int
+expr_sink(expr, membership)
+struct expr *expr;
+struct membership *membership;
+{
+    return (expr_sink_internal(expr, membership, NULL /* parent */));
+}
+
+static struct expr *expr_sink_register_head = NULL;
+
+void expr_sink_register TAC_ARGS((struct expr *expr));
+
+void
+expr_sink_register(expr)
+struct expr *expr;
+{
+    if (!expr)
+       return;
+
+    expr->parent = expr_sink_register_head;
+    expr_sink_register_head = expr;
+}
+
+int expr_sink_commit TAC_ARGS((void));
+
+int
+expr_sink_commit()
+{
+    struct expr *expr;
+
+    while ((expr = expr_sink_register_head)) {
+       expr_sink_register_head = expr->parent;
+       /* 'expr->parent' not defined for 'expr_sink()' */
+
+       if (expr_sink(expr, NULL /* membership */))
+           return (1);         /* failure */
+    }
+    return (0);                /* success */
+}
+
+struct expr *dupl_expr TAC_ARGS((const struct expr *in));
+
+struct expr *
+dupl_expr(in)
+const struct expr *in;
+{
+    struct expr *expr_root = NULL;
+    struct expr **succ_exprp = &expr_root;
+    struct expr *expr;
+
+    for (;in; in=in->next) {
+       expr = (struct expr *) tac_malloc(sizeof(struct expr));
+       expr->line = in->line;
+       expr->next = NULL;
+       expr->type = in->type;
+       switch (in->type) {
+
+       case S_not:
+           if (in->u.not.child && in->u.not.child->type==S_not) {
+               free(expr);
+               expr = dupl_expr(in->u.not.child->u.not.child);
+           } else
+               expr->u.not.child = dupl_expr(in->u.not.child);
+           break;
+
+       case S_and:
+       case S_or:
+           if (!in->u.and_or.child_first) {
+               free(expr);
+               continue;
+           } else if (!in->u.and_or.child_first->next) {
+               free(expr);
+               expr = dupl_expr(in->u.and_or.child_first);
+           } else
+               expr->u.and_or.child_first = dupl_expr(in->u.and_or.child_first);
+           break;
+
+       case S_user:
+       case S_host:
+       case S_group:
+           if (in->u.entity.name)
+               expr->u.entity.name = tac_strdup(in->u.entity.name);
+           else
+               expr->u.entity.name = NULL;
+           expr->u.entity.entity = in->u.entity.entity;
+           break;
+
+       default:
+           report(LOG_ERR, "Illegal node type %d for dupl_expr", in->type);
+           free_expr(expr_root);
+           return (NULL);
+       }
+
+       *succ_exprp = expr;
+       succ_exprp = &expr->next;
+    }
+    return (expr_root);
+}
+
+
+/* 'check_*_scan_*()' section:
+ */
+
+static void check_request_scan_expr TAC_ARGS((struct expr *expr, int flush));
+
+static void
+check_request_scan_expr(expr, flush)
+struct expr *expr;
+int flush;
+{
+#if REPORT_CHECK_SCAN_VERBOSE
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "check_request_scan_expr: " PF_EXPR " (" PF_ERESULT_EXPR ")",
+               PA_EXPR(expr), PA_ERESULT_EXPR(expr));
+#endif
+
+    if (!flush && expr->request_scan.seq == request_scan_seq)
+       return;         /* up to date */
+
+    expr->request_scan.result = ER_UNKNOWN;
+    expr->request_scan.loop_reported = 0;
+    expr->request_scan.seq = request_scan_seq;
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "check_request_scan_expr: done: " PF_EXPR,
+               PA_EXPR(expr));
+}
+
+static void check_eval_scan_expr TAC_ARGS((struct expr *expr, int flush));
+
+static void
+check_eval_scan_expr(expr, flush)
+struct expr *expr;
+int flush;
+{
+#if REPORT_CHECK_SCAN_VERBOSE
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "check_eval_scan_expr: " PF_EXPR,
+               PA_EXPR(expr));
+#endif
+
+    if (!flush && expr->eval_scan.seq == eval_scan_seq)
+       return;         /* up to date */
+    check_request_scan_expr(expr, 0);
+
+    switch (expr->type) {
+
+    case S_user:
+    case S_host:
+    case S_group: {
+#ifdef SCAN_PARANOIA
+              if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node) == &eval_notified_expr_list) {
+           report(LOG_ERR, "INTERNAL: expr still connected to eval_notified_expr_list in check_eval_scan_expr");
+       } else if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node)) {
+           ENTITY *notifying_entity = EXPR_ENTITY_TO_NOTIFYING_ENTITY(expr);
+
+           if (notifying_entity != expr->u.entity.entity)
+               report(LOG_ERR, "INTERNAL: expr->notify_expr_node->list != expr->entity");
+           if (notifying_entity->eval_scan.seq != expr->eval_scan.seq)
+               report(LOG_ERR, "INTERNAL: entity seq != expr node seq");
+           tac_list_node_remove(&expr->eval_scan.u.entity.notify_expr_node);
+           }
+#else /* SCAN_PARANOIA */
+       tac_list_node_init(&expr->eval_scan.u.entity.notify_expr_node);
+#endif /* SCAN_PARANOIA */
+       } break;
+    }
+
+    expr->eval_scan.seq = eval_scan_seq;       /* used above, keep as LAST! */
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "check_eval_scan_expr: done: " PF_EXPR,
+               PA_EXPR(expr));
+}
+
+static void check_request_scan_membership TAC_ARGS((struct membership *membership, int flush));
+
+static void
+check_request_scan_membership(membership, flush)
+struct membership *membership;
+int flush;
+{
+#if REPORT_CHECK_SCAN_VERBOSE
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "check_request_scan_membership: " PF_MEMBERSHIP " (" PF_ERESULT_MEMBERSHIP ")",
+               PA_MEMBERSHIP(membership), PA_ERESULT_MEMBERSHIP(membership));
+#endif
+
+    if (!flush && membership->request_scan.seq == request_scan_seq)
+       return;         /* up to date */
+
+#ifdef SCAN_PARANOIA
+    {
+        struct tac_list *virtual_list = tac_list_node_get_list(&membership->request_scan.virtual_membership_node);
+
+        if (virtual_list && virtual_list != &request_virtual_membership_list)
+           report(LOG_ERR, "Illegal list in membership->virtual_membership_node.list");
+       if (virtual_list)
+           tac_list_node_remove(&membership->request_scan.virtual_membership_node);
+    }
+#else /* SCAN_PARANOIA */
+    tac_list_node_init(&membership->request_scan.virtual_membership_node);
+#endif /* SCAN_PARANOIA */
+
+    membership->request_scan.seq = request_scan_seq;   /* used above, keep as LAST! */
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "check_request_scan_membership: done: " PF_MEMBERSHIP,
+               PA_MEMBERSHIP(membership));
+}
+
+/* we are cross-checking (membership<->parent entity)! */
+
+static void check_eval_scan_membership TAC_ARGS((struct membership *membership, int flush));
+
+static void
+check_eval_scan_membership(membership, flush)
+struct membership *membership;
+int flush;
+{
+#if REPORT_CHECK_SCAN_VERBOSE
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "check_eval_scan_membership: " PF_MEMBERSHIP,
+               PA_MEMBERSHIP(membership));
+#endif
+
+    if (!flush && membership->eval_scan.seq == eval_scan_seq)
+       return;         /* up to date */
+    check_request_scan_membership(membership, 0);
+
+    membership->eval_scan.unsolved = 1;
+    membership->eval_scan.seq = eval_scan_seq;
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "check_eval_scan_membership: done: " PF_MEMBERSHIP,
+               PA_MEMBERSHIP(membership));
+}
+
+static void check_request_scan_entity TAC_ARGS((ENTITY *entity, int flush));
+
+static void
+check_request_scan_entity(entity, flush)
+ENTITY *entity;
+int flush;
+{
+#if REPORT_CHECK_SCAN_VERBOSE
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "check_request_scan_entity: " PF_ENTITY " (" PF_ERESULT_ENTITY ")",
+               PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
+#endif
+
+    if (!flush && entity->request_scan.seq == request_scan_seq)
+       return;
+
+    entity->request_scan.belongs = ER_UNKNOWN;
+    entity->request_scan.seq = request_scan_seq;
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "check_request_scan_entity: done: " PF_ENTITY,
+               PA_ENTITY(entity));
+}
+
+static void check_value_scan_entity TAC_ARGS((ENTITY *entity, int flush));
+
+static void
+check_value_scan_entity(entity, flush)
+ENTITY *entity;
+int flush;
+{
+#if REPORT_CHECK_SCAN_VERBOSE
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "check_value_scan_entity: " PF_ENTITY,
+               PA_ENTITY(entity));
+#endif
+
+    if (!flush && entity->value_scan.seq == value_scan_seq)
+       return;
+    check_request_scan_entity(entity, 0);
+
+    entity->value_scan.seen = 0;
+    entity->value_scan.from = NULL;
+    entity->value_scan.seq = value_scan_seq;
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "check_value_scan_entity: done: " PF_ENTITY,
+               PA_ENTITY(entity));
+}
+
+static void check_eval_scan_entity TAC_ARGS((ENTITY *entity, int flush));
+
+static void
+check_eval_scan_entity(entity, flush)
+ENTITY *entity;
+int flush;
+{
+    struct tac_list_node *child_membership_parent_node;
+
+#if REPORT_CHECK_SCAN_VERBOSE
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "check_eval_scan_entity: " PF_ENTITY,
+               PA_ENTITY(entity));
+#endif
+
+    if (!flush && entity->eval_scan.seq == eval_scan_seq)
+       return;         /* up to date */
+    check_value_scan_entity(entity, 0);
+
+    entity->eval_scan.unsolved_to_child_membership_num = entity->to_child_membership_num;
+
+    if ((child_membership_parent_node = tac_list_first_node(&entity->to_child_membership_list))) {
+       struct membership *child_membership = PARENT_NODE_TO_MEMBERSHIP(child_membership_parent_node);
+
+       entity->eval_scan.unsolved_to_child_membership_first = child_membership;
+    } else
+       entity->eval_scan.unsolved_to_child_membership_first = NULL;
+
+#ifdef SCAN_PARANOIA
+    {
+       struct tac_list_node *notify_expr_node;
+
+       while ((notify_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
+           struct expr *notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(notify_expr_node);
+
+           if (notify_expr->u.entity.entity != entity)
+               report(LOG_ERR, "INTERNAL: notify_expr->entity != entity");
+           if (notify_expr->eval_scan.seq != entity->eval_scan.seq)
+               report(LOG_ERR, "INTERNAL: notify_expr seq != entity seq");
+           tac_list_node_remove(notify_expr_node);
+       }
+
+       if (tac_list_node_get_list(&entity->eval_scan.pending_entity_node))
+           tac_list_node_remove(&entity->eval_scan.pending_entity_node);
+    }
+#else /* SCAN_PARANOIA */
+    tac_list_init(&entity->eval_scan.notify_expr_list);
+    tac_list_node_init(&entity->eval_scan.pending_entity_node);
+#endif /* SCAN_PARANOIA */
+
+    entity->eval_scan.seq = eval_scan_seq;     /* used above, keep as LAST! */
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "check_eval_scan_entity: done: " PF_ENTITY,
+               PA_ENTITY(entity));
+}
+
+
+/* invalidation managing section (for '*_scan_begin()'):
+ */
+
+/* this will happen once upon 'unsigned' overflow, ehm */
+
+#define INVALIDATE_SEQ_PTR(object,ptr) \
+    (G_STRUCT_MEMBER(unsigned, ptr, invalidate_scan_##object##_table[what]) = (unsigned) -1)
+#define INVALIDATE_SEQ(object) \
+    (INVALIDATE_SEQ_PTR(object,object))
+
+static const long invalidate_scan_expr_table[IS_MAX]={
+    G_STRUCT_OFFSET(struct expr, request_scan.seq),
+    -1,
+    G_STRUCT_OFFSET(struct expr,    eval_scan.seq)};
+
+static void invalidate_scan_expr TAC_ARGS((struct expr *expr,enum invalidate_scan what));
+
+static void
+invalidate_scan_expr(expr_single, what)
+struct expr *expr_single;
+enum invalidate_scan what;
+{
+    struct expr *expr_parent, *expr_child;
+
+    if (!expr_single) {
+       report(LOG_ERR, "INTERNAL: NULL input expressions not support by invalidate_scan_expr");
+       return;
+    }
+    if (expr_single->parent) {
+       report(LOG_ERR, "INTERNAL: non-root expressions not supported by invalidate_scan_expr");
+       return;
+    }
+
+    /* TOP->DOWN scanner: */
+top_down:
+    do {
+       INVALIDATE_SEQ_PTR(expr,expr_single);
+       expr_parent = expr_single;
+
+       switch (expr_parent->type) {
+
+       case S_not:
+           expr_child = expr_parent->u.not.child;
+           continue;
+
+       case S_and:
+       case S_or:
+           expr_child = expr_parent->u.and_or.child_first;
+           break;
+
+       case S_user:
+       case S_host:
+       case S_group:
+           expr_child = NULL;  /* no child exists */
+           break;
+
+       default:
+           report(LOG_ERR, "Illegal child node type %d for invalidate_scan_expr", expr_parent->type);
+           return;
+       }
+    } while ((expr_single = expr_child));
+    /* expr_child==NULL, we have only expr_parent: */
+
+    expr_child = expr_parent;
+
+    /* we have only expr_child: */
+    /* BOTTOM->UP scanner */
+    do {
+        if ((expr_single = expr_child->next))
+           goto top_down;
+       expr_parent = expr_child->parent;
+    } while ((expr_child = expr_parent));
+}
+
+static const long invalidate_scan_membership_table[IS_MAX]={
+    G_STRUCT_OFFSET(struct membership, request_scan.seq),
+    -1,
+    G_STRUCT_OFFSET(struct membership,    eval_scan.seq)};
+
+static void invalidate_scan_membership TAC_ARGS((struct membership *membership,enum invalidate_scan what));
+
+static void
+invalidate_scan_membership(membership, what)
+struct membership *membership;
+enum invalidate_scan what;
+{
+    INVALIDATE_SEQ(membership);
+
+    if (membership->when)
+       invalidate_scan_expr(membership->when, what);
+}
+
+static const long invalidate_scan_entity_table[IS_MAX]={
+    G_STRUCT_OFFSET(ENTITY, request_scan.seq),
+    G_STRUCT_OFFSET(ENTITY,   value_scan.seq),
+    G_STRUCT_OFFSET(ENTITY,    eval_scan.seq)};
+
+static void invalidate_scan_entity TAC_ARGS((ENTITY *entity,enum invalidate_scan what));
+
+static void
+invalidate_scan_entity(entity, what)
+ENTITY *entity;
+enum invalidate_scan what;
+{
+    struct tac_list_node *child_membership_node;
+    struct membership *child_membership;
+
+    INVALIDATE_SEQ(entity);
+
+    if (what==IS_VALUE)                /* optimalization */
+       return;
+
+    for (
+           child_membership_node = tac_list_first_node(&entity->to_child_membership_list);
+           child_membership_node;
+           child_membership_node = tac_list_node_next(&child_membership->parent_node)
+           ) {
+       child_membership = PARENT_NODE_TO_MEMBERSHIP(child_membership_node);
+       invalidate_scan_membership(child_membership, what);
+    }
+}
+
+void scan_invalidate_entities_hashtable TAC_ARGS((void **hashtable, enum invalidate_scan what));
+
+void
+scan_invalidate_entities_hashtable(hashtable, what)
+void **hashtable;
+enum invalidate_scan what;
+{
+    int i;
+    ENTITY *entity;
+
+    for (i = 0; i < HASH_TAB_SIZE; i++)
+       for (entity = (ENTITY *) hashtable[i]; entity; entity = entity->hash)
+           invalidate_scan_entity(entity, what);
+}
+
+/* '*_scan_begin()' section:
+ */
+
+void request_scan_begin TAC_ARGS((void));
+
+void
+request_scan_begin()
+{
+#ifdef SCAN_PARANOIA
+    static int inited = 0;
+#endif /* SCAN_PARANOIA */
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "request_scan_begin:");
+
+    request_scan_user_known = 0;
+
+    if (!++request_scan_seq)
+       scan_invalidate_entities(IS_REQUEST);
+
+#ifdef SCAN_PARANOIA
+    if (!inited) {
+#endif /* SCAN_PARANOIA */
+       tac_list_init(&request_virtual_membership_list);
+#ifdef SCAN_PARANOIA
+       inited = 1;
+    } else {
+       struct tac_list_node *virtual_membership_node;
+
+       while ((virtual_membership_node = tac_list_first_node(&request_virtual_membership_list))) {
+           struct membership *virtual_membership = VIRTUAL_MEMBERSHIP_NODE_TO_MEMBERSHIP(virtual_membership_node);
+
+           if (virtual_membership->request_scan.seq == request_scan_seq)
+               report(LOG_ERR, "INTERNAL: request_virtual_membership_list membership seq == ++request_scan_seq in request_scan_begin");
+           tac_list_node_remove(virtual_membership_node);
+           unlink_membership(virtual_membership);
+           free_membership(virtual_membership);
+           }
+    }
+#endif /* SCAN_PARANOIA */
+}
+
+static void value_scan_begin TAC_ARGS((ENTITY *entity));
+
+static void
+value_scan_begin(entity)
+ENTITY *entity;
+{
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "value_scan_begin:");
+
+    if (!++value_scan_seq)
+       scan_invalidate_entities(IS_VALUE);
+
+    check_value_scan_entity(entity, 0);        /* sure as seq invalidated */
+    /* assumed (entity->value_scan.from == NULL) */
+}
+
+#ifdef SCAN_PARANOIA
+
+static void eval_scan_begin_pending_entity_node TAC_ARGS((struct tac_list_node *pending_entity_node));
+
+static void
+eval_scan_begin_pending_entity_node(pending_entity_node)
+struct tac_list_node *pending_entity_node;
+{
+    ENTITY *pending_entity = PENDING_ENTITY_NODE_TO_ENTITY(pending_entity_node);
+
+    if (pending_entity->eval_scan.seq == eval_scan_seq)
+       report(LOG_ERR, "INTERNAL: eval_{pending}_entity_list entity seq == ++eval_scan_seq in eval_scan_begin");
+
+    tac_list_node_remove(pending_entity_node);
+}
+
+#endif /* SCAN_PARANOIA */
+
+static void eval_scan_begin TAC_ARGS((void));
+
+static void
+eval_scan_begin()
+{
+#ifdef SCAN_PARANOIA
+    static int inited = 0;
+#endif /* SCAN_PARANOIA */
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "eval_scan_begin:");
+
+    if (!++eval_scan_seq)
+       scan_invalidate_entities(IS_EVAL);
+
+#ifdef SCAN_PARANOIA
+    if (!inited) {
+#endif /* SCAN_PARANOIA */
+       tac_list_init(&eval_kicked_entity_list);
+       tac_list_init(&eval_destroy_entity_list);
+       tac_list_init(&eval_notified_expr_list);
+#ifdef SCAN_PARANOIA
+       inited = 1;
+    } else {
+       struct tac_list_node *pending_entity_node;
+       struct tac_list_node *notify_expr_node;
+
+       while ((pending_entity_node = tac_list_first_node(&eval_kicked_entity_list)))
+           eval_scan_begin_pending_entity_node(pending_entity_node);
+       while ((pending_entity_node = tac_list_first_node(&eval_destroy_entity_list)))
+           eval_scan_begin_pending_entity_node(pending_entity_node);
+
+       while ((notify_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
+           struct expr *notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(notify_expr_node);
+
+           if (notify_expr->eval_scan.seq == eval_scan_seq)
+               report(LOG_ERR, "INTERNAL: eval_notified_expr_list expr seq == ++eval_scan_seq in eval_scan_begin");
+
+           tac_list_node_remove(notify_expr_node);
+       }
+    }
+#endif /* SCAN_PARANOIA */
+}
+
+/* 'priority=0' => addtail - used for WANTED entities
+ * 'priority=1' => addhead - used for SOLVED entities
+ *                 It may be better to do insert it AFTER all currently solved
+ *                 entities but may be not but who cares...
+ */
+
+static void register_kicked_entity TAC_ARGS((ENTITY *entity, int priority));
+
+static void register_kicked_entity(entity, priority)
+ENTITY *entity;
+int priority;
+{
+    struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
+
+    check_eval_scan_entity(entity, 0);
+
+    if (tac_list_node_get_list(pending_entity_node) == &eval_destroy_entity_list) {
+       tac_list_node_remove (pending_entity_node);
+       if (debug & DEBUG_CFGEVAL_FLAG)
+           report(LOG_DEBUG, "register_kicked_entity: REMOVED " PF_ENTITY " from eval_DESTROY_entity_list",
+                   PA_ENTITY(entity));
+    }
+    if (tac_list_node_get_list(pending_entity_node) == NULL) {
+       if (priority)
+           tac_list_addhead(&eval_kicked_entity_list, pending_entity_node);
+       else
+           tac_list_addtail(&eval_kicked_entity_list, pending_entity_node);
+       if (debug & DEBUG_CFGEVAL_FLAG)
+           report(LOG_DEBUG, "register_kicked_entity: REGISTERED " PF_ENTITY " to eval_KICKED_entity_list (priority=%s)",
+                   PA_ENTITY(entity), (priority ? "YES" : "NO"));
+    }
+#ifdef SCAN_PARANOIA
+    if ((tac_list_node_get_list(pending_entity_node) != &eval_kicked_entity_list)) {
+       report(LOG_ERR, "Illegal list in entity->pending_entity_node.list");
+       return;
+    }
+#endif
+}
+
+/* check_eval_scan_*() is assumed both for "expr" and for "entity" ! */
+
+static void expr_eval_notify_expr TAC_ARGS((struct expr *expr));
+
+static void
+expr_eval_notify_expr(expr)
+struct expr *expr;
+{
+    ENTITY *entity = expr->u.entity.entity;
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "expr_eval_notify_expr: REGISTERED notify " PF_EXPR " when " PF_ENTITY " is known",
+               PA_EXPR(expr), PA_ENTITY(entity));
+
+    if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
+       return;
+
+    tac_list_addtail(&entity->eval_scan.notify_expr_list,
+           &expr->eval_scan.u.entity.notify_expr_node);
+
+    register_kicked_entity(entity, 0 /* priority */);
+}
+
+/* check_eval_scan_*() is assumed for "expr" ! */
+
+static void expr_eval_notify_expr_remove_internal TAC_ARGS((struct expr *expr));
+
+static void
+expr_eval_notify_expr_remove_internal(expr)
+struct expr *expr;
+{
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "expr_eval_notify_expr_remove_internal: no longer interested in " PF_EXPR,
+               PA_EXPR(expr));
+
+    if (!expr)
+       return;
+    if (expr->eval_scan.seq != eval_scan_seq)
+       return;
+    if (expr->request_scan.result != ER_UNKNOWN)
+       return;
+
+    switch (expr->type) {
+
+    case S_not:
+       expr_eval_notify_expr_remove_internal(expr->u.not.child);
+       break;
+
+    case S_and:
+    case S_or: {
+       struct expr *child;
+
+       for (child=expr->u.and_or.child_first; child; child=child->next)
+           expr_eval_notify_expr_remove_internal(child);
+       } break;
+
+    case S_user:
+    case S_host:
+    case S_group: {
+       ENTITY *entity = expr->u.entity.entity;
+       struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
+
+       if (!tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
+           break;
+
+       tac_list_node_remove(&expr->eval_scan.u.entity.notify_expr_node);
+       if (tac_list_first_node(&entity->eval_scan.notify_expr_list))
+           break;
+       /* no one is further interested in "entity" */
+
+       if ((tac_list_node_get_list(pending_entity_node) == &eval_kicked_entity_list)) {
+           tac_list_node_remove (pending_entity_node);
+           if (debug & DEBUG_CFGEVAL_FLAG)
+               report(LOG_DEBUG, "expr_eval_notify_expr: REMOVED " PF_ENTITY " from eval_KICKED_entity_list",
+                       PA_ENTITY(entity));
+       }
+       if (tac_list_node_get_list(pending_entity_node) == NULL) {
+           tac_list_addtail(&eval_destroy_entity_list, pending_entity_node);
+           if (debug & DEBUG_CFGEVAL_FLAG)
+               report(LOG_DEBUG, "expr_eval_notify_expr: REGISTERED " PF_ENTITY " to eval_DESTROY_entity_list",
+                       PA_ENTITY(entity));
+       }
+#ifdef SCAN_PARANOIA
+       if (tac_list_node_get_list(pending_entity_node) != &eval_destroy_entity_list) {
+           report(LOG_ERR, "Illegal list in entity->pending_entity_node.list");
+           return;
+       }
+#endif
+
+       } break;
+
+    default:
+       report(LOG_ERR, "Illegal node type %d for expr_eval_notify_expr_remove", expr->type);
+       return;
+    }
+}
+
+static void expr_eval_notify_expr_flush_destroy_entity_list TAC_ARGS((void));
+
+static void expr_eval_notify_expr_flush_destroy_entity_list()
+{
+struct tac_list_node *destroy_entity_node;
+
+    while ((destroy_entity_node = tac_list_first_node(&eval_destroy_entity_list))) {
+       ENTITY *destroy_entity = PENDING_ENTITY_NODE_TO_ENTITY(destroy_entity_node);
+       struct tac_list_node *destroy_notify_expr_node;
+
+       if (debug & DEBUG_CFGEVAL_FLAG)
+           report(LOG_DEBUG, "expr_eval_notify_expr_flush_destroy_entity_list: PROCESSING " PF_ENTITY " from eval_DESTROY_entity_list",
+                   PA_ENTITY(destroy_entity));
+
+       while ((destroy_notify_expr_node = tac_list_first_node(&destroy_entity->eval_scan.notify_expr_list))) {
+           struct expr *destroy_notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(destroy_notify_expr_node);
+
+           expr_eval_notify_expr_remove_internal(destroy_notify_expr);
+       }
+    }
+}
+
+static void expr_eval_notify_expr_remove TAC_ARGS((struct expr *expr));
+
+static void
+expr_eval_notify_expr_remove(expr)
+struct expr *expr;
+{
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "expr_eval_notify_expr_remove: no longer interested in " PF_EXPR,
+               PA_EXPR(expr));
+
+    expr_eval_notify_expr_remove_internal(expr);
+    expr_eval_notify_expr_flush_destroy_entity_list();
+}
+
+/* It would be very nice to try to optimize the expression before evaluation.
+
+   We are not interested in some CPU time complexity of the expression.
+   But we would be very happy to discard any user/host/group membership
+   dependencies (our 'variables'). Unfortunately such optimization is
+   NP problem (classification by courtesy of Daniel Kral) so it is considered
+   too expensive for us.
+
+   TODO in future: Full NP optimization for small number of variables and/or
+   heuristic optimizations for complex expressions.
+*/
+
+static enum eval_result expr_eval_immediate TAC_ARGS((struct expr *expr_single));
+
+static enum eval_result
+expr_eval_immediate(expr_single)
+struct expr *expr_single;
+{
+    struct expr *expr_child, *expr_parent;
+    enum eval_result result_child, result_parent = 0 /* GCC paranoia */;
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "expr_eval_immediate: " PF_EXPR,
+               PA_EXPR(expr_single));
+
+    if (!expr_single)
+       return (ER_TRUE);
+
+    /* TOP->DOWN scanner: */
+top_down:
+    while (1) {
+       enum eval_result result_single;
+
+       if (debug & DEBUG_CFGEVAL_FLAG)
+           report(LOG_DEBUG, "expr_eval_immediate: top_down start: " PF_EXPR,
+                   PA_EXPR(expr_single));
+
+       check_eval_scan_expr(expr_single, 0);
+       result_single = expr_single->request_scan.result;
+       if (result_single != ER_UNKNOWN)
+           break;
+       switch (expr_single->type) {
+
+       case S_not:
+           expr_single = expr_single->u.not.child;
+           continue;
+
+       case S_and:
+       case S_or:
+           expr_single = expr_single->u.and_or.child_first;
+           continue;
+
+       case S_user:
+       case S_host:
+       case S_group: {
+           ENTITY *entity = expr_single->u.entity.entity;
+
+           check_eval_scan_entity(entity, 0);
+
+           if (entity->request_scan.belongs == ER_UNKNOWN)
+               expr_eval_notify_expr(expr_single);
+           else
+               result_single = entity->request_scan.belongs;
+           } break;
+
+       default:
+           report(LOG_ERR, "Illegal child node type %d for expr_eval", expr_single->type);
+           return (ER_UNKNOWN);
+       }
+
+       expr_single->request_scan.result = result_single;
+       break;
+    }
+
+    /* BOTTOM->UP scanner: */
+    do {
+       if (debug & DEBUG_CFGEVAL_FLAG)
+           report(LOG_DEBUG, "expr_eval_immediate: bottom_up start: " PF_EXPR,
+                   PA_EXPR(expr_single));
+
+       expr_parent = expr_single->parent;
+       if (!expr_parent)
+           break;
+       if (expr_parent->eval_scan.seq != eval_scan_seq) {
+           report(LOG_ERR, "INTERNAL: Parent expr node eval_scan NOT up-to-date");
+           return (ER_UNKNOWN);
+       }
+       if (expr_parent->request_scan.seq != request_scan_seq) {
+           report(LOG_ERR, "INTERNAL: Parent expr node request_scan NOT up-to-date");
+           return (ER_UNKNOWN);
+       }
+       if (expr_parent->request_scan.result != ER_UNKNOWN) {
+           report(LOG_WARNING, "INTERNAL-WARNING: Parent expr node already known, wasteful eval occured");
+           return (ER_UNKNOWN);
+       }
+
+       expr_child = expr_single;
+       result_child = expr_child->request_scan.result;
+
+       if (debug & DEBUG_CFGEVAL_FLAG)
+           report(LOG_DEBUG, "expr_eval_immediate: bottom_up switch: child=" PF_EXPR ",parent=" PF_EXPR,
+                   PA_EXPR(expr_child), PA_EXPR(expr_parent));
+
+       switch (expr_parent->type) {
+
+       case S_not:
+           switch (result_child) {
+           case ER_UNKNOWN: result_parent = ER_UNKNOWN; break;
+           case ER_FALSE:   result_parent = ER_TRUE;    break;
+           case ER_TRUE:    result_parent = ER_FALSE;   break;
+           }
+           break;
+
+       case S_and:
+       case S_or: {
+           enum eval_result veto    = (expr_parent->type==S_and ? ER_FALSE : ER_TRUE );
+           enum eval_result consent = (expr_parent->type==S_and ? ER_TRUE  : ER_FALSE);
+
+                if (result_child == veto)
+               result_parent = veto;
+           else if (result_child == ER_UNKNOWN || result_child == consent) {
+               if (expr_child->next) {
+                   expr_single = expr_child->next;
+                   if (debug & DEBUG_CFGEVAL_FLAG)
+                       report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: traversed to and_or next: " PF_EXPR,
+                               PA_EXPR(expr_single));
+                   goto top_down;
+               }
+
+               if (debug & DEBUG_CFGEVAL_FLAG)
+                   report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: full scan: " PF_EXPR,
+                           PA_EXPR(expr_single));
+
+               result_parent = consent;
+               for (expr_child = expr_parent->u.and_or.child_first; expr_child; expr_child = expr_child->next)
+               {
+                   check_eval_scan_expr(expr_child, 0);        /* shouldn't be needed */
+                        if (expr_child->request_scan.result == ER_UNKNOWN)
+                       result_parent = ER_UNKNOWN;     /* assumed (result_parent != veto) */
+                   else if (expr_child->request_scan.result == veto) {
+                       result_parent = veto;
+                       break;
+                   }
+               }
+               break;
+           }
+           } break;
+
+       default:
+           report(LOG_ERR, "Illegal parent node type %d for expr_eval", expr_parent->type);
+           return (ER_UNKNOWN);
+       }
+
+       if (debug & DEBUG_CFGEVAL_FLAG)
+           report(LOG_DEBUG, "expr_eval_immediate: bottom_up end: child=" PF_EXPR ",parent=" PF_EXPR,
+                   PA_EXPR(expr_child), PA_EXPR(expr_parent));
+
+       if (result_parent != ER_UNKNOWN) {
+           expr_parent->request_scan.result = result_parent;
+           /* we no longer need any notifications from entities to solve sub-expression */
+           expr_eval_notify_expr_remove(expr_parent);
+       }
+
+       expr_single = expr_parent;
+    } while (0);
+    /* The whole expression has been scanned to its root, we have "expr_single" */
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "expr_eval_immediate: done: " PF_EXPR,
+               PA_EXPR(expr_single));
+
+    return (expr_single->request_scan.result);
+}
+
+static void membership_solved TAC_ARGS((struct membership *membership));
+
+static void
+membership_solved(membership)
+struct membership *membership;
+{
+    ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
+
+    check_request_scan_entity(parent_entity, 0);
+
+#ifdef SCAN_PARANOIA
+    if (!membership->eval_scan.unsolved) {
+       report(LOG_ERR, "INTERNAL: membership already solved in membership_solved");
+       return;
+    }
+#endif
+
+    membership->eval_scan.unsolved = 0;
+
+#ifdef SCAN_PARANOIA
+    if (!parent_entity->eval_scan.unsolved_to_child_membership_num) {
+       report(LOG_ERR, "INTERNAL: unsolved_to_child_membership_num-- == 0 in membership_solved");
+       parent_entity->eval_scan.unsolved_to_child_membership_num++;
+    }
+#endif
+    parent_entity->eval_scan.unsolved_to_child_membership_num--;
+
+    if (!parent_entity->eval_scan.unsolved_to_child_membership_num
+     && parent_entity->request_scan.belongs == ER_UNKNOWN) {
+       parent_entity->request_scan.belongs = ER_FALSE;
+       register_kicked_entity(parent_entity, 1 /* priority */);
+    }
+}
+
+static void membership_parent_solve TAC_ARGS((struct membership *membership, enum eval_result how));
+
+static void
+membership_parent_solve(membership, how)
+struct membership *membership;
+enum eval_result how;
+{
+    enum eval_result negative = (how == ER_TRUE ? ER_FALSE : ER_TRUE);
+    ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
+
+    check_request_scan_entity(parent_entity, 0);
+
+    if (parent_entity->request_scan.belongs == negative)
+       report(LOG_ERR, "INTERNAL: parent " PF_ENTITY "already negative to what says membership " PF_MEMBERSHIP "in membership_eval_immediate",
+               PA_ENTITY(parent_entity), PA_MEMBERSHIP(membership));
+
+    parent_entity->request_scan.belongs = how;
+    register_kicked_entity(parent_entity, 1 /* priority */);
+
+    membership_solved(membership);
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "membership_parent_solve: " PF_MEMBERSHIP " marked parent " PF_ENTITY,
+               PA_MEMBERSHIP(membership), PA_ENTITY(parent_entity));
+}
+
+static void membership_eval_immediate TAC_ARGS((struct membership *membership));
+
+static void
+membership_eval_immediate(membership)
+struct membership *membership;
+{
+    enum eval_result membership_valid;
+    ENTITY *child_entity, *parent_entity;
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "membership_eval_immediate: " PF_MEMBERSHIP,
+               PA_MEMBERSHIP(membership));
+
+    check_eval_scan_membership(membership, 0);
+
+    if (!membership->eval_scan.unsolved)
+       return;
+    parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
+    check_request_scan_entity(parent_entity, 0);
+    if (parent_entity->request_scan.belongs != ER_UNKNOWN)     /* why to solve this membership? */
+       return;
+
+    membership_valid = expr_eval_immediate(membership->when);
+
+    child_entity = MEMBERSHIP_TO_CHILD_ENTITY( membership);
+    check_request_scan_entity( child_entity, 0);
+
+    if (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE) {
+       membership_parent_solve(membership, ER_FALSE);
+       return;
+    }
+    if (child_entity->request_scan.belongs == ER_TRUE  && membership_valid == ER_TRUE ) {
+       membership_parent_solve(membership, ER_TRUE );
+       return;
+    }
+
+    if ( child_entity->request_scan.belongs == ER_UNKNOWN)
+       register_kicked_entity( child_entity, 0 /* priority */);
+    if (parent_entity->request_scan.belongs == ER_UNKNOWN)
+       register_kicked_entity(parent_entity, 0 /* priority */);
+
+    if ( child_entity->request_scan.belongs != ER_UNKNOWN
+     && parent_entity->request_scan.belongs != ER_UNKNOWN)
+       membership_solved(membership);
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "membership_eval_immediate: done: " PF_MEMBERSHIP,
+               PA_MEMBERSHIP(membership));
+}
+
+static void entity_eval_immediate TAC_ARGS((ENTITY *entity));
+
+static void
+entity_eval_immediate(entity)
+ENTITY *entity;
+{
+    struct tac_list_node *notified_expr_node;
+    struct tac_list_node *child_membership_node;
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "entity_eval_immediate: " PF_ENTITY,
+               PA_ENTITY(entity));
+
+    check_eval_scan_entity(entity, 0);
+
+    if (!request_scan_user_known) {
+#ifdef SCAN_PARANOIA
+       if (entity->request_scan.belongs != ER_UNKNOWN)
+           report(LOG_ERR, "INTERNAL: belonging known while still !request_scan_user_known for " PF_ENTITY " in entity_eval_immediate",
+                   PA_ENTITY(entity));
+#endif
+       return;
+    }
+
+    if (entity->request_scan.belongs == ER_UNKNOWN) {
+       if (entity->eval_scan.unsolved_to_child_membership_first) {
+           struct membership *order_membership = entity->eval_scan.unsolved_to_child_membership_first;
+           struct tac_list_node *next_membership_parent_node = tac_list_node_next(&order_membership->parent_node);
+
+           membership_eval_immediate(order_membership);
+           if (next_membership_parent_node)
+               entity->eval_scan.unsolved_to_child_membership_first = PARENT_NODE_TO_MEMBERSHIP(next_membership_parent_node);
+           else
+               entity->eval_scan.unsolved_to_child_membership_first = NULL;
+
+           register_kicked_entity(entity, 0 /* priority */);
+
+           if (debug & DEBUG_CFGEVAL_FLAG)
+               report(LOG_DEBUG, "entity_eval_immediate: finishing as we ordered child membership: " PF_MEMBERSHIP,
+                       PA_MEMBERSHIP(order_membership));
+           return;
+       }
+
+       if (!entity->eval_scan.unsolved_to_child_membership_num)
+           entity->request_scan.belongs = ER_FALSE;
+       else {
+           if (debug & DEBUG_CFGEVAL_FLAG)
+               report(LOG_DEBUG, "entity_eval_immediate: finishing as unsolved child memberships still available and I'm still clueless");
+               return;
+       }
+    }
+    /* belonging is known here */
+
+    /* recheck all memberships we may decide */
+    for (
+           child_membership_node = tac_list_first_node(&entity->to_parent_membership_list);
+           child_membership_node;
+           child_membership_node = tac_list_node_next(child_membership_node)
+           ) {
+       struct membership *child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
+
+       membership_eval_immediate(child_membership);
+    }
+
+    /* notify all exprs which are interested in us */
+    while ((notified_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
+       tac_list_node_remove(notified_expr_node);
+       tac_list_addtail(&eval_notified_expr_list, notified_expr_node);
+    }
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "entity_eval_immediate: done: " PF_ENTITY,
+               PA_ENTITY(entity));
+}
+
+
+enum eval_result expr_eval TAC_ARGS((struct expr *expr));
+
+enum eval_result
+expr_eval(expr)
+struct expr *expr;
+{
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "expr_eval: top level order for " PF_EXPR,
+               PA_EXPR(expr));
+
+    if (!expr)
+       return (ER_TRUE);
+
+    eval_scan_begin();
+    if (expr_eval_immediate(expr) != ER_UNKNOWN)
+       return (expr->request_scan.result);
+
+    /* all 'solved' nodes MUST be removed BEFORE '*_immediate()' has been called,
+     * otherwise we may have no longer valid node!
+     */
+    for (;;) {
+       struct tac_list_node *notified_expr_node, *kicked_entity_node;
+
+       /* check it rather always, checking just on notifications looks too complex.
+       */
+       if (expr->request_scan.result != ER_UNKNOWN) {
+           if (debug & DEBUG_CFGEVAL_FLAG)
+               report(LOG_DEBUG, "expr_eval: finishing as ordered " PF_EXPR " got known",
+                       PA_EXPR(expr));
+           return (expr->request_scan.result);
+       }
+
+#if 0  /* not needed as it is now always called after any destroy */
+       expr_eval_notify_expr_flush_destroy_entity_list();      /* eval_destroy_entity_list */
+#endif /* not needed */
+
+       if ((notified_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
+           struct expr *notified_expr = NOTIFY_EXPR_NODE_TO_EXPR(notified_expr_node);
+
+           if (debug & DEBUG_CFGEVAL_FLAG)
+               report(LOG_DEBUG, "expr_eval: PROCESSING " PF_EXPR " from eval_NOTIFIED_expr_list",
+                       PA_EXPR(notified_expr));
+
+           tac_list_node_remove(notified_expr_node);
+           expr_eval_immediate(notified_expr);
+
+           if (notified_expr->membership)
+               membership_eval_immediate(notified_expr->membership);
+
+           continue;           /* shortcut */
+       }
+
+       if ((kicked_entity_node = tac_list_first_node(&eval_kicked_entity_list))) {
+           ENTITY *kicked_entity = PENDING_ENTITY_NODE_TO_ENTITY(kicked_entity_node);
+
+           if (debug & DEBUG_CFGEVAL_FLAG)
+               report(LOG_DEBUG, "expr_eval: PROCESSING " PF_ENTITY " from eval_KICKED_entity_list",
+                       PA_ENTITY(kicked_entity));
+
+           tac_list_node_remove(kicked_entity_node);
+           entity_eval_immediate(kicked_entity);
+           continue;           /* shortcut */
+       }
+
+       break;  /* nothing done yet, all lists are empty! */
+    }
+
+    if (!expr->request_scan.loop_reported) {
+       report(LOG_WARNING, "Unable to resolve expression from line %d, some looping occured", expr->line);
+       expr->request_scan.loop_reported = 1;
+    }
+    return (ER_UNKNOWN);
+}
+
+
+void eval_force_belong_entity TAC_ARGS((ENTITY *entity));
+
+void eval_force_belong_entity(entity)
+ENTITY *entity;
+{
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "eval_force_belong_entity: " PF_ENTITY " (before check_scan " PF_ERESULT_ENTITY ")",
+               PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
+
+    check_request_scan_entity(entity, 0);
+
+    if (entity->request_scan.belongs == ER_FALSE)
+       report(LOG_ERR, "Dangerous force of TRUE to FALSE-determined entity in eval_force_belong_entity");
+
+    entity->request_scan.belongs = ER_TRUE;
+}
+
+void scan_init_entity TAC_ARGS((ENTITY *entity));
+
+void
+scan_init_entity(entity)
+ENTITY *entity;
+{
+    entity->request_scan.seq = request_scan_seq-1;     /* invalidate */
+    entity->  value_scan.seq =   value_scan_seq-1;     /* invalidate */
+    entity->   eval_scan.seq =    eval_scan_seq-1;     /* invalidate */
+    tac_list_init(&entity->eval_scan.notify_expr_list);
+    tac_list_node_init(&entity->eval_scan.pending_entity_node);
+}
+
+struct membership *enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child, struct expr *when));
+
+struct membership *
+enlist_entity_direct(parent, child, when)
+ENTITY *parent;
+ENTITY *child;
+struct expr *when;
+{
+    struct membership *membership = (struct membership *) tac_malloc(sizeof(struct membership));
+
+    tac_list_node_init(&membership->parent_node);
+    tac_list_node_init(&membership->child_node);
+    membership->request_scan.seq = request_scan_seq-1;
+    tac_list_node_init(&membership->request_scan.virtual_membership_node);
+    membership->eval_scan.seq = eval_scan_seq-1;
+
+    tac_list_addtail(&parent->to_child_membership_list , &membership->parent_node);
+    parent->to_child_membership_num++;
+    tac_list_addtail(& child->to_parent_membership_list, &membership-> child_node);
+    membership->when = when;
+    if (expr_sink(membership->when, membership)) {
+       unlink_membership(membership);
+       free_membership(membership);
+       return (NULL);
+    }
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "enlist_entity_direct: done: " PF_MEMBERSHIP,
+               PA_MEMBERSHIP(membership));
+
+    return (membership);
+}
+
+struct membership *virtual_enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child));
+
+struct membership *
+virtual_enlist_entity_direct(parent, child)
+ENTITY *parent;
+ENTITY *child;
+{
+    struct membership *membership;
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "virtual_enlist_entity_direct: the following enlist will be VIRTUAL...");
+
+    membership = enlist_entity_direct(parent, child, NULL /* when */);
+    if (!membership)
+       return (NULL);
+
+    check_request_scan_membership(membership, 0);
+    tac_list_addtail(&request_virtual_membership_list, &membership->request_scan.virtual_membership_node);
+
+    return (membership);
+}
+
+/* returns given 'entity' or NULL if already visited */
+
+void (*value_scan_forward_seen_hook) TAC_ARGS((struct membership *membership));
+
+static ENTITY *value_scan_forward TAC_ARGS((struct membership *membership));
+
+static ENTITY *
+value_scan_forward(membership)
+struct membership *membership;
+{
+    ENTITY *parent_entity;
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "value_scan_forward: from " PF_MEMBERSHIP " try forward...",
+               PA_MEMBERSHIP(membership));
+
+    parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
+
+    if (ER_TRUE != expr_eval(membership->when)) {
+       if (debug & DEBUG_CFGEVAL_FLAG)
+           report(LOG_DEBUG, "value_scan_forward: forward NOT successful due to failed 'when' evaluation.");
+       return (NULL);
+    }
+    check_value_scan_entity(parent_entity, 0);
+    if (parent_entity->value_scan.seen) {
+       if (debug & DEBUG_CFGEVAL_FLAG)
+           report(LOG_DEBUG, "value_scan_forward: forward NOT successful as the parent " PF_ENTITY " was already seen this value scan.",
+                   PA_ENTITY(parent_entity));
+       if (value_scan_forward_seen_hook)
+           (*value_scan_forward_seen_hook)(membership);
+       return (NULL);
+    }
+    parent_entity->value_scan.seen = 1;
+    parent_entity->value_scan.from = membership;
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "value_scan_forward: forward SUCCESSFUL to parent " PF_ENTITY,
+               PA_ENTITY(parent_entity));
+    return (parent_entity);
+}
+
+struct membership *value_scan_backward TAC_ARGS((ENTITY *entity));
+
+struct membership *
+value_scan_backward(entity)
+ENTITY *entity;
+{
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "value_scan_backward: from " PF_ENTITY " went back to " PF_MEMBERSHIP,
+               PA_ENTITY(entity), PA_MEMBERSHIP(entity->value_scan.from));
+
+#ifdef SCAN_PARANOIA
+    if (entity->value_scan.seq != value_scan_seq) {
+       report(LOG_ERR, "entity value_scan NOT up-to-date in value_scan_backward");
+       return (NULL);
+    }
+#endif
+
+    return (entity->value_scan.from);
+}
+
+/* Scan the entity graph and return each node found.
+   'when' conditions for graph connections are respected,
+   looping is correctly prevented.
+*/
+
+enum value_scan_func_result value_scan_entity TAC_ARGS((ENTITY *entity, int recurse, value_scan_func_t func, void *func_data));
+
+enum value_scan_func_result
+value_scan_entity(entity, recurse, func, func_data)
+ENTITY *entity;
+int recurse;
+value_scan_func_t func;
+void *func_data;
+{
+    enum value_scan_func_result vsfr;
+    struct tac_list_node *membership_node;
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "value_scan_entity: " PF_ENTITY ", recurse=%d",
+               PA_ENTITY(entity), recurse);
+
+    vsfr=(*func)(entity,func_data);
+
+    if (debug & DEBUG_CFGEVAL_FLAG)
+       report(LOG_DEBUG, "value_scan_entity: root func-> " PF_VSFR,
+               PA_VSFR(vsfr));
+
+    if (vsfr != VSFR_CONTINUE) {
+       if (debug & DEBUG_CFGEVAL_FLAG)
+           report(LOG_DEBUG, "value_scan_entity: finishing as root func didn't return VSFR_CONTINUE");
+       return (vsfr);
+    }
+    if (!recurse ) {
+       if (debug & DEBUG_CFGEVAL_FLAG)
+           report(LOG_DEBUG, "value_scan_entity: finishing as recurse not ordered");
+       return (VSFR_STOP);
+    }
+
+    value_scan_begin(entity);
+    membership_node = tac_list_first_node(&entity->to_parent_membership_list);
+    if (!membership_node) {
+       if (debug & DEBUG_CFGEVAL_FLAG)
+           report(LOG_DEBUG, "value_scan_entity: finishing as no parent entities of root");
+       return (VSFR_CONTINUE);         /* no parent entities */
+    }
+
+    while (1) {
+       struct membership *membership = CHILD_NODE_TO_MEMBERSHIP(membership_node);
+
+       if (debug & DEBUG_CFGEVAL_FLAG)
+           report(LOG_DEBUG, "value_scan_entity: trace loop start: " PF_MEMBERSHIP,
+                   PA_MEMBERSHIP(membership));
+
+       entity = value_scan_forward(membership);
+       if (entity) {
+           if (debug & DEBUG_CFGEVAL_FLAG)
+               report(LOG_DEBUG, "value_scan_entity: successful recurse to " PF_ENTITY,
+                       PA_ENTITY(entity));
+
+           vsfr=(*func)(entity,func_data);
+
+           if (debug & DEBUG_CFGEVAL_FLAG)
+               report(LOG_DEBUG, "value_scan_entity: func(" PF_ENTITY ")-> " PF_VSFR,
+                       PA_ENTITY(entity), PA_VSFR(vsfr));
+
+           if (vsfr == VSFR_FOUND) {
+               if (debug & DEBUG_CFGEVAL_FLAG)
+                   report(LOG_DEBUG, "value_scan_entity: finishing as func returned VSFR_FOUND");
+               return (vsfr);
+           }
+           if (vsfr == VSFR_CONTINUE)
+               membership_node = tac_list_first_node(&entity->to_parent_membership_list);
+       }
+       if (!entity || vsfr == VSFR_STOP) {
+           ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
+
+           entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);    /* for retreat from the LAST membership */
+
+           if (debug & DEBUG_CFGEVAL_FLAG)
+               report(LOG_DEBUG, "value_scan_entity: unsuccessful recurse to " PF_ENTITY ", tracing back through child " PF_ENTITY,
+                       PA_ENTITY(parent_entity), PA_ENTITY(entity));
+
+           membership_node = tac_list_node_next(&membership->child_node);
+       }
+
+       while (!membership_node) {
+           membership = value_scan_backward(entity);
+           if (!membership) {
+               if (debug & DEBUG_CFGEVAL_FLAG)
+                   report(LOG_DEBUG, "value_scan_entity: finishing as all nodes were scanned");
+               return (VSFR_CONTINUE);         /* FINISH */
+           }
+
+           entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);    /* for retreat from the LAST membership */
+
+           if (debug & DEBUG_CFGEVAL_FLAG)
+               report(LOG_DEBUG, "value_scan_entity: backward retreat ('next' chase) "
+                               "through " PF_MEMBERSHIP " to child " PF_ENTITY,
+                               PA_MEMBERSHIP(membership), PA_ENTITY(entity));
+
+           membership_node = tac_list_node_next(&membership->child_node);
+       }
+    }
+    /* NOTREACHED */
+}
diff --git a/cfgeval.h b/cfgeval.h
new file mode 100644 (file)
index 0000000..63f33cb
--- /dev/null
+++ b/cfgeval.h
@@ -0,0 +1,134 @@
+#ifndef CFGEVAL_H
+#define CFGEVAL_H 1
+
+#include "tac_plus.h"
+
+#include "utils.h"
+
+
+struct entity;
+typedef struct entity ENTITY;
+enum invalidate_scan {
+    IS_REQUEST = 0,
+    IS_VALUE   = 1,
+    IS_EVAL    = 2,
+    IS_MAX     = 3
+};
+
+enum eval_result {
+    ER_UNKNOWN,
+    ER_FALSE,
+    ER_TRUE
+};
+
+enum value_scan_func_result {
+    VSFR_CONTINUE,     /* for value_scan_entity() it means 'not found' */
+    VSFR_FOUND,                /* immediately return from the whole value_scan_entity() */
+    VSFR_STOP          /* backtrack (stop) this branch, scan further; nevere returned by value_scan_entity() */
+};
+
+struct membership {
+    struct tac_list_node parent_node;  /* to_child_membership_list , AKA legacy "member" */
+    struct tac_list_node  child_node;  /* to_parent_membership_list */
+
+    struct {
+       unsigned seq;                   /* corresponds to global request_scan_seq */
+       struct tac_list_node virtual_membership_node;
+    } request_scan;            /*   cfg_request() scanning */
+
+    struct {
+       unsigned seq;                   /* corresponds to global eval_scan_seq */
+       unsigned unsolved:1;            /* we haven't yet decreased
+                                        * parent_entity->eval_scan.unsolved_to_child_membership_num */
+    } eval_scan;               /*     expr_eval() scanning, many per value_scan */
+
+    struct expr *when;
+};
+#define MEMBERSHIP_TO_PARENT_ENTITY(membership) \
+       (&TAC_MEMBER_STRUCT(ENTITY, tac_list_node_get_list(&(membership)->parent_node), to_child_membership_list ))
+#define MEMBERSHIP_TO_CHILD_ENTITY(membership) \
+       (&TAC_MEMBER_STRUCT(ENTITY, tac_list_node_get_list(&(membership)-> child_node), to_parent_membership_list))
+#define PARENT_NODE_TO_MEMBERSHIP(parent_node_) \
+       (&TAC_MEMBER_STRUCT(struct membership, (parent_node_), parent_node))
+#define  CHILD_NODE_TO_MEMBERSHIP( child_node_) \
+       (&TAC_MEMBER_STRUCT(struct membership, ( child_node_),  child_node))
+#define UNSOLVED_CHILD_NODE_TO_MEMBERSHIP(unsolved_child_node_) \
+       (&TAC_MEMBER_STRUCT(struct membership, (unsolved_child_node_), eval_scan.unsolved_child_node))
+#define VIRTUAL_MEMBERSHIP_NODE_TO_MEMBERSHIP(virtual_membership_node_) \
+       (&TAC_MEMBER_STRUCT(struct membership, (virtual_membership_node_), request_scan.virtual_membership_node))
+
+struct expr {
+    struct {
+       unsigned seq;                   /* corresponds to global eval_scan_seq */
+       enum eval_result result;        /* known result of this whole branch */
+       unsigned loop_reported:1;       /* prevent excessive logging */
+    } request_scan;            /*   cfg_request() scanning */
+
+    struct {
+       unsigned seq;                   /* corresponds to global eval_scan_seq */
+       union {
+
+       struct {                /* for S_host, S_user or S_group */
+                       /* connected to either "entity->eval_scan.notify_expr_list"
+                        * or to global "eval_notified_expr_list"
+                        */
+           struct tac_list_node notify_expr_node;      /* gets removed on this expr->seq!= */
+       } entity;
+
+       } u;
+    } eval_scan;               /*     expr_eval() scanning, many per value_scan */
+
+    struct membership *membership;     /* our owner */
+    struct expr *parent;       /* NULL if we are the root expr */
+                               /* "parent" also (mis)used by expr_sink_{register,commit}() ! */
+    struct expr *next;         /* used in childs of S_and / S_or */
+    int type;                  /* S_not, S_and, S_or, S_host, S_user or S_group */
+    int line;
+    union {
+
+    struct {
+       struct expr *child;
+    } not;
+
+    struct {
+       struct expr *child_first;       /* linked by expr->next */
+    } and_or;
+
+    struct {           /* for S_host, S_user or S_group */
+       const char *name;
+       ENTITY *entity;
+    } entity;
+
+    } u;
+};
+#define EXPR_ENTITY_TO_NOTIFYING_ENTITY(expr_) \
+       (&TAC_MEMBER_STRUCT(ENTITY, tac_list_node_get_list(&(expr_)->eval_scan.u.entity.notify_expr_node), eval_scan.notify_expr_list))
+#define NOTIFY_EXPR_NODE_TO_EXPR(notify_expr_node_) \
+       (&TAC_MEMBER_STRUCT(struct expr, (notify_expr_node_), eval_scan.u.entity.notify_expr_node))
+
+typedef enum value_scan_func_result (*value_scan_func_t) TAC_ARGS((ENTITY *entity,void *func_data));
+extern void (*value_scan_forward_seen_hook) TAC_ARGS((struct membership *membership));
+
+
+extern int request_scan_user_known;    /* have we allowed to 'solve' S_user entities at all? */
+
+
+extern void unlink_expr TAC_ARGS((struct expr *expr));
+extern void free_expr TAC_ARGS((struct expr *expr));
+extern void scan_free_entity TAC_ARGS((ENTITY *entity));
+extern struct expr *new_expr TAC_ARGS((int type));
+extern enum value_scan_func_result value_scan_entity TAC_ARGS((ENTITY *entity, int recurse, value_scan_func_t func, void *func_data));
+extern struct membership *value_scan_backward TAC_ARGS((ENTITY *entity));
+extern enum eval_result expr_eval TAC_ARGS((struct expr *expr_single));
+extern struct expr *dupl_expr TAC_ARGS((const struct expr *in));
+extern void scan_init_entity TAC_ARGS((ENTITY *entity));
+extern struct membership *enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child, struct expr *when));
+extern struct membership *virtual_enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child));
+extern void scan_invalidate_entities_hashtable TAC_ARGS((void **hashtable, enum invalidate_scan what));
+extern void request_scan_begin TAC_ARGS((void));
+extern void eval_force_belong_entity TAC_ARGS((ENTITY *entity));
+extern void expr_sink_register TAC_ARGS((struct expr *expr));
+extern int expr_sink_commit TAC_ARGS((void));
+
+
+#endif /* CFGEVAL_H */
index 6eaef53..099dcd0 100644 (file)
--- a/cfgfile.c
+++ b/cfgfile.c
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
+
 #include <stdio.h>
+#include <stdlib.h>
 #include <errno.h>
-#include "regexp.h"
+#include <string.h>
+
+#ifndef WITH_INCLUDED_REGEX
+#ifdef HAVE_REGEX_H
+#include <regex.h>
+#endif
+#endif
+
+#include "cfgfile.h"
+#include "report.h"
+#include "utils.h"
+#include "hash.h"
+#include "parse.h"
+#include "main.h"
+#include "do_author.h"                 /* for "struct identity" */
+
+#ifdef WITH_INCLUDED_REGEX
+#include "tac_regexp.h"
+#endif
+
+
+static void sym_get TAC_ARGS((void));
+static void when_expr_root_init TAC_ARGS((void));
+static void rch TAC_ARGS((void));
+static int parse_entity TAC_ARGS((int entity_type));
+static NODE *parse_svcs TAC_ARGS((void));
+static int parse_conditional_block TAC_ARGS((ENTITY *entity));
+static NODE *parse_cmd_matches TAC_ARGS((void));
+static NODE *parse_attrs TAC_ARGS((void));
+static void getsym TAC_ARGS((void));
+static ENTITY *new_entity TAC_ARGS((int type, char *name, int line));
+static enum eval_result entity_svc_default TAC_ARGS((ENTITY *entity));
+
 
 /*
-   <config>         := <decl>*
+   <config>           := <decl>*
 
-   <decl>           := <top_level_decl> | <user_decl>
+   <decl>             := <top_level_decl> | <entity_decl>
 
-   <top_level_decl> := <authen_default> |
-                       accounting file = <string>
-                       default authorization = permit |
-                       key = <string>
+   <top_level_decl>   := <authen_default> |
+                         accounting file = <string> |
+                         default authorization = permit |
+                         key = <string> |
+                         authorization = ( first | recursive )
 
-   <authen_default> := default authentication = file <filename> 
+   <authen_default>   := default authentication = file <filename>
 #if defined(DB)
-                   | db <string> )
+                         | db <string>
 #endif
-   
-<permission>     := permit | deny
 
-   <filename>       := <string>
+   <permission>       := permit | deny
+
+   <filename>         := <string>
 
-   <password>       := <string>
+   <password>         := <string>
 
-   <user_decl>      := user = <string> {
-                        [ default service = [ permit | deny ] ]
-                        <user_attr>*
-                        <svc>*
-                   }
+   <user_decl>        := user  = <string> {
+                           [ <service_default> ]
+                           <user_attr>*
+                           <svc>*
+                         }
 
-   <password_spec>  := file <filename> | 
-                      skey | 
-                      cleartext <password> |
-                      des <password> |
+   <host_decl>        := host  = <string> {
+                           [ <service_default> ]
+                           <host_attr>*
+                           <svc>*
+                         }
 
-#ifdef USE_PAM         
-                      pam <pam_service> |
-#endif                 
-#if defined(DB)                
-                       db <string>
+   <group_decl>       := group = <string> {
+                           [ <service_default> ]
+                           <group_attr>*
+                           <svc>*
+                         }
+
+   <service_default>  := default service = ( permit | deny | default )
+
+   <password_spec>    := file <filename> |
+                         skey |
+                         cleartext <password> |
+                         des <password> |
+
+#ifdef USE_PAM
+                         pam <pam_service> |
 #endif
-                      nopassword
+#if defined(DB)
+                         db <string>
+#endif
+                         nopassword
 
-   <user_attr>      :=   name     = <string> |
+   <user_attr>       :=  name     = <string> |
                          login    = <password_spec> |
-                        member   = <string> |
-                        expires  = <string> |
-                        arap     = cleartext <string> |
-                        chap     = cleartext <string> |
+                         member   = <string> |
+                         expires  = <string> |
+                         arap     = cleartext <string> |
+                         chap     = cleartext <string> |
 #ifdef MSCHAP
-                        ms-chap  = cleartext <string> |
+                         ms-chap  = cleartext <string> |
+#endif
+                         pap      = cleartext <string> |
+                         pap      = des <string> |
+#ifdef USE_PAM
+                         pap      = pam <pam_service> |
 #endif
-                        pap      = cleartext <string> |
-                        pap      = des <string> |
-#ifdef USE_PAM 
-                        pap      = pam <pam_service> |
-#endif                 
-                        opap     = cleartext <string> |
-                        global   = cleartext <string> |
-                        msg      = <string>
-                        before authorization = <string> |
-                        after authorization = <string>
+                         opap     = cleartext <string> |
+                         global   = cleartext <string> |
+                         msg      = <string>
+                         before authorization = <string> |
+                         after  authorization = <string> |
+                         <when_attr>
+
+   <host_attr>       :=  key      = <string> |
+                         <user_attr>
+
+   <group_attr>      :=  enlist   = <entity_spec> |
+                         key      = <string> |
+                         <user_attr>
+
+   <when_attr>       := member   = <string> |
+                        enlist   = <entity_spec> |
+                        <svc> |
+                        <when_attr_block>
+
+   <when_attr_block> := <when_decl> {
+                          <when_attr>*
+                        }
 
-   <svc>            := <svc_auth> | <cmd_auth>
+   <svc>             := <svc_auth> | <cmd_auth>
 
-   <cmd_auth>       := cmd = <string> {
-                        <cmd-match>*
-                    }
+   <cmd_auth>        := cmd = <string> {
+                          <when_match>*
+                        }
 
-   <cmd-match>      := <permission> <string>
+   <when_match>      := <permission> <string> |
+                        <when_match_block>
 
-   <svc_auth>       := service = ( exec | arap | slip | ppp protocol = <string> {
-                        [ default attribute = permit ]
-                        <attr_value_pair>*
-                    }
+   <when_match_block> := <when_decl> {
+                           <when_match>*
+                         }
 
-   <attr_value_pair> := [ optional ] <string> = <string>
+   <svc_auth>        := service = ( exec | arap | slip | ppp protocol = <string> ) {
+# first matching <svc_auth> is the FINAL one, no further graph scanning occurs!
+                          [ default attribute = permit ]
+                          <when_AV_pair>*
+                        }
 
+   <when_AV_pair>    := [ optional ] <string> = <string> |
+                        <when_AV_pair_block>
+
+   <when_AV_pair_block> := <when_decl> {
+                             <when_AV_pair>*
+                           }
+
+   <when_decl>       := when = <expr>
+
+# to avoid ambiguous precence by forbid of "or" & "and" without parentheses:
+   <expr>            := <entity_spec> |
+                        not <expr> |
+                        '(' <expr_or>  ')' |
+                        '(' <expr_and> ')'
+
+   <expr_or>         := <expr> |
+                        <expr> or  <expr_or>
+
+   <expr_and>        := <expr> |
+                        <expr> and <expr_and>
+
+   <entity_spec>     := ( user | host | group ) <string>
 */
 
 static char sym_buf[MAX_INPUT_LINE_LEN];       /* parse buffer */
@@ -107,102 +200,54 @@ static int sym_line = 1; /* current line number for parsing */
 static FILE *cf = NULL;                /* config file pointer */
 static int sym_error = 0;      /* a parsing error has occurred */
 static int no_user_dflt = 0;   /* default if user doesn't exist */
+                               /* ='default authorization': 0/S_permit */
+static int algorithm_recursive = 0;    /* use newer authorization alogrithm? */
+                               /* 1 if 'authorization = recursive' */
 static char *authen_default = NULL;    /* top level authentication default */
-static int authen_default_method = 0; /*For method check */
+                                       /* ='default authentication' */
+static int authen_default_method = 0;  /* For method check */
+                                       /* ='default authentication' symbol */
 static char *nopasswd_str = "nopassword";
 
-/* A host definition structure. Currently unused, but when we start
-   configuring host-specific information e.g. per-host keys, this is
-   where it should be kept.
-
-   The first 2 fields (name and hash) are used by the hash table
-   routines to hash this structure into a table.  Do not (re)move them */
-
-struct host {
-    char *name;                        /* host name */
-    void *hash;                        /* hash table next pointer */
-    int line;                  /* line number defined on */
-    char *key;                 /* host spesific key */
-    char *type;                        /* host type         */
-};
-
-/* A user or group definition
-
-   The first 2 fields (name and hash) are used by the hash table
-   routines to hash this structure into a table.  Move them at your
-   peril */
-
-struct user {
-    char *name;                        /* username */
-    void *hash;                        /* hash table next pointer */
-    int line;                  /* line number defined on */
-    long flags;                        /* flags field */
-
-#define FLAG_ISUSER  1         /* this structure represents a user */
-#define FLAG_ISGROUP 2         /* this structure represents a group */
-#define FLAG_SEEN    4         /* for circular definition detection */
-
-    char *full_name;           /* users full name */
-    char *login;               /* Login password */
-    int nopasswd;               /* user requires no password */
-    char *global;              /* password to use if none set */
-    char *member;              /* group we are a member of */
-    char *expires;             /* expiration date */
-    char *arap;                        /* our arap secret */
-    char *pap;                 /* our pap secret */
-    char *opap;                        /* our outbound pap secret */
-    char *chap;                        /* our chap secret */
-#ifdef MSCHAP
-    char *mschap;              /* our mschap secret */
-#endif /* MSCHAP */
-    char *msg;                 /* a message for this user */
-    char *before_author;       /* command to run before authorization */
-    char *after_author;                /* command to run after authorization */
-    int svc_dflt;              /* default authorization behaviour for svc or
-                                * cmd */
-    NODE *svcs;                        /* pointer to svc nodes */
-#ifdef MAXSESS
-    int maxsess;               /* Max sessions/user */
-#endif /* MAXSESS */
-    char *time;                /* Timestamp  */
-};
-
-typedef struct host HOST;
-typedef struct user USER;
 
 /* Only the first 2 fields (name and hash) are used by the hash table
    routines to hashh structures into a table.
 */
 
-union hash {
-    struct user u;
-    struct host h;
-};
-
-typedef union hash HASH;
+static void *grouptable[HASH_TAB_SIZE];        /* Table of group declarations */
+static void *usertable[HASH_TAB_SIZE]; /* Table of user declarations */
+static void *hosttable[HASH_TAB_SIZE]; /* Table of host declarations */
 
-void *grouptable[HASH_TAB_SIZE];/* Table of group declarations */
-void *usertable[HASH_TAB_SIZE];        /* Table of user declarations */
-void *hosttable[HASH_TAB_SIZE];        /* Table of host declarations */
 
+struct enlist_entity_item {
+    struct enlist_entity_item *next;
+    int parent_type; char *parent;
+    int  child_type; char * child;     /* will be created when not found (for "enlist") */
+    struct expr *when;
+    int line;
+};
+static struct enlist_entity_item * enlist_entity_list;
+static struct enlist_entity_item **enlist_entity_list_tailp = &enlist_entity_list;
 
-static void
- sym_get();
 
+static void parse_error TAC_ARGS((char *fmt,...)) G_GNUC_PRINTF(1, 2);
 
 #ifdef __STDC__
+
 #include <stdarg.h>            /* ANSI C, variable length args */
 static void
 parse_error(char *fmt,...)
-#else
+
+#else /* __STDC__ */
+
 #include <varargs.h>           /* has 'vararg' definitions */
 /* VARARGS2 */
 static void
 parse_error(fmt, va_alist)
 char *fmt;
-
 va_dcl                         /* no terminating semi-colon */
-#endif
+
+#endif /* __STDC__ */
 {
     char msg[256];             /* temporary string */
     va_list ap;
@@ -220,7 +265,9 @@ va_dcl                              /* no terminating semi-colon */
     tac_exit(1);
 }
 
-char *
+const char *cfg_nodestring TAC_ARGS((int type));
+
+const char *
 cfg_nodestring(type)
     int type;
 {
@@ -250,6 +297,54 @@ cfg_nodestring(type)
     }
 }
 
+const char *entity_type_to_string TAC_ARGS((int entity_type));
+
+const char *
+entity_type_to_string(entity_type)
+int entity_type;
+{
+    switch (entity_type) {
+    case S_user:
+       return ("user");
+    case S_host:
+       return ("host");
+    case S_group:
+       return ("group");
+    }
+    return (NULL);
+}
+
+static void **entity_type_to_hashtable TAC_ARGS((int entity_type));
+
+static void **
+entity_type_to_hashtable(entity_type)
+int entity_type;
+{
+    switch (entity_type) {
+    case S_user:
+       return (usertable);
+    case S_host:
+       return (hosttable);
+    case S_group:
+       return (grouptable);
+    }
+    return (NULL);
+}
+
+void scan_invalidate_entities TAC_ARGS((enum invalidate_scan what));
+
+void
+scan_invalidate_entities(what)
+enum invalidate_scan what;
+{
+    scan_invalidate_entities_hashtable( usertable, what);
+    scan_invalidate_entities_hashtable( hosttable, what);
+    scan_invalidate_entities_hashtable(grouptable, what);
+}
+
+
+static void free_attrs TAC_ARGS((NODE *node));
+
 static void
 free_attrs(node)
 NODE *node;
@@ -257,16 +352,20 @@ NODE *node;
     NODE *next;
 
     while (node) {
+       unlink_expr(node->when);
+       free_expr(node->when);
+       node->when = NULL;
+
        switch (node->type) {
        case N_optarg:
        case N_arg:
            if (debug & DEBUG_CLEAN_FLAG)
                report(LOG_DEBUG, "free_cmd_match %s %s",
                       cfg_nodestring(node->type),
-                      node->value);
+                      (const char *) node->value);
            break;
        default:
-           report(LOG_ERR, "Illegal node type %s for free_attrs", 
+           report(LOG_ERR, "Illegal node type %s for free_attrs",
                   cfg_nodestring(node->type));
            return;
        }
@@ -278,6 +377,8 @@ NODE *node;
     }
 }
 
+static void free_cmd_matches TAC_ARGS((NODE *node));
+
 static void
 free_cmd_matches(node)
 NODE *node;
@@ -288,16 +389,32 @@ NODE *node;
        if (debug & DEBUG_CLEAN_FLAG)
            report(LOG_DEBUG, "free_cmd_match %s %s",
                   cfg_nodestring(node->type),
-                  node->value);
+                  (const char *) node->value);
+
+       unlink_expr(node->when);
+       free_expr(node->when);
+       node->when = NULL;
 
        free(node->value);      /* text */
-       free(node->value1);     /* regexp compiled text */
+
+#ifdef WITH_INCLUDED_REGEX
+
+       free(node->value1);     /* tac_regexp compiled text */
+
+#else /* WITH_INCLUDED_REGEX */
+
+       regfree((regex_t *) node->value1);      /* POSIX regex compiled text */
+
+#endif /* WITH_INCLUDED_REGEX */
+
        next = node->next;
        free(node);
        node = next;
     }
 }
 
+static void free_svcs TAC_ARGS((NODE *node));
+
 static void
 free_svcs(node)
 NODE *node;
@@ -305,12 +422,16 @@ NODE *node;
     NODE *next;
 
     while (node) {
+       unlink_expr(node->when);
+       free_expr(node->when);
+       node->when = NULL;
 
        switch (node->type) {
        case N_svc_cmd:
            if (debug & DEBUG_CLEAN_FLAG)
                report(LOG_DEBUG, "free %s %s",
-                      cfg_nodestring(node->type), node->value);
+                      cfg_nodestring(node->type),
+                      (const char *) node->value);
            free(node->value);  /* cmd name */
            free_cmd_matches(node->value1);
            next = node->next;
@@ -340,86 +461,108 @@ NODE *node;
     }
 }
 
+static void free_enlist_entity_item TAC_ARGS((struct enlist_entity_item *item));
+
+static void
+free_enlist_entity_item(item)
+struct enlist_entity_item *item;
+{
+    free(item->parent);
+    free(item->child);
+    free_expr(item->when);
+}
+
+
+static void free_entity TAC_ARGS((ENTITY *entity));
+
 static void
-free_userstruct(user)
-USER *user;
+free_entity(entity)
+ENTITY *entity;
 {
     if (debug & DEBUG_CLEAN_FLAG)
        report(LOG_DEBUG, "free %s %s",
-              (user->flags & FLAG_ISUSER) ? "user" : "group",
-              user->name);
-
-    if (user->name)
-       free(user->name);
-    if (user->full_name)
-       free(user->full_name);
-    if (user->login)
-       free(user->login);
-    if (user->member)
-       free(user->member);
-    if (user->expires)
-       free(user->expires);
-    if (user->time)
-       free(user->time);
-    if (user->arap)
-       free(user->arap);
-    if (user->chap)
-       free(user->chap);
+               entity_type_to_string(entity->type), entity->name);
+
+    /* function MUST be called while the whole entity is still VALID! */
+    scan_free_entity(entity);
+
+    if (entity->name)
+       free(entity->name);
+    if (entity->full_name)
+       free(entity->full_name);
+    if (entity->login)
+       free(entity->login);
+    if (entity->expires)
+       free(entity->expires);
+    if (entity->time)
+       free(entity->time);
+    if (entity->arap)
+       free(entity->arap);
+    if (entity->chap)
+       free(entity->chap);
 #ifdef MSCHAP
-    if (user->mschap)
-       free(user->mschap);
+    if (entity->mschap)
+       free(entity->mschap);
 #endif /* MSCHAP */
-    if (user->pap)
-       free(user->pap);
-    if (user->opap)
-       free(user->opap);
-    if (user->global)
-       free(user->global);
-    if (user->msg)
-       free(user->msg);
-    if (user->before_author)
-       free(user->before_author);
-    if (user->after_author)
-       free(user->after_author);
-    free_svcs(user->svcs);
+    if (entity->pap)
+       free(entity->pap);
+    if (entity->opap)
+       free(entity->opap);
+    if (entity->global)
+       free(entity->global);
+    if (entity->msg)
+       free(entity->msg);
+    if (entity->before_author)
+       free(entity->before_author);
+    if (entity->after_author)
+       free(entity->after_author);
+    if (entity->key)
+       free(entity->key);
+    free_svcs(entity->svcs);
 }
 
+static void free_hashtable TAC_ARGS((void **hashtable));
+
 static void
-free_hoststruct(host)
-HOST *host;
+free_hashtable(hashtable)
+void **hashtable;
 {
-    if (debug & DEBUG_CLEAN_FLAG)
-       report(LOG_DEBUG, "free %s",
-               host->name);
+    int i;
+    ENTITY *entity,**entityp;
 
-    if (host->name)
-       free(host->name);
-    
-    if (host->key)
-       free(host->key);
-    
-    if (host->type)
-       free(host->type);
+    for (i = 0; i < HASH_TAB_SIZE; i++) {
+       entityp = (ENTITY **) (hashtable+i);
+       while ((entity = *entityp)) {
+           *entityp = entity->hash;
+           free_entity(entity);
+           free(entity);
+       }
+    }
 }
 
+
 /*
  * Exported routines
  */
 
+void cfg_clean_config TAC_ARGS((void));
+
 /* Free all allocated structures preparatory to re-reading the config file */
 void
 cfg_clean_config()
 {
-    int i;
-    USER *entry, *next;
-    HOST *host_entry,*hn;
+    struct enlist_entity_item *enlist_entity_item;
 
     if (authen_default) {
        free(authen_default);
        authen_default = NULL;
     }
-   
-   if (authen_default_method) {
+
+    if (algorithm_recursive) {
+       algorithm_recursive = 0;
+    }
+
+    if (authen_default_method) {
        authen_default_method = 0;
     }
 
@@ -432,49 +575,27 @@ cfg_clean_config()
        free(session.acctfile);
        session.acctfile = NULL;
     }
-    
+
     if (session.db_acct) {
        free(session.db_acct);
        session.db_acct = NULL;
     }
 
-    /* clean the hosttable */
-    for (i = 0; i < HASH_TAB_SIZE; i++) {
-       host_entry = (HOST *) hosttable[i];
-       while (host_entry) {
-           hn = host_entry->hash;
-           free_hoststruct(host_entry);
-           free(host_entry);
-           host_entry = hn;
-       }
-       hosttable[i] = NULL;
-    }
-
-    /* the grouptable */
-    for (i = 0; i < HASH_TAB_SIZE; i++) {
-       entry = (USER *) grouptable[i];
-       while (entry) {
-           next = entry->hash;
-           free_userstruct(entry);
-           free(entry);
-           entry = next;
-       }
-       grouptable[i] = NULL;
-    }
+    free_hashtable( usertable);
+    free_hashtable( hosttable);
+    free_hashtable(grouptable);
 
-    /* the usertable */
-    for (i = 0; i < HASH_TAB_SIZE; i++) {
-       entry = (USER *) usertable[i];
-       while (entry) {
-           next = entry->hash;
-           free_userstruct(entry);
-           free(entry);
-           entry = next;
-       }
-       usertable[i] = NULL;
+    while (enlist_entity_list) {
+       enlist_entity_item = enlist_entity_list;
+       enlist_entity_list = enlist_entity_item->next;
+       free_enlist_entity_item(enlist_entity_item);
+       free(enlist_entity_item);
     }
+    enlist_entity_list_tailp = &enlist_entity_list;
 }
 
+static int parse_permission TAC_ARGS((void));
+
 static int
 parse_permission()
 {
@@ -490,6 +611,8 @@ parse_permission()
     return (symbol);
 }
 
+static int parse TAC_ARGS((int symbol));
+
 static int
 parse(symbol)
 int symbol;
@@ -505,9 +628,13 @@ int symbol;
     return (0);
 }
 
+static int parse_opt_svc_default TAC_ARGS((void));
+
 static int
 parse_opt_svc_default()
 {
+    int retval;
+
     if (sym_code != S_default) {
        return (0);
     }
@@ -515,14 +642,30 @@ parse_opt_svc_default()
     parse(S_default);
     parse(S_svc);
     parse(S_separator);
-    if (sym_code == S_permit) {
-       parse(S_permit);
-       return (S_permit);
+
+    switch (sym_code) {
+    default:
+       parse_error("expecting 'permit', 'deny' or 'default' but found '%s' on line %d",
+                   sym_buf, sym_line);
+       return (1);
+
+    case S_default:
+       if (!algorithm_recursive) {
+           parse_error("'default service = %s' supported only if set top level 'authorization = recursive', on line %d",
+                       sym_buf, sym_line);
+           return (1);
+       }
+       /* FALLTHRU */
+    case S_permit:
+    case S_deny:
+       retval = sym_code;
+       sym_get();
+       return (retval);
     }
-    parse(S_deny);
-    return (S_deny);
 }
 
+static int parse_opt_attr_default TAC_ARGS((void));
+
 static int
 parse_opt_attr_default()
 {
@@ -536,27 +679,26 @@ parse_opt_attr_default()
     return (S_permit);
 }
 
-static int parse_user();
-static int parse_host();
-
-static void
- rch();
-
 /*
    Parse lines in the config file, creating data structures
    Return 1 on error, otherwise 0 */
 
+static int parse_decls TAC_ARGS((void));
+
 static int
 parse_decls()
 {
-    no_user_dflt = 0; /* default if user doesn't exist */
+    no_user_dflt = 0;          /* default if user doesn't exist */
+    algorithm_recursive = 0;   /* use backward compatible alg. by default */
+    when_expr_root_init();
+    enlist_entity_list_tailp = &enlist_entity_list;
 
     sym_code = 0;
     rch();
 
     bzero(grouptable, sizeof(grouptable));
     bzero(usertable, sizeof(usertable));
-    bzero(hosttable, sizeof(hosttable)); 
+    bzero(hosttable, sizeof(hosttable));
 
     sym_get();
 
@@ -571,17 +713,17 @@ parse_decls()
            sym_get();
            parse(S_file);
            parse(S_separator);
-           if (session.acctfile) 
+           if (session.acctfile)
                free(session.acctfile);
            session.acctfile = tac_strdup(sym_buf);
            sym_get();
            continue;
 
-#ifdef DB      
+#ifdef DB
        case S_db_accounting:
            sym_get();
            parse(S_separator);
-           if (session.db_acct) 
+           if (session.db_acct)
                free(session.db_acct);
            session.db_acct = tac_strdup(sym_buf);
            sym_get();
@@ -608,13 +750,13 @@ parse_decls()
                parse(S_separator);
 
                switch(sym_code) {
-                
+
                case S_file:
 #ifdef DB
                case S_db:
 #endif
 #ifdef USE_LDAP
-               case S_ldap;
+               case S_ldap:
 #endif
 #ifdef USE_PAM
                case S_pam:
@@ -637,11 +779,31 @@ parse_decls()
                parse(S_separator);
                parse(S_permit);
                no_user_dflt = S_permit;
-               report(LOG_INFO, 
+               report(LOG_INFO,
                       "default authorization = permit is now deprecated. Please use user = DEFAULT instead");
                continue;
            }
 
+       case S_authorization:
+           sym_get();
+           parse(S_separator);
+           switch (sym_code) {
+           default:
+               parse_error("expecting 'first' or 'recursive' but found '%s' on line %d",
+                           sym_buf, sym_line);
+               return (1);
+
+           case S_first:
+               parse(S_first);
+               algorithm_recursive = 0;
+               continue;
+
+           case S_recursive:
+               parse(S_recursive);
+               algorithm_recursive = 1;
+               continue;
+           }
+
        case S_key:
            /* Process a key declaration. */
            sym_get();
@@ -655,18 +817,13 @@ parse_decls()
            session.keyline = sym_line;
            sym_get();
            continue;
-       
-       case S_host:
-           parse_host();
-           continue;
-       
+
        case S_user:
+       case S_host:
        case S_group:
-           parse_user();
+           parse_entity(sym_code);
            continue;
 
-           /* case S_host: parse_host(); continue; */
-
        default:
            parse_error("Unrecognised token %s on line %d", sym_buf, sym_line);
            return (1);
@@ -674,8 +831,6 @@ parse_decls()
     }
 }
 
-static NODE *parse_svcs();
-
 /* Assign a value to a field. Issue an error message and return 1 if
    it's already been assigned. This is a macro because I was sick of
    repeating the same code fragment over and over */
@@ -688,199 +843,513 @@ sym_get(); parse(S_separator); if (field) { \
     } \
     field = tac_strdup(sym_buf);
 
-static int
-parse_host()
+static struct expr *when_expr_root;
+
+static void when_expr_root_init TAC_ARGS((void));
+
+static void
+when_expr_root_init()
 {
-    HOST *h;
-    HOST *host = (HOST *) tac_malloc(sizeof(HOST));
-    int save_sym;
-    char buf[MAX_INPUT_LINE_LEN];
+    free_expr(when_expr_root);
+    when_expr_root = new_expr(S_and);
+}
 
-    bzero(host, sizeof(HOST));
+static struct expr *parse_expr_node TAC_ARGS((int single_item));
 
-    sym_get();
-    parse(S_separator);
-    host->name = tac_strdup(sym_buf);
-    host->line = sym_line;
-    
-    h = hash_add_entry(hosttable, (void *) host);
-    
-    if (h) {
-        parse_error("multiply defined %s on lines %d and %d",
-                    host->name, h->line, sym_line);
-        return (1);
-    }
+static struct expr *
+parse_expr_node(single_item)
+int single_item;
+{
+    struct expr *expr_root = NULL;
+    struct expr **succ_exprp = &expr_root;
+    struct expr *expr;
 
-    sym_get();
-    parse(S_openbra);
-    
     while (1) {
        switch (sym_code) {
-        case S_eof:
-            return (0);
-       case S_key:
-           ASSIGN(host->key);
-            sym_get();
-            continue;
-       case S_type:
-           ASSIGN(host->type);
-            sym_get();
-            continue;
-       
-       case S_closebra:
-            parse(S_closebra);
-            return (0);
+
+       case S_not:
+           expr = (struct expr *) tac_malloc(sizeof(struct expr));
+           expr->line = sym_line;
+           *succ_exprp = expr;
+           expr->next = NULL;
+           succ_exprp = &expr->next;
+           expr->type = S_not;
+           sym_get();
+           expr->u.not.child = parse_expr_node(1 /* single_item */);
+           if (!expr->u.not.child) {
+               free_expr(expr_root);
+               return (NULL);
+           }
+           break;
+
+       case S_user:
+       case S_host:
+       case S_group:
+           expr = (struct expr *) tac_malloc(sizeof(struct expr));
+           expr->line = sym_line;
+           *succ_exprp = expr;
+           expr->next = NULL;
+           succ_exprp = &expr->next;
+           expr->type = sym_code;
+           sym_get();
+           expr->u.entity.name = tac_strdup(sym_buf);
+           sym_get();
+           expr->u.entity.entity = NULL;       /* not known yet */
+           break;
+
+       case S_openparen:
+           sym_get();
+           expr = parse_expr_node(0 /* single_item */);
+           *succ_exprp = expr;
+           parse(S_closeparen);
+
+           if (expr->next) {
+               report(LOG_ERR, "Illegal filled next field of parsed parenthesed expr");
+               free_expr(expr_root);
+               return (NULL);
+           }
+           succ_exprp = &expr->next;
+           break;
 
        default:
-           parse_error("Unrecognised keyword %s for host %s on line %d",
-                        sym_buf, host->name,sym_line);
+           parse_error("expecting 'not', 'user', 'host', 'group' or '(' but found '%s' on line %d",
+                   sym_buf, sym_line);
+           free_expr(expr_root);
+           return (NULL);
+       }
 
-            return (0);
-        }
-    } /* while */
-} /* finish parse_host */
+       if (single_item)                /* used by 'not' operator with high precedence */
+           return (expr_root);
 
+        switch (sym_code) {
 
-static int
-parse_user()
-{
-    USER *n;
-    int isuser;
-    USER *user = (USER *) tac_malloc(sizeof(USER));
-    int save_sym;
-    char **fieldp;
-    char buf[MAX_INPUT_LINE_LEN];
+       case S_and:
+       case S_or:
+           if (expr_root->type == (sym_code==S_and ? S_or : S_and)) {
+               parse_error("ambiguous use of 'and' together with 'or', parentheses required on line %d",
+                       sym_line);
+               free_expr(expr_root);
+               return (NULL);
+           }
+           if (expr_root->type != sym_code) {
+               expr = (struct expr *) tac_malloc(sizeof(struct expr));
+               expr->line = sym_line;
+               expr->next = NULL;
+               expr->type = sym_code;
+               expr->u.and_or.child_first = expr_root;
+               expr_root = expr;
+           }
+           sym_get();
+           continue;
+       }
 
-    bzero(user, sizeof(USER));
+       return(expr_root);
+    }
+}
 
-    isuser = (sym_code == S_user);
+static struct expr *parse_when_decl TAC_ARGS((void));
 
-    sym_get();
+static struct expr *
+parse_when_decl()
+{
+    parse(S_when);
+    if (!algorithm_recursive) {
+       parse_error("'when' conditionals supported only if set top level 'authorization = recursive', on line %d",
+                   sym_line);
+       return (NULL);
+    }
     parse(S_separator);
-    user->name = tac_strdup(sym_buf);
-    user->line = sym_line;
-
-    if (isuser) {
-       user->flags |= FLAG_ISUSER;
-       n = hash_add_entry(usertable, (void *) user);
-    } else {
-       user->flags |= FLAG_ISGROUP;
-       n = hash_add_entry(grouptable, (void *) user);
+    return (parse_expr_node(0 /* single_item */));
+}
+
+static int push_parsed_when_decl TAC_ARGS((void));
+
+static int
+push_parsed_when_decl()
+{
+    struct expr *new_expr;
+
+    new_expr = parse_when_decl();
+    if (!new_expr)
+       return (1);
+    if (new_expr->next) {
+       report(LOG_ERR, "Illegal filled next field of parsed expr");
+       free_expr(new_expr);
+       return (1);
     }
+    new_expr->next = when_expr_root->u.and_or.child_first;
+    when_expr_root->u.and_or.child_first = new_expr;
+    when_expr_root->line = new_expr->line;
+    return (0);
+}
 
-    if (n) {
-       parse_error("multiply defined %s %s on lines %d and %d",
-                   isuser ? "user" : "group",
-                   user->name, n->line, sym_line);
+static int pop_when_decl TAC_ARGS((void));
+
+static int
+pop_when_decl()
+{
+    struct expr *first_expr;
+
+    first_expr = when_expr_root->u.and_or.child_first;
+    if (!first_expr) {
+       report(LOG_ERR, "No expr in stack and pop_when_decl() called");
        return (1);
     }
-    sym_get();
-    parse(S_openbra);
+    when_expr_root->u.and_or.child_first = first_expr->next;
+    free_expr(first_expr);
+    return (0);
+}
 
-    /* Is the default deny for svcs or cmds to be overridden? */
-    user->svc_dflt = parse_opt_svc_default();
+static struct expr *copy_current_when_decl TAC_ARGS((void));
 
-    while (1) {
-       switch (sym_code) {
-       case S_eof:
-           return (0);
-       
-       case S_time:
-          ASSIGN(user->time);
-          sym_get(); 
-          continue;
+static struct expr *
+copy_current_when_decl()
+{
+    return (dupl_expr(when_expr_root));
+}
 
-       case S_before:
-           sym_get();
-           parse(S_authorization);
-           if (user->before_author)
-               free(user->before_author);
-           user->before_author = tac_strdup(sym_buf);
-           sym_get();
-           continue;
+ENTITY *entity_lookup TAC_ARGS((int type, const char *name));
 
-       case S_after:
-           sym_get();
-           parse(S_authorization);
-           if (user->after_author)
-               free(user->after_author);
-           user->after_author = tac_strdup(sym_buf);
-           sym_get();
-           continue;
+ENTITY *
+entity_lookup(type, name)
+int type;
+const char *name;
+{
+    return (hash_lookup(entity_type_to_hashtable(type), name));
+}
 
-       case S_svc:
-       case S_cmd:
-           
-           if (user->svcs) {   
-               /* 
-                * Already parsed some services/commands. Thanks to Gabor Kiss
-                * who found this bug.
-                */
-               NODE *p;
-               for (p=user->svcs; p->next; p=p->next) 
-                   /* NULL STMT */;
-               p->next = parse_svcs();
-           } else {
-               user->svcs = parse_svcs();
-           }
-           continue;
+static int enlist_entity_connect TAC_ARGS((void));
 
-       case S_login:
-           if (user->login) {
-               parse_error("Duplicate value for %s %s and %s on line %d",
-                           codestring(sym_code), user->login,
-                           sym_buf, sym_line);
-               tac_exit(1);
-           }
-           sym_get();
-           parse(S_separator);
-           switch(sym_code) {
+static int
+enlist_entity_connect()
+{
+    struct enlist_entity_item *item;
+    ENTITY *parent_entity, *child_entity;
 
-           case S_skey:
-               user->login = tac_strdup(sym_buf);
-               break;
+    while ((item=enlist_entity_list)) {
 
-           case S_nopasswd:
+       parent_entity = entity_lookup(item->parent_type, item->parent);
+       if (!parent_entity) {
+           parse_error("Entity %s %s not defined, referenced as parent on line %d",
+                   entity_type_to_string(item->parent_type), item->parent, item->line);
+           return (1);
+       }
+       child_entity = entity_lookup(item-> child_type, item-> child);
+       if (!child_entity) {
+           child_entity = new_entity(item->child_type, item->child, item->line);
+           if (!child_entity)
+               return (1);             /* 'hash_add_entry()' conflict */
+           item->child = NULL;         /* don't free string ref'ed from 'child_entity'! */
+       }
+
+       enlist_entity_direct(parent_entity, child_entity, item->when);
+
+       enlist_entity_list = item->next;
+       item->when = NULL;
+       free_enlist_entity_item(item);
+       free(item);
+    }
+    enlist_entity_list_tailp = &enlist_entity_list;
+    return (0);
+}
+
+static void enlist_entity TAC_ARGS((int parent_type, const char *parent, int child_type, const char *child));
+
+static void
+enlist_entity(parent_type, parent, child_type, child)
+int parent_type;
+const char *parent;
+int child_type;
+const char *child;
+{
+    struct enlist_entity_item *item =
+               (struct enlist_entity_item *) tac_malloc(sizeof(struct enlist_entity_item));
+
+    item->next = NULL;
+    *enlist_entity_list_tailp = item;
+    enlist_entity_list_tailp = &item->next;
+
+    item->parent_type = parent_type;
+    item->parent = tac_strdup(parent);
+    item-> child_type =  child_type;
+    item->child = tac_strdup(child);
+    item->when = copy_current_when_decl();
+    item->line = sym_line;
+}
+
+static int parse_entity_spec TAC_ARGS((void));
+
+/* returns 0 for error, otherwise S_user, S_host or S_group; sym_buf filled */
+static int
+parse_entity_spec()
+{
+    int retval;
+
+    if (sym_code != S_user
+     && sym_code != S_host
+     && sym_code != S_group
+       ) {
+       parse_error("Expecting 'user', 'host' or ' group' as entity specification, found %s on line %d",
+                   sym_buf, sym_line);
+       return (0);
+    }
+
+    retval = sym_code;
+    sym_get();
+
+    return (retval);
+}
+
+static int parse_conditional_block_item TAC_ARGS((ENTITY *entity));
+
+static int
+parse_conditional_block_item(entity)
+ENTITY *entity;
+{
+    switch (sym_code) {
+    case S_eof:
+       return (1);
+
+    /* case S_closebra: not needed, handled by our caller parse_conditional_block() */
+
+    default:
+       parse_error("Unrecognised keyword %s for entity on line %d",
+                   sym_buf, sym_line);
+       return (1);
+
+    case S_member:
+       sym_get();
+       parse(S_separator);
+       enlist_entity(S_group, sym_buf, entity->type, entity->name);
+       sym_get();
+       break;
+
+    case S_enlist: {
+       int parsed_entity_type;
+
+       if (entity->type != S_group) {
+           parse_error("'enlist' keyword allowed only in 'group' section on line %d",
+                       sym_line);
+           return (1);
+       }
+       sym_get();
+       parse(S_separator);
+       parsed_entity_type = parse_entity_spec();
+       if (!parsed_entity_type)
+           return (1);
+       enlist_entity(entity->type, entity->name, parsed_entity_type, sym_buf);
+       sym_get();
+       break;
+       }
+
+    case S_svc:
+    case S_cmd:
+
+       if (entity->svcs) {
+           /*
+            * Already parsed some services/commands. Thanks to Gabor Kiss
+            * who found this bug.
+            */
+           NODE *p;
+           for (p=entity->svcs; p->next; p=p->next)
+               /* NULL STMT */;
+           p->next = parse_svcs();
+       } else {
+           entity->svcs = parse_svcs();
+       }
+       break;
+
+    case S_when:
+       if (parse_conditional_block(entity))
+           return (1);
+       break;
+    }
+
+    return (0);
+}
+
+static int parse_conditional_block TAC_ARGS((ENTITY *entity));
+
+static int
+parse_conditional_block(entity)
+ENTITY *entity;
+{
+    int retval = -1 /* GCC paranoia */;
+
+    if (push_parsed_when_decl())
+       return (1);
+    parse(S_openbra);
+
+    while (1) {
+       if (sym_code == S_closebra) {
+           sym_get();
+           retval = 0;         /* success */
+           break;
+       }
+
+       if (parse_conditional_block_item(entity)) {
+           retval = 1;         /* failure */
+           break;
+       }
+    }
+
+    if (pop_when_decl())
+       return (1);
+
+    return (retval);
+}
+
+/* passed 'name' WILL be directly stored to returned ENTITY, don't touch it! */
+
+static ENTITY *new_entity TAC_ARGS((int type, char *name, int line));
+
+static ENTITY *
+new_entity(type, name, line)
+int type;
+char *name;
+int line;
+{
+    ENTITY *entity = (ENTITY *) tac_malloc(sizeof(ENTITY));
+    ENTITY *hash_conflict;
+
+    bzero(entity, sizeof(ENTITY));
+    tac_list_init(&entity->to_parent_membership_list);
+    tac_list_init(&entity->to_child_membership_list );
+    entity->to_child_membership_num = 0;
+    scan_init_entity(entity);
+
+    entity->type = type;
+    entity->name = name;
+    entity->line = line;
+
+    hash_conflict = hash_add_entry(entity_type_to_hashtable(type), (void *) entity);
+    if (hash_conflict) {
+       parse_error("multiply defined %s %s on lines %d and %d",
+                   entity_type_to_string(type),
+                   entity->name, hash_conflict->line, sym_line);
+       free (entity);
+       return (NULL);
+    }
+
+    return (entity);
+}
+
+static int parse_entity TAC_ARGS((int entity_type));
+
+static int
+parse_entity(entity_type)
+int entity_type;
+{
+    ENTITY *entity;
+    int save_sym;
+    char **fieldp = NULL /* GCC paranoia */;
+    char buf[MAX_INPUT_LINE_LEN];
+
+    sym_get();
+    parse(S_separator);
+
+    entity = new_entity(entity_type, tac_strdup(sym_buf) /* name */, sym_line /* line */);
+    if (!entity)
+       return (1);             /* 'hash_add_entry()' conflict, 'tac_strdup(sym_buf)' leaked! */
+
+    sym_get();
+    parse(S_openbra);
+
+    /* Is the default deny for svcs or cmds to be overridden? */
+    entity->svc_dflt = parse_opt_svc_default();
+
+    while (1) {
+       if (entity_type != S_user)
+           switch (sym_code) {
+           case S_key:
+               ASSIGN(entity->key);
+               sym_get();
+               continue;
+           }
+
+       switch (sym_code) {
+       case S_eof:
+           return (0);
+
+       case S_time:
+          ASSIGN(entity->time);
+          sym_get();
+          continue;
+
+       case S_before:
+           sym_get();
+           parse(S_authorization);
+           if (entity->before_author)
+               free(entity->before_author);
+           entity->before_author = tac_strdup(sym_buf);
+           sym_get();
+           continue;
+
+       case S_after:
+           sym_get();
+           parse(S_authorization);
+           if (entity->after_author)
+               free(entity->after_author);
+           entity->after_author = tac_strdup(sym_buf);
+           sym_get();
+           continue;
+
+       case S_login:
+           if (entity->login) {
+               parse_error("Duplicate value for %s %s and %s on line %d",
+                           codestring(sym_code), entity->login,
+                           sym_buf, sym_line);
+               tac_exit(1);
+           }
+           sym_get();
+           parse(S_separator);
+           switch(sym_code) {
+
+           case S_skey:
+               entity->login = tac_strdup(sym_buf);
+               break;
+
+           case S_nopasswd:
                /* set to dummy string, so that we detect a duplicate
                 * password definition attempt
                 */
-               user->login = tac_strdup(nopasswd_str);
-               user->nopasswd = 1;
+               entity->login = tac_strdup(nopasswd_str);
+               entity->nopasswd = 1;
                break;
-               
+
            case S_file:
            case S_cleartext:
            case S_des:
-#ifdef USE_PAM 
-           case S_pam: 
-#endif /* USE_PAM */           
+#ifdef USE_PAM
+           case S_pam:
+#endif /* USE_PAM */
 #ifdef DB
            case S_db:
 #endif /* USE DB */
                sprintf(buf, "%s ", sym_buf);
                sym_get();
                strcat(buf, sym_buf);
-               user->login = tac_strdup(buf);
+               entity->login = tac_strdup(buf);
                break;
-       
+
            default:
 #ifdef USE_PAM
                parse_error(
  "expecting 'file', 'cleartext', 'pam'.'nopassword', 'skey', or 'des' keyword after 'login =' on line %d",
                            sym_line);
-#else  
+#else
                parse_error(
- "expecting 'file', 'cleartext', 'nopassword', 'skey', or 'des' keyword after 'login =' on line %d", 
+ "expecting 'file', 'cleartext', 'nopassword', 'skey', or 'des' keyword after 'login =' on line %d",
                            sym_line);
-#endif /* USE_PAM */                   
+#endif /* USE_PAM */
            }
            sym_get();
            continue;
 
        case S_pap:
-           if (user->pap) {
+           if (entity->pap) {
                parse_error("Duplicate value for %s %s and %s on line %d",
-                           codestring(sym_code), user->pap,
+                           codestring(sym_code), entity->pap,
                            sym_buf, sym_line);
                tac_exit(1);
            }
@@ -890,17 +1359,17 @@ parse_user()
 
            case S_cleartext:
            case S_des:
-#ifdef USE_PAM 
+#ifdef USE_PAM
            case S_pam:
-#endif /*USE_PAM */                    
+#endif /*USE_PAM */
                sprintf(buf, "%s ", sym_buf);
                sym_get();
                strcat(buf, sym_buf);
-               user->pap = tac_strdup(buf);
-               break;  
+               entity->pap = tac_strdup(buf);
+               break;
 
                sprintf(buf, "%s ", sym_buf);
-               user->pap = tac_strdup(buf);
+               entity->pap = tac_strdup(buf);
                break;
 
            default:
@@ -910,7 +1379,7 @@ parse_user()
  sym_line);
 #else
                parse_error(
- "expecting 'cleartext', or 'des' keyword after 'pap =' on line %d", 
+ "expecting 'cleartext', or 'des' keyword after 'pap =' on line %d",
  sym_line);
 #endif /*USE_PAM */
            }
@@ -918,23 +1387,17 @@ parse_user()
            continue;
 
        case S_name:
-           ASSIGN(user->full_name);
+           ASSIGN(entity->full_name);
            sym_get();
            continue;
 
-       case S_member:
-           ASSIGN(user->member);
-           sym_get();
-           continue;
-       
-
        case S_expires:
-           ASSIGN(user->expires);
+           ASSIGN(entity->expires);
            sym_get();
            continue;
-       
+
        case S_message:
-           ASSIGN(user->msg);
+           ASSIGN(entity->msg);
            sym_get();
            continue;
 
@@ -946,26 +1409,38 @@ parse_user()
        case S_opap:
        case S_global:
            save_sym = sym_code;
-           sym_get(); 
-           parse(S_separator); 
+           sym_get();
+           parse(S_separator);
            sprintf(buf, "%s ", sym_buf);
            parse(S_cleartext);
            strcat(buf, sym_buf);
 
-           if (save_sym == S_arap)
-               fieldp = &user->arap;
-           if (save_sym == S_chap)
-               fieldp = &user->chap;
+           switch (save_sym) {
+           case S_arap:
+               fieldp = &entity->arap;
+               break;
+           case S_chap:
+               fieldp = &entity->chap;
+               break;
 #ifdef MSCHAP
-           if (save_sym == S_mschap)
-               fieldp = &user->mschap;
+           case S_mschap:
+               fieldp = &entity->mschap;
+               break;
 #endif /* MSCHAP */
-           if (save_sym == S_pap)
-               fieldp = &user->pap;
-           if (save_sym == S_opap)
-               fieldp = &user->opap;
-           if (save_sym == S_global)
-               fieldp = &user->global;
+           case S_pap:
+               fieldp = &entity->pap;
+               break;
+           case S_opap:
+               fieldp = &entity->opap;
+               break;
+           case S_global:
+               fieldp = &entity->global;
+               break;
+           default:
+               report(LOG_ERR, "INTERNAL: fieldp not recognized (on line %d)",
+                       sym_line);
+               continue;
+           }
 
            if (*fieldp) {
                parse_error("Duplicate value for %s %s and %s on line %d",
@@ -982,31 +1457,29 @@ parse_user()
 
 #ifdef MAXSESS
        case S_maxsess:
-           sym_get(); 
+           sym_get();
            parse(S_separator);
-           if (sscanf(sym_buf, "%d", &user->maxsess) != 1) {
+           if (sscanf(sym_buf, "%d", &entity->maxsess) != 1) {
                parse_error("expecting integer, found '%s' on line %d",
                    sym_buf, sym_line);
            }
            sym_get();
            continue;
 #endif /* MAXSESS */
+
        default:
            if (STREQ(sym_buf, "password")) {
                fprintf(stderr,
                        "\npassword = <string> is obsolete. Use login = des <string>\n");
            }
-           parse_error("Unrecognised keyword %s for user on line %d",
-                       sym_buf, sym_line);
 
-           return (0);
+           if (parse_conditional_block_item(entity))
+               return (0);             /* error message already printed */
        }
     }
 }
 
-static NODE *parse_attrs();
-static NODE *parse_cmd_matches();
+static NODE *parse_svcs TAC_ARGS((void));
 
 static NODE *
 parse_svcs()
@@ -1037,8 +1510,11 @@ parse_svcs()
 
        result->value1 = parse_cmd_matches();
        result->type = N_svc_cmd;
+       result->when = copy_current_when_decl();
+       expr_sink_register(result->when);
 
        parse(S_closebra);
+
        result->next = parse_svcs();
        return (result);
     }
@@ -1077,80 +1553,151 @@ parse_svcs()
     }
     sym_get();
     parse(S_openbra);
+
     result->dflt = parse_opt_attr_default();
     result->value = parse_attrs();
+    result->when = copy_current_when_decl();
+    expr_sink_register(result->when);
+
     parse(S_closebra);
+
     result->next = parse_svcs();
     return (result);
 }
 
-/*  <cmd-match>         := <permission> <string> */
+/*  <cmd_match>         := <permission> <string> */
+
+static NODE *parse_cmd_matches TAC_ARGS((void));
 
 static NODE *
 parse_cmd_matches()
 {
+    NODE *retval = NULL, **succp = &retval;
     NODE *result;
 
-    if (sym_code != S_permit && sym_code != S_deny) {
-       return (NULL);
-    }
-    result = (NODE *) tac_malloc(sizeof(NODE));
+    for (;;) {
+       switch (sym_code) {
+       default:
+           return (retval);
 
-    bzero(result, sizeof(NODE));
-    result->line = sym_line;
+       case S_when:
+           if (push_parsed_when_decl())
+               tac_exit(1);            /* no error return possibility */
+           parse(S_openbra);
+           result = parse_cmd_matches();
+           parse(S_closebra);
+           if (pop_when_decl())
+               tac_exit(1);            /* no error return possibility */
+           break;
 
-    result->type = (parse_permission() == S_permit) ? N_permit : N_deny;
-    result->value = tac_strdup(sym_buf);
+       case S_permit:
+       case S_deny:
 
-    result->value1 = (void *) regcomp(result->value);
-    if (!result->value1) {
-       report(LOG_ERR, "in regular expression %s on line %d",
-              sym_buf, sym_line);
-       tac_exit(1);
-    }
-    sym_get();
+           result = (NODE *) tac_malloc(sizeof(NODE));
 
-    result->next = parse_cmd_matches();
+           bzero(result, sizeof(NODE));
+           result->line = sym_line;
 
-    return (result);
+           result->type = (parse_permission() == S_permit) ? N_permit : N_deny;
+           result->value = tac_strdup(sym_buf);
+
+#ifdef WITH_INCLUDED_REGEX
+
+           result->value1 = (void *) tac_regcomp(result->value);
+
+#else /* WITH_INCLUDED_REGEX */
+
+           result->value1 = tac_malloc(sizeof(regex_t));
+           if (regcomp(result->value1, result->value /* regex */, REG_NOSUB /* cflags */)) {
+               free(result->value1);
+               result->value1 = NULL;
+           }
+
+#endif /* WITH_INCLUDED_REGEX */
+
+           if (!result->value1) {
+               report(LOG_ERR, "in regular expression %s on line %d",
+                      sym_buf, sym_line);
+               tac_exit(1);
+           }
+           sym_get();
+
+           result->when = copy_current_when_decl();
+           expr_sink_register(result->when);
+
+           result->next = NULL;
+       }
+       *succp = result;
+       while (result->next)
+           result = result->next;      /* skip parsed chain from parse_cmd_matches() */
+       succp = &result->next;
+    }
+    /* NOTREACHED */
 }
 
+static NODE *parse_attrs TAC_ARGS((void));
+
 static NODE *
 parse_attrs()
 {
+    NODE *retval = NULL, **succp = &retval;
     NODE *result;
     char buf[MAX_INPUT_LINE_LEN];
-    int optional = 0;
+    int optional;
 
-    if (sym_code == S_closebra) {
-       return (NULL);
-    }
-    result = (NODE *) tac_malloc(sizeof(NODE));
+    for (;;) {
+       optional = 0;
 
-    bzero(result, sizeof(NODE));
-    result->line = sym_line;
+       switch (sym_code) {
+       case S_closebra:
+           return (retval);
 
-    if (sym_code == S_optional) {
-       optional++;
-       sym_get();
-    }
-    result->type = optional ? N_optarg : N_arg;
+       case S_when:
+           if (push_parsed_when_decl())
+               tac_exit(1);            /* no error return possibility */
+           parse(S_openbra);
+           result = parse_attrs();
+           parse(S_closebra);
+           if (pop_when_decl())
+               tac_exit(1);            /* no error return possibility */
+           break;
 
-    strcpy(buf, sym_buf);
-    parse(S_string);
-    strcat(buf, sym_buf);
-    parse(S_separator);
-    strcat(buf, sym_buf);
-    parse(S_string);
+       case S_optional:
+           optional = 1;
+           sym_get();
+           /* FALLTHRU */
+       default:
+           result = (NODE *) tac_malloc(sizeof(NODE));
 
-    result->value = tac_strdup(buf);
-    result->next = parse_attrs();
-    return (result);
+           bzero(result, sizeof(NODE));
+           result->line = sym_line;
+
+           result->type = optional ? N_optarg : N_arg;
+
+           strcpy(buf, sym_buf);
+           parse(S_string);
+           strcat(buf, sym_buf);
+           parse(S_separator);
+           strcat(buf, sym_buf);
+           parse(S_string);
+
+           result->value = tac_strdup(buf);
+
+           result->when = copy_current_when_decl();
+           expr_sink_register(result->when);
+
+           result->next = NULL;
+       }
+       *succp = result;
+       while (result->next)
+           result = result->next;      /* skip parsed chain from parse_attrs() */
+       succp = &result->next;
+    }
+    /* NOTREACHED */
 }
 
 
-static void
- getsym();
+static void sym_get TAC_ARGS((void));
 
 static void
 sym_get()
@@ -1163,9 +1710,11 @@ sym_get()
     }
 }
 
+static char *sym_buf_add TAC_ARGS((int c));
+
 static char *
 sym_buf_add(c)
-char c;
+int c;                         /* promoted "char" type */
 {
     if (sym_pos >= MAX_INPUT_LINE_LEN) {
        sym_buf[MAX_INPUT_LINE_LEN-1] = '\0';
@@ -1179,7 +1728,9 @@ char c;
     sym_buf[sym_pos++] = c;
     return(sym_buf);
 }
-    
+
+static void getsym TAC_ARGS((void));
+
 static void
 getsym()
 {
@@ -1220,6 +1771,18 @@ next:
        rch();
        return;
 
+    case '(':
+       strcpy(sym_buf, "(");
+       sym_code = S_openparen;
+       rch();
+       return;
+
+    case ')':
+       strcpy(sym_buf, ")");
+       sym_code = S_closeparen;
+       rch();
+       return;
+
     case '#':
        while ((sym_ch != '\n') && (sym_ch != EOF))
            rch();
@@ -1246,7 +1809,7 @@ next:
                        rch();
                        return;
                    }
-                   
+
                    /* fall through */
                case '"':
                    if (!sym_buf_add(sym_ch)) {
@@ -1304,6 +1867,8 @@ next:
     }
 }
 
+static void rch TAC_ARGS((void));
+
 static void
 rch()
 {
@@ -1318,96 +1883,105 @@ rch()
 }
 
 
-/* For a user or group, find the value of a field. Does not recurse. */
-VALUE
-get_value(user, field)
-USER *user;
+static VALUE get_value TAC_ARGS((ENTITY *entity, int field));
+
+/* Find the value of a field. Does not recurse. */
+static VALUE
+get_value(entity, field)
+ENTITY *entity;
 int field;
 {
     VALUE v;
 
+    v.pval = NULL;     /* do both just for sure... */
     v.intval = 0;
 
-    if (!user) {
-       parse_error("get_value: illegal user");
+    if (!entity) {
+       parse_error("get_value: illegal entity");
        return (v);
     }
     switch (field) {
 
     case S_name:
-       v.pval = user->name;
+       v.pval = entity->name;
        break;
 
     case S_login:
-       v.pval = user->login;
+       v.pval = entity->login;
        break;
 
     case S_global:
-       v.pval = user->global;
-       break;
-
-    case S_member:
-       v.pval = user->member;
+       v.pval = entity->global;
        break;
 
     case S_expires:
-       v.pval = user->expires;
+       v.pval = entity->expires;
        break;
 
     case S_arap:
-       v.pval = user->arap;
+       v.pval = entity->arap;
        break;
 
     case S_chap:
-       v.pval = user->chap;
+       v.pval = entity->chap;
        break;
 
 #ifdef MSCHAP
     case S_mschap:
-       v.pval = user->mschap;
+       v.pval = entity->mschap;
        break;
 #endif /* MSCHAP */
 
     case S_pap:
-       v.pval = user->pap;
+       v.pval = entity->pap;
        break;
 
     case S_opap:
-       v.pval = user->opap;
+       v.pval = entity->opap;
        break;
 
     case S_message:
-       v.pval = user->msg;
+       v.pval = entity->msg;
        break;
 
     case S_svc:
-       v.pval = user->svcs;
+       v.pval = entity->svcs;
        break;
 
     case S_before:
-       v.pval = user->before_author;
+       v.pval = entity->before_author;
        break;
 
     case S_after:
-       v.pval = user->after_author;
+       v.pval = entity->after_author;
        break;
 
     case S_svc_dflt:
-       v.intval = user->svc_dflt;
+       v.intval = entity->svc_dflt;
        break;
 
 #ifdef MAXSESS
     case S_maxsess:
-       v.intval = user->maxsess;
+       v.intval = entity->maxsess;
        break;
-#endif 
+#endif
 
     case S_nopasswd:
-       v.intval = user->nopasswd;
+       v.intval = entity->nopasswd;
        break;
-       
+
     case S_time:
-       v.pval = user->time;
+       v.pval = entity->time;
+       break;
+
+    case S_key:
+       if (entity->type == S_user) {
+           report(LOG_ERR, "get_value: S_key field not supported in %s %s",
+                       entity_type_to_string(entity->type), entity->name);
+           v.pval = NULL;
+           return(v);
+       }
+       v.pval = entity->key;
        break;
 
     default:
@@ -1417,102 +1991,100 @@ int field;
     return (v);
 }
 
-/* For host , find value of field. Doesn't recursive */
-VALUE
-get_hvalue(host, field)
-HOST *host;
-int field;
+
+/* Internal graph scanning routines */
+
+static enum value_scan_func_result value_scan TAC_ARGS((int type, const char *name, int recurse, value_scan_func_t func, void *func_data));
+
+static enum value_scan_func_result
+value_scan(type, name, recurse, func, func_data)
+int type;
+const char *name;
+int recurse;
+value_scan_func_t func;
+void *func_data;
 {
-    VALUE v;
-    v.intval = 0;
-    if(!host) {
-       parse_error("get_hvalue: illegal host");
-        return (v);
-    }
-    switch (field) {
-       case S_name:
-        v.pval = host->name;
-        break;
-       
-       case S_key:
-       v.pval = host->key;
-       break;
-       
-       default:
-        report(LOG_ERR, "get_value: unknown field %d", field);
-        break;
+    ENTITY *entity;
+
+    if (debug & DEBUG_CONFIG_FLAG)
+       report(LOG_DEBUG, "value_scan: find %s %s, recurse=%d",
+               entity_type_to_string(type), name, recurse);
+
+    entity = entity_lookup(type, name);
+    if (!entity) {
+       if (debug & DEBUG_CONFIG_FLAG)
+           report(LOG_DEBUG, "value_scan: no %s named %s",
+                   entity_type_to_string(type), name);
+       return (VSFR_CONTINUE);
     }
-    return (v);
-}
 
+    return (value_scan_entity(entity, recurse, func, func_data));
+}
 
 /* For each user, check she doesn't circularly reference a
    group. Return 1 if it does */
-static int
-circularity_check()
+
+static int circularity_check_failed;
+
+static void circularity_check_fail TAC_ARGS((struct membership *membership));
+
+static void
+circularity_check_fail(membership)
+struct membership *membership;
 {
-    USER *user, *entry, *group;
-    USER **users = (USER **) hash_get_entries(usertable);
-    USER **groups = (USER **) hash_get_entries(grouptable);
-    USER **p, **q;
+    ENTITY *entity;
 
-    /* users */
-    for (p = users; *p; p++) {
-       user = *p;
+    circularity_check_failed = 1;
 
-       if (debug & DEBUG_PARSE_FLAG)
-           report(LOG_DEBUG, "circularity_check: user=%s", user->name);
+    report(LOG_ERR, "recursively defined groups:");
+    while (membership) {
+       entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);
+       report(LOG_ERR, "%s %s",
+               entity_type_to_string(entity->type), entity->name);
+       membership = value_scan_backward(entity);
+    }
+}
 
-       /* Initialise all groups "seen" flags to zero */
-       for (q = groups; *q; q++) {
-           group = *q;
-           group->flags &= ~FLAG_SEEN;
-       }
+static enum value_scan_func_result circularity_check_func TAC_ARGS((ENTITY *entity, void *func_data));
 
-       entry = user;
+static enum value_scan_func_result
+circularity_check_func(entity, func_data /* unused */)
+ENTITY *entity;
+void *func_data;
+{
+    /* only useful to speedup case of failure */
+    if (circularity_check_failed)
+       return (VSFR_FOUND);
 
-       while (entry) {
-           /* check groups we are a member of */
-           char *groupname = entry->member;
+    return (VSFR_CONTINUE);
+}
 
-           if (debug & DEBUG_PARSE_FLAG)
-               report(LOG_DEBUG, "\tmember of group %s",
-                      groupname ? groupname : "<none>");
+static int circularity_check TAC_ARGS((void));
 
+static int
+circularity_check()
+{
+    ENTITY *entity;
+    ENTITY **users_base = (ENTITY **) hash_get_entries(usertable);
+    ENTITY **users;
 
-           /* if not a member of any groups, go on to next user */
-           if (!groupname)
-               break;
+    /* users */
+    for (users = users_base; *users; users++) {
+       entity = *users;
 
-           group = (USER *) hash_lookup(grouptable, groupname);
-           if (!group) {
-               report(LOG_ERR, "%s=%s, group %s does not exist",
-                      (entry->flags & FLAG_ISUSER) ? "user" : "group",
-                      entry->name, groupname);
-               free(users);
-               free(groups);
-               return (1);
-           }
-           if (group->flags & FLAG_SEEN) {
-               report(LOG_ERR, "recursively defined groups");
-
-               /* print all seen "groups" */
-               for (q = groups; *q; q++) {
-                   group = *q;
-                   if (group->flags & FLAG_SEEN)
-                       report(LOG_ERR, "%s", group->name);
-               }
-               free(users);
-               free(groups);
-               return (1);
-           }
-           group->flags |= FLAG_SEEN;  /* mark group as seen */
-           entry = group;
-       }
+       if (debug & DEBUG_PARSE_FLAG)
+           report(LOG_DEBUG, "circularity_check: user=%s", entity->name);
+
+       circularity_check_failed = 0;
+       value_scan_forward_seen_hook = circularity_check_fail;
+       value_scan_entity(entity, TAC_PLUS_RECURSE,
+               (value_scan_func_t) circularity_check_func, NULL /* func_data-unused */);
+       value_scan_forward_seen_hook = NULL;
+       if (circularity_check_failed)
+           break;
     }
-    free(users);
-    free(groups);
-    return (0);
+    free(users_base);
+    return (circularity_check_failed);
 }
 
 
@@ -1525,147 +2097,85 @@ circularity_check()
    Returns void * because it can return a string or a node pointer
    (should really return a union pointer).
 */
-static VALUE
-cfg_get_value(name, isuser, attr, recurse)
-char *name;
-int isuser, attr, recurse;
-{
-    USER *user, *group;
-    VALUE value;
 
-    value.pval = NULL;
+static VALUE cfg_get_value_VALUE;      /* private */
 
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_get_value: name=%s isuser=%d attr=%s rec=%d",
-              name, isuser, codestring(attr), recurse);
-
-    /* find the user/group entry */
-
-    user = (USER *) hash_lookup(isuser ? usertable : grouptable, name);
-
-    if (!user) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_value: no user/group named %s", name);
-       return (value);
-    }
+static enum value_scan_func_result cfg_get_value_func TAC_ARGS((ENTITY *entity, int *attrp));
 
+static enum value_scan_func_result
+cfg_get_value_func(entity,attrp /* func_data */)
+ENTITY *entity;
+int *attrp;
+{
     /* found the entry. Lookup value from attr=value */
-    value = get_value(user, attr);
+    cfg_get_value_VALUE = get_value(entity, *attrp);
+    if (cfg_get_value_VALUE.pval)
+       return (VSFR_FOUND);
 
-    if (value.pval || !recurse) {
-       return (value);
-    }
-    /* no value. Check containing group */
-    if (user->member)
-       group = (USER *) hash_lookup(grouptable, user->member);
-    else
-       group = NULL;
+    return (VSFR_CONTINUE);
+}
 
-    while (group) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_value: recurse group = %s",
-                  group->name);
+static VALUE cfg_get_value TAC_ARGS((int type, const char *name, int attr, int recurse));
 
-       value = get_value(group, attr);
+static VALUE
+cfg_get_value(type, name, attr, recurse)
+int type;
+const char *name;
+int attr, recurse;
+{
+    if (debug & DEBUG_CONFIG_FLAG)
+       report(LOG_DEBUG, "cfg_get_value: type=%s name=%s attr=%s recurse=%d",
+              entity_type_to_string(type), name, codestring(attr), recurse);
 
-       if (value.pval) {
-           return (value);
-       }
-       /* still nothing. Check containing group and so on */
+    cfg_get_value_VALUE.pval = NULL;
+    value_scan(type, name, recurse,
+               (value_scan_func_t) cfg_get_value_func, &attr /* func_data */);
+    return (cfg_get_value_VALUE);
+}
 
-       if (group->member)
-           group = (USER *) hash_lookup(grouptable, group->member);
-       else
-           group = NULL;
-    }
 
-    /* no value for this user or her containing groups */
-    value.pval = NULL;
-    return (value);
-}
+/* Wrappers for cfg_get_value:
+ */
 
+int cfg_get_intvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
 
-/* Wrappers for cfg_get_value */
 int
-cfg_get_intvalue(name, isuser, attr, recurse)
-char *name;
-int isuser, attr, recurse;
+cfg_get_intvalue(type, name, attr, recurse)
+int type;
+const char *name;
+int attr, recurse;
 {
-    int val = cfg_get_value(name, isuser, attr, recurse).intval;
+    int val = cfg_get_value(type, name, attr, recurse).intval;
 
     if (debug & DEBUG_CONFIG_FLAG)
        report(LOG_DEBUG, "cfg_get_intvalue: returns %d", val);
     return(val);
 }
 
-char *
-cfg_get_pvalue(name, isuser, attr, recurse)
-char *name;
-int isuser, attr, recurse;
-{
-    char *p = cfg_get_value(name, isuser, attr, recurse).pval;
-
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_get_pvalue: returns %s", 
-              p ? p : "NULL");
-    return(p);
-}
-
-/* For getting host values */
-static VALUE
-cfg_get_hvalue(name, attr)
-char *name;
-int attr;
-{
-    HOST *host;
-    VALUE value;
-
-    value.pval = NULL;
-    if (debug & DEBUG_CONFIG_FLAG)
-        report(LOG_DEBUG, "cfg_get_hvalue: name=%s attr=%s ",
-               name, codestring(attr));
-    
-    /* find the host entry in hash table */
-
-    host = (HOST *) hash_lookup( hosttable, name);
+const char *cfg_get_pvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
 
-    if (!host) {
-        if (debug & DEBUG_CONFIG_FLAG)
-            report(LOG_DEBUG, "cfg_get_hvalue: no host named %s", name);
-        return (value);
-    }
-
-    /* found the entry. Lookup value from attr=value */
-    value = get_hvalue(host, attr);
-
-    if (value.pval) {
-        return (value);
-    }
-    /* No any value for this host */    
-    value.pval = NULL;
-    return (value);
-}
-
-/* Wrappers for cfg_get_hvalue */
-char *
-cfg_get_phvalue(name, attr)
-char *name;
-int attr;
+const char *
+cfg_get_pvalue(type, name, attr, recurse)
+int type;
+const char *name;
+int attr, recurse;
 {
-    char *p = cfg_get_hvalue(name, attr).pval;
+    char *p = cfg_get_value(type, name, attr, recurse).pval;
 
     if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_get_phvalue: returns %s", 
-              p ? p : "NULL");
+       report(LOG_DEBUG, "cfg_get_pvalue: returns %s",
+               p ? p : "NULL");
     return(p);
 }
 
-/*
-   Read the config file and do some basic sanity checking on
-   it. Return 1 if we find any errors. */
+/* Read the config file and do some basic sanity checking on
+ * it. Return 1 if we find any errors.
+ */
+int cfg_read_config TAC_ARGS((const char *cfile));
 
+int
 cfg_read_config(cfile)
-char *cfile;
+const char *cfile;
 {
     sym_line = 1;
 
@@ -1679,7 +2189,17 @@ char *cfile;
        return (1);
     }
 
-    if (circularity_check()) {
+    if (0
+     || enlist_entity_connect()
+     || expr_sink_commit()
+           /* circularity is allowed in the new fully-recursive algorithm */
+     || (!algorithm_recursive && circularity_check())
+        ) {
+       fclose(cf);
+       return (1);
+    }
+    if (!when_expr_root || when_expr_root->type!=S_and || when_expr_root->u.and_or.child_first) {
+       report(LOG_ERR, "Some 'when' expression found still pushed on stack");
        fclose(cf);
        return (1);
     }
@@ -1688,350 +2208,447 @@ char *cfile;
     return (0);
 }
 
-/* return 1 if user exists, 0 otherwise */
+/* return 1 if user exists, 0 otherwise
+ */
+int cfg_user_exists TAC_ARGS((const char *username));
+
 int
 cfg_user_exists(username)
-char *username;
+const char *username;
 {
-    USER *user = (USER *) hash_lookup(usertable, username);
-
-    return (user != NULL);
+    return (NULL != hash_lookup(usertable, username));
 }
 
 /* return expiry string of user. If none, try groups she is a member
-   on, and so on, recursively if recurse is non-zero */
-char *
-cfg_get_expires(username, recurse)
-char *username;
+ * on, and so on, recursively if recurse is non-zero
+ */
+const char *cfg_get_expires TAC_ARGS((const char *username, int recurse));
 
+const char *
+cfg_get_expires(username, recurse)
+const char *username;
+int recurse;
 {
-    return (cfg_get_pvalue(username, TAC_IS_USER, S_expires, recurse));
+    return (cfg_get_pvalue(S_user, username, S_expires, recurse));
 }
 
 /* return time string of user. If none, try groups she is a member
-   on, and so on, recursively if recurse is non-zero */
-char *
+ * on, and so on, recursively if recurse is non-zero
+ */
+const char *cfg_get_timestamp TAC_ARGS((const char *username, int recurse));
+
+const char *
 cfg_get_timestamp(username, recurse)
-char *username;
+const char *username;
+int recurse;
 {
-    return (cfg_get_pvalue(username, TAC_IS_USER, S_time, recurse));
+    return (cfg_get_pvalue(S_user, username, S_time, recurse));
 }
 
-
 /* return password string of user. If none, try groups she is a member
-   on, and so on, recursively if recurse is non-zero */
-char *
-cfg_get_login_secret(user, recurse)
-char *user;
+ * on, and so on, recursively if recurse is non-zero
+ */
+const char *cfg_get_login_secret TAC_ARGS((const char *user, int recurse));
 
+const char *
+cfg_get_login_secret(user, recurse)
+const char *user;
+int recurse;
 {
-    return (cfg_get_pvalue(user, TAC_IS_USER, S_login, recurse));
+    return (cfg_get_pvalue(S_user, user, S_login, recurse));
 }
 
 /* return value of the nopasswd field. If none, try groups she is a member
-   on, and so on, recursively if recurse is non-zero */
+ * on, and so on, recursively if recurse is non-zero
+ */
+int cfg_get_user_nopasswd TAC_ARGS((const char *user, int recurse));
+
 int
 cfg_get_user_nopasswd(user, recurse)
-    char *user;
+const char *user;
+int recurse;
 {
-    return (cfg_get_intvalue(user, TAC_IS_USER, S_nopasswd, recurse));
+    return (cfg_get_intvalue(S_user, user, S_nopasswd, recurse));
 }
 
 /* return user's secret. If none, try groups she is a member
-   on, and so on, recursively if recurse is non-zero */
-char *
-cfg_get_arap_secret(user, recurse)
-char *user;
+ * on, and so on, recursively if recurse is non-zero
+ */
+const char *cfg_get_arap_secret TAC_ARGS((const char *user, int recurse));
 
+const char *
+cfg_get_arap_secret(user, recurse)
+const char *user;
+int recurse;
 {
-    return (cfg_get_pvalue(user, TAC_IS_USER, S_arap, recurse));
+    return (cfg_get_pvalue(S_user, user, S_arap, recurse));
 }
 
-char *
-cfg_get_chap_secret(user, recurse)
-char *user;
+const char *cfg_get_chap_secret TAC_ARGS((const char *user, int recurse));
 
+const char *
+cfg_get_chap_secret(user, recurse)
+const char *user;
+int recurse;
 {
-    return (cfg_get_pvalue(user, TAC_IS_USER, S_chap, recurse));
+    return (cfg_get_pvalue(S_user, user, S_chap, recurse));
 }
 
 #ifdef MSCHAP
-char *
-cfg_get_mschap_secret(user, recurse)
-char *user;
 
+const char *cfg_get_mschap_secret TAC_ARGS((const char *user, int recurse));
+
+const char *
+cfg_get_mschap_secret(user, recurse)
+const char *user;
+int recurse;
 {
-    return (cfg_get_pvalue(user, TAC_IS_USER, S_mschap, recurse));
+    return (cfg_get_pvalue(S_user, user, S_mschap, recurse));
 }
+
 #endif /* MSCHAP */
 
-char *
+const char *cfg_get_pap_secret TAC_ARGS((const char *user, int recurse));
+
+const char *
 cfg_get_pap_secret(user, recurse)
-char *user;
+const char *user;
+int recurse;
 {
-    return (cfg_get_pvalue(user, TAC_IS_USER, S_pap, recurse));
+    return (cfg_get_pvalue(S_user, user, S_pap, recurse));
 }
 
-char *
+const char *cfg_get_opap_secret TAC_ARGS((const char *user, int recurse));
+
+const char *
 cfg_get_opap_secret(user, recurse)
-char *user;
+const char *user;
+int recurse;
 {
-    return (cfg_get_pvalue(user, TAC_IS_USER, S_opap, recurse));
+    return (cfg_get_pvalue(S_user, user, S_opap, recurse));
 }
 
 /* return the global password for the user (or the group, etc.) */
 
-char *
-cfg_get_global_secret(user, recurse)
-char *user;
+const char *cfg_get_global_secret TAC_ARGS((const char *user, int recurse));
 
+const char *
+cfg_get_global_secret(user, recurse)
+const char *user;
+int recurse;
 {
-    return (cfg_get_pvalue(user, TAC_IS_USER, S_global, recurse));
+    return (cfg_get_pvalue(S_user, user, S_global, recurse));
 }
 
 #ifdef USE_PAM
+
 /* Return a pointer to a node representing a PAM Service name */
-char *
-cfg_get_pam_service(user,recurse)
-char *user;
 
+const char *cfg_get_pam_service TAC_ARGS((const char *user, int recurse));
+
+const char *
+cfg_get_pam_service(user, recurse)
+const char *user;
+int recurse;
 {
- char *cfg_passwd;
- char *p;   
   const char *cfg_passwd;
+    const char *p;
 
-cfg_passwd = cfg_get_pap_secret(user, recurse);
-if (!cfg_passwd) {
-               cfg_passwd = cfg_get_global_secret(user, recurse);
-}
-if (!cfg_passwd && !cfg_user_exists(user)) {
+    cfg_passwd = cfg_get_pap_secret(user, recurse);
+
+    if (!cfg_passwd)
+       cfg_passwd = cfg_get_global_secret(user, recurse);
+
+    if (!cfg_passwd && !cfg_user_exists(user)) {
         cfg_passwd = cfg_get_authen_default();
         switch (cfg_get_authen_default_method()) {
-               case (S_pam): 
-                       if (debug & DEBUG_AUTHOR_FLAG)
-                        report(LOG_DEBUG, "Get Default PAM Service :%s",cfg_passwd);
-                       return(cfg_passwd);
-                       break;
-               default:
-                       if (debug & DEBUG_AUTHOR_FLAG)
-                        report(LOG_DEBUG, "I havent find any PAM Service!!");
-                       return(NULL);/* Haven't any PAM Service!! */
+
+       case (S_pam):
+           if (debug & DEBUG_AUTHOR_FLAG)
+               report(LOG_DEBUG, "Get Default PAM Service :%s",cfg_passwd);
+           return(cfg_passwd);
+           break;
+
+       default:
+           if (debug & DEBUG_AUTHOR_FLAG)
+               report(LOG_DEBUG, "I havent find any PAM Service!!");
+           return(NULL);/* Haven't any PAM Service!! */
        }
-}
+    }
 
-p=tac_find_substring("pam ", cfg_passwd);
+    p = tac_find_substring("pam ", cfg_passwd);
 
-if(p) {  /* We find PAM services */
+    if(p) {  /* We find PAM services */
        if (debug & DEBUG_AUTHOR_FLAG)
                report(LOG_DEBUG, "I get PAM sevice:%s",p);
-return (p);
-}
+       return (p);
+    }
 
-if (debug & DEBUG_AUTHOR_FLAG)
+    if (debug & DEBUG_AUTHOR_FLAG)
        report(LOG_DEBUG, "No any PAM Sevice");
 
-return(NULL);
+    return(NULL);
 }
 
 #endif /* For PAM */
-       
 
 
 /* Return a pointer to a node representing a given service
    authorization, taking care of recursion issues correctly. Protocol
-   is only read if the type is N_svc_ppp. svcname is only read if type
+   is only read if the svctype is N_svc_ppp. svcname is only read if type
    is N_svc.
 */
 
-NODE *
-cfg_get_svc_node(username, type, protocol, svcname, recurse)
-char *username;
-int type;
-char *protocol, *svcname;
-int recurse;
-{
-    USER *user, *group;
-    NODE *svc;
-
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, 
-              "cfg_get_svc_node: username=%s %s proto=%s svcname=%s rec=%d",
-              username, 
-              cfg_nodestring(type), 
-              protocol ? protocol : "", 
-              svcname ? svcname : "", 
-              recurse);
-
-    /* find the user/group entry */
-    user = (USER *) hash_lookup(usertable, username);
+struct cfg_get_svc_node_param {
+    int svctype;
+    const char *protocol, *svcname;
+    NODE *node;
+    int retval;
+};
 
-    if (!user) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_svc_node: no user named %s", username);
-       return (NULL);
-    }
+static enum value_scan_func_result cfg_get_svc_node_func TAC_ARGS((ENTITY *entity, struct cfg_get_svc_node_param *param));
 
-    /* found the user entry. Find svc node */
-    for(svc = (NODE *) get_value(user, S_svc).pval; svc; svc = svc->next) {
+static enum value_scan_func_result
+cfg_get_svc_node_func(entity, param /* func_data */)
+ENTITY *entity;
+struct cfg_get_svc_node_param *param;
+{
+    NODE *svc;
+    enum eval_result svc_default;
 
-       if (svc->type != type) 
+    for (svc = (NODE *) get_value(entity, S_svc).pval; svc; svc = svc->next) {
+       if (svc->type != param->svctype)
            continue;
-
-       if (type == N_svc_ppp && !STREQ(svc->value1, protocol)) {
+       if (param->svctype == N_svc_ppp && param->protocol && !STREQ(svc->value1, param->protocol))
            continue;
-       }
-
-       if (type == N_svc && !STREQ(svc->value1, svcname)) {
+       if (param->svctype == N_svc     && param->svcname  && !STREQ(svc->value1, param->svcname ))
+           continue;
+       if (expr_eval(svc->when) != ER_TRUE)    /* expensive */
            continue;
-       }
 
        if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, 
+           report(LOG_DEBUG,
                   "cfg_get_svc_node: found %s proto=%s svcname=%s",
-                  cfg_nodestring(type), 
-                  protocol ? protocol : "", 
-                  svcname ? svcname : "");
-
-       return(svc);
-    }
+                  cfg_nodestring(param->svctype),
+                  param->protocol ? param->protocol : "",
+                  param->svcname ? param->svcname : "");
 
-    if (!recurse) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_svc_node: returns NULL");
-       return (NULL);
+       param->node = svc;
+       param->retval = 1;
+       return (VSFR_FOUND);
     }
 
-    /* no matching node. Check containing group */
-    if (user->member)
-       group = (USER *) hash_lookup(grouptable, user->member);
-    else
-       group = NULL;
-
-    while (group) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_svc_node: recurse group = %s",
-                  group->name);
-
-       for(svc = (NODE *) get_value(group, S_svc).pval; svc; svc = svc->next) {
-
-           if (svc->type != type) 
-               continue;
+    /* look at 'default service' settings */
+    svc_default = entity_svc_default(entity);
+    switch (svc_default) {
 
-           if (type == N_svc_ppp && !STREQ(svc->value1, protocol)) {
-               continue;
-           }
+    case ER_TRUE:
+    case ER_FALSE:
+       if (debug & DEBUG_AUTHOR_FLAG)
+           report(LOG_DEBUG,
+          "cfg_get_svc_node: svc=%s protocol=%s svcname=%s forced %s by default service",
+                  cfg_nodestring(param->svctype),
+                  param->protocol ? param->protocol : "",
+                  param->svcname ? param->svcname : "",
+                  (svc_default == ER_TRUE ? "permit" : "deny"));
+
+       param->retval = (svc_default == ER_TRUE);
+       return (VSFR_FOUND);
+
+    default:   /* shouldn't happen */
+    case ER_UNKNOWN:
+       return (VSFR_CONTINUE);
+    }
+    /* NOTREACHED */
+}
 
-           if (type == N_svc && !STREQ(svc->value1, svcname)) {
-               continue;
-           }
+int cfg_get_svc_node TAC_ARGS((const char *username, int svctype, const char *protocol, const char *svcname, int recurse, NODE **nodep));
 
-           if (debug & DEBUG_CONFIG_FLAG)
-               report(LOG_DEBUG, 
-                      "cfg_get_svc_node: found %s proto=%s svcname=%s",
-                      cfg_nodestring(type), 
-                      protocol ? protocol : "", 
-                      svcname ? svcname : "");
+int
+cfg_get_svc_node(username, svctype, protocol, svcname, recurse, nodep)
+const char *username;
+int svctype;
+const char *protocol;
+const char *svcname;
+int recurse;
+NODE **nodep;
+{
+    struct cfg_get_svc_node_param param;
+    enum value_scan_func_result vsfr;
 
-           return(svc);
-       }
+    param.svctype = svctype;
+    param.protocol = protocol;
+    param.svcname = svcname;
+    param.node = NULL;
+    param.retval = 0;
 
-       /* still nothing. Check containing group and so on */
+    if (debug & DEBUG_CONFIG_FLAG)
+       report(LOG_DEBUG,
+              "cfg_get_svc_node: username=%s %s proto=%s svcname=%s rec=%d",
+              username,
+              cfg_nodestring(svctype),
+              protocol ? protocol : "",
+              svcname ? svcname : "",
+              recurse);
 
-       if (group->member)
-           group = (USER *) hash_lookup(grouptable, group->member);
-       else
-           group = NULL;
-    }
+    vsfr = value_scan(S_user, username, recurse,
+               (value_scan_func_t) cfg_get_svc_node_func, &param /* func_data */);
+    if (nodep)
+       *nodep = param.node;
 
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_get_svc_node: returns NULL");
+    if (vsfr == VSFR_FOUND)
+       return (param.retval);
 
-    /* no matching svc node for this user or her containing groups */
-    return (NULL);
+    /* The service does not exist. Do the default */
+    return (cfg_no_user_permitted() ? 1 : 0);
 }
 
-/* Return a pointer to the node representing a set of command regexp
+/* Return a pointer to the node representing a set of command tac_regexp
    matches for a user and command, handling recursion issues correctly */
-NODE *
-cfg_get_cmd_node(name, cmdname, recurse)
-char *name, *cmdname;
-int recurse;
 
+struct cfg_authorize_cmd_param {
+    const char *cmd;
+    const char *args;
+    enum eval_result result;
+};
+
+static enum value_scan_func_result cfg_authorize_cmd_func TAC_ARGS((ENTITY *entity, struct cfg_authorize_cmd_param *param));
+
+static enum value_scan_func_result
+cfg_authorize_cmd_func(entity, param /* func_data */)
+ENTITY *entity;
+struct cfg_authorize_cmd_param *param;
 {
-    USER *user, *group;
     NODE *svc;
 
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_get_cmd_node: name=%s cmdname=%s rec=%d",
-              name, cmdname, recurse);
+    for (svc = (NODE *) get_value(entity, S_svc).pval; svc; svc = svc->next) {
+       NODE *node;
 
-    /* find the user/group entry */
-    user = (USER *) hash_lookup(usertable, name);
+       if (svc->type != N_svc_cmd)
+           continue;
+       if (!STREQ(svc->value, param->cmd))
+           continue;
+       if (expr_eval(svc->when) != ER_TRUE)    /* expensive */
+           continue;
 
-    if (!user) {
        if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_cmd_node: no user named %s", name);
-       return (NULL);
-    }
-    /* found the user entry. Find svc node */
-    svc = (NODE *) get_value(user, S_svc).pval;
-
-    while (svc) {
-       if (svc->type == N_svc_cmd && STREQ(svc->value, cmdname)) {
-           if (debug & DEBUG_CONFIG_FLAG)
-               report(LOG_DEBUG, "cfg_get_cmd_node: found cmd %s %s node",
-                      cmdname, cfg_nodestring(svc->type));
-           return (svc);
-       }
-       svc = svc->next;
-    }
+           report(LOG_DEBUG, "cfg_authorize_cmd: found cmd %s %s node",
+                  param->cmd, cfg_nodestring(svc->type));
 
-    if (!recurse) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_cmd_node: returns NULL");
-       return (NULL);
-    }
-    /* no matching node. Check containing group */
-    if (user->member)
-       group = (USER *) hash_lookup(grouptable, user->member);
-    else
-       group = NULL;
+       /* we have 'cmd <openbra>' point, now traverse through its 'permit'/'deny' pairs: */
 
-    while (group) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_cmd_node: recurse group = %s",
-                  group->name);
+       for (node = svc->value1; node; node = node->next) {
+           int match;
+
+           if (expr_eval(node->when) != ER_TRUE)               /* expensive */
+               continue;
+
+#ifdef WITH_INCLUDED_REGEX
+
+           match = tac_regexec((tac_regexp *) node->value1, param->args);
+
+#else /* WITH_INCLUDED_REGEX */
 
-       svc = get_value(group, S_svc).pval;
+           match = !regexec((const regex_t *) node->value1, param->args /* string */,
+                   0 /* nmatch */, NULL /* pmatch */, 0 /* eflags */);
 
-       while (svc) {
-           if (svc->type == N_svc_cmd && STREQ(svc->value, cmdname)) {
-               if (debug & DEBUG_CONFIG_FLAG)
-                   report(LOG_DEBUG, "cfg_get_cmd_node: found cmd %s node %s",
-                          cmdname, cfg_nodestring(svc->type));
-               return (svc);
+#endif /* WITH_INCLUDED_REGEX */
+
+           if (debug & DEBUG_AUTHOR_FLAG) {
+               report(LOG_INFO, "line %d compare %s %s '%s' & '%s' %smatch",
+                      node->line, param->cmd,
+                      node->type == N_permit ? "permit" : "deny",
+                      (const char *) node->value, param->args, (match ? "" : "no "));
+           }
+
+           if (!match)
+               continue;
+
+           switch (node->type) {
+           case N_permit:
+               if (debug & DEBUG_AUTHOR_FLAG) {
+                   report(LOG_DEBUG, "%s %s permitted by line %d",
+                          param->cmd, param->args, node->line);
+               }
+               param->result = ER_TRUE;
+               return (VSFR_FOUND);
+               break;
+           case N_deny:
+               if (debug & DEBUG_AUTHOR_FLAG) {
+                   report(LOG_DEBUG, "%s %s denied by line %d",
+                          param->cmd, param->args, node->line);
+               }
+               param->result = ER_FALSE;
+               return (VSFR_FOUND);
+               break;
+           default:
+               report(LOG_ERR, "INTERNAL: illegal configuration node: %s: %s %s",
+                      session.peer, param->cmd, param->args);
+               param->result = ER_UNKNOWN;     /* error */
+               return (VSFR_FOUND);
            }
-           svc = svc->next;
        }
+       if (!algorithm_recursive) {     /* compatibility mode: */
+           if (debug & DEBUG_AUTHOR_FLAG)
+               report(LOG_DEBUG, "cmd %s exists, but no args match, denied (as no 'authorization = recursive' found)",
+                       param->cmd);
+           param->result = ER_FALSE;   /* emulate last "deny .*" */
+           return (VSFR_FOUND);
+       }
+    }
+
+    /* look at 'default service' settings */
+    param->result = entity_svc_default(entity);
+    switch (param->result) {
+
+    case ER_TRUE:
+       if (debug & DEBUG_AUTHOR_FLAG)
+           report(LOG_DEBUG, "cmd %s does not exist, permitted by default", param->cmd);
+       return (VSFR_FOUND);
+
+    case ER_FALSE:
 
-       /* still nothing. Check containing group and so on */
+       if (debug & DEBUG_AUTHOR_FLAG)
+           report(LOG_DEBUG, "cmd %s does not exist, denied by default", param->cmd);
+       return (VSFR_FOUND);
 
-       if (group->member)
-           group = (USER *) hash_lookup(grouptable, group->member);
-       else
-           group = NULL;
+    default:   /* shouldn't happen */
+    case ER_UNKNOWN:
+       return (VSFR_CONTINUE);
     }
+    /* NOTREACHED */
+}
+
+enum eval_result cfg_authorize_cmd TAC_ARGS((const char *username, const char *cmd, const char *args));
+
+enum eval_result
+cfg_authorize_cmd(username, cmd, args)
+const char *username;
+const char *cmd;
+const char *args;
+{
+    struct cfg_authorize_cmd_param param;
+
+    param.cmd = cmd;
+    param.args = args;
+    param.result = ER_UNKNOWN; /* error */
 
     if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_get_cmd_node: returns NULL");
+       report(LOG_DEBUG, "cfg_authorize_cmd: name=%s cmdname=%s args=%s",
+              username, cmd, args);
 
-    /* no matching cmd node for this user or her containing groups */
-    return (NULL);
+    value_scan(S_user, username, TAC_PLUS_RECURSE,
+               (value_scan_func_t) cfg_authorize_cmd_func, &param /* func_data */);
+
+    if (param.result != ER_UNKNOWN)
+       return (param.result);
+
+    /* The command does not exist. Do the default */
+    return (cfg_no_user_permitted() ? ER_TRUE : ER_FALSE);
 }
 
 /* Return an array of character strings representing configured AV
- * pairs, given a username and a service node. 
+ * pairs, given a username and a service node.
  *
  * In the AV strings returned, manipulate the separator character to
  * indicate which args are optional and which are mandatory.
@@ -2039,6 +2656,8 @@ int recurse;
  * Lastly, indicate what default permission was configured by setting
  * denyp */
 
+char **cfg_get_svc_attrs TAC_ARGS((NODE *svcnode, int *denyp));
+
 char **
 cfg_get_svc_attrs(svcnode, denyp)
 NODE *svcnode;
@@ -2063,9 +2682,14 @@ int *denyp;
 
     i = 0;
     for (node = svcnode->value; node; node = node->next) {
-       char *arg = tac_strdup(node->value);
-       char *p = index(arg, '=');
+       char *arg;
+       char *p;
+
+       if (expr_eval(node->when) != ER_TRUE)   /* expensive */
+           continue;   /* ignore this node */
 
+       arg = tac_strdup(node->value);
+       p = index(arg, '=');
        if (p && node->type == N_optarg)
            *p = '*';
        args[i++] = arg;
@@ -2075,23 +2699,28 @@ int *denyp;
 }
 
 
-int
-cfg_user_svc_default_is_permit(user)
-char *user;
+static enum eval_result entity_svc_default TAC_ARGS((ENTITY *entity));
 
+static enum eval_result
+entity_svc_default(entity)
+ENTITY *entity;
 {
-    int permit = cfg_get_intvalue(user, TAC_IS_USER, S_svc_dflt,
-                              TAC_PLUS_RECURSE);
-
-    switch (permit) {
-    default:                   /* default is deny */
-    case S_deny:
-       return (0);
+    switch (entity->svc_dflt) {
     case S_permit:
-       return (1);
+       return (ER_TRUE);
+    case S_deny:
+       return (ER_FALSE);
+    case S_default:
+    case 0:    /* not specified */
+       return (ER_UNKNOWN);
+    default:
+       report(LOG_ERR, "INTERNAL: invalid entity svc_dflt (%d)", entity->svc_dflt);
+       return (ER_UNKNOWN);
     }
 }
 
+int cfg_no_user_permitted TAC_ARGS((void));
+
 int
 cfg_no_user_permitted()
 {
@@ -2101,106 +2730,135 @@ cfg_no_user_permitted()
 }
 
 
-char *
+const char *cfg_get_authen_default TAC_ARGS((void));
+
+const char *
 cfg_get_authen_default()
 {
     return (authen_default);
 }
 
+int cfg_get_authen_default_method TAC_ARGS((void));
+
 /* For describe authentication method(pam,file,db..etc) */
-int 
+int
 cfg_get_authen_default_method()
 {
    return (authen_default_method);
 }
 
 
-/* Return 1 if this user has any ppp services configured. Used for
-   authorizing ppp/lcp requests */
-int
-cfg_ppp_is_configured(username, recurse)
-    char *username;
-    int recurse;
-{
-    USER *user, *group;
-    NODE *svc;
+/* Host entity management:
+ */
 
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_ppp_is_configured: username=%s rec=%d",
-              username, recurse);
+const char *cfg_get_host_key TAC_ARGS((const char *host));
 
-    /* find the user/group entry */
-    user = (USER *) hash_lookup(usertable, username);
+/* For getting host key */
+const char *
+cfg_get_host_key(host)
+const char *host;
+{
+    return (cfg_get_pvalue(S_host, host, S_key, algorithm_recursive /* recurse */));
+}
 
-    if (!user) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_ppp_is_configured: no user named %s", 
-                  username);
-       return (0);
-    }
+static ENTITY *force_belong_entity TAC_ARGS((int type, const char *name));
 
-    /* found the user entry. Find svc node */
-    for(svc = (NODE *) get_value(user, S_svc).pval; svc; svc = svc->next) {
+static ENTITY *
+force_belong_entity(type, name)
+int type;
+const char *name;
+{
+    ENTITY *entity = entity_lookup(type, name);
 
-       if (svc->type != N_svc_ppp) 
-           continue;
+    if (entity)
+       eval_force_belong_entity(entity);
 
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_ppp_is_configured: found svc ppp %s node",
-                  svc->value1);
-       
-       return(1);
-    }
+    return (entity);
+}
 
-    if (!recurse) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_ppp_is_configured: returns 0");
-       return (0);
-    }
+/* assumed existing initialized "session.peer*" */
 
-    /* no matching node. Check containing group */
-    if (user->member)
-       group = (USER *) hash_lookup(grouptable, user->member);
-    else
-       group = NULL;
+static ENTITY *request_peer_addr;
+static ENTITY *request_peer;
+static ENTITY *request_DEFAULT_group;
 
-    while (group) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_ppp_is_configured: recurse group = %s",
-                  group->name);
+static void enlist_request_peer TAC_ARGS((const char *hostname, ENTITY **entityp));
 
-       for(svc = (NODE *) get_value(group, S_svc).pval; svc; svc = svc->next) {
+static void
+enlist_request_peer(hostname, entityp)
+const char *hostname;
+ENTITY **entityp;
+{
+    *entityp = NULL;
+    if (!hostname)
+       return;
 
-           if (svc->type != N_svc_ppp)
-               continue;
+    *entityp = force_belong_entity(S_host, hostname);
+    if (*entityp && request_DEFAULT_group)
+       virtual_enlist_entity_direct(request_DEFAULT_group /* parent */, *entityp /* child */);
+}
 
-           if (debug & DEBUG_CONFIG_FLAG)
-               report(LOG_DEBUG, "cfg_ppp_is_configured: found svc ppp %s node",
-                      svc->value1);
-       
-           return(1);
-       }
+/* Try to build the following scenery:
+ * 
+ * host <session.peer_addr> [=ER_TRUE]
+ *  |
+ *  +-- group <DEFAULT_GROUPNAME>
+ *
+ * host <session.peer     > [=ER_TRUE]
+ *  |
+ *  +-- group <DEFAULT_GROUPNAME>
+ */
 
-       /* still nothing. Check containing group and so on */
+void cfg_request_scan_begin TAC_ARGS((void));
 
-       if (group->member)
-           group = (USER *) hash_lookup(grouptable, group->member);
-       else
-           group = NULL;
-    }
+void
+cfg_request_scan_begin()
+{
+    request_scan_begin();
 
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_ppp_is_configured: returns 0");
+    request_DEFAULT_group = entity_lookup(S_group, DEFAULT_GROUPNAME);
 
-    /* no PPP svc nodes for this user or her containing groups */
-    return (0);
+    if (session.peer_addr != session.peer)
+       enlist_request_peer(session.peer_addr, &request_peer_addr);
+    enlist_request_peer(session.peer, &request_peer);
 }
 
-/* For getting host key */
-char *
-cfg_get_host_key(host)
-char *host;
+/* Try to build the following scenery:
+ *
+ * ( user <identity->username> |  user <DEFAULT_USERNAME> ) [=ER_TRUE]
+ *  |
+ *  +-- host <session.peer_addr> [=ER_TRUE]
+ *  |    |
+ *  |    +- group <DEFAULT_GROUPNAME>
+ *  |
+ *  +-- host <session.peer     > [=ER_TRUE]
+ *  |    |
+ *  |    +-- group <DEFAULT_GROUPNAME>
+ *  |
+ *  +-- group <DEFAULT_GROUPNAME>
+ */
+
+void cfg_request_identity TAC_ARGS((const struct identity *identity));
+
+void
+cfg_request_identity(identity)
+const struct identity *identity;
 {
-    return (cfg_get_phvalue(host, S_key));
-}
+    ENTITY *user_entity = force_belong_entity(S_user, identity->username);
+    ENTITY *request_DEFAULT_group = entity_lookup(S_group, DEFAULT_GROUPNAME);
+
+    if (!user_entity)
+       user_entity = force_belong_entity(S_user, DEFAULT_USERNAME);
 
+    request_scan_user_known = 1;
+
+    if (!user_entity)
+       return;
+
+    if (request_peer_addr)
+       virtual_enlist_entity_direct(request_peer_addr     /* parent */, user_entity /* child */);
+    if (request_peer     )
+       virtual_enlist_entity_direct(request_peer          /* parent */, user_entity /* child */);
+    if (request_DEFAULT_group)
+       virtual_enlist_entity_direct(request_DEFAULT_group /* parent */, user_entity /* child */);
+}
diff --git a/cfgfile.h b/cfgfile.h
new file mode 100644 (file)
index 0000000..747a8b1
--- /dev/null
+++ b/cfgfile.h
@@ -0,0 +1,163 @@
+#ifndef CFGFILE_H
+#define CFGFILE_H 1
+
+#include "tac_plus.h"
+
+#include "utils.h"
+#include "cfgeval.h"
+
+
+/* Configurable:
+ */
+
+#define DEFAULT_USERNAME       "DEFAULT"
+#define DEFAULT_GROUPNAME      "DEFAULT"
+
+
+#define TAC_PLUS_RECURSE      1
+#define TAC_PLUS_NORECURSE    0
+
+/* Node types */
+
+#define N_arg           50
+#define N_optarg        51
+#define N_svc_exec      52
+#define N_svc_slip      53
+#define N_svc_ppp       54
+#define N_svc_arap      55
+#define N_svc_cmd       56
+#define N_permit        57
+#define N_deny          58
+#define N_svc           59
+
+typedef struct node NODE;
+
+/* A parse tree node */
+struct node {
+    int type;     /* node type (arg, svc, proto) */
+    NODE *next;   /* pointer to next node in chain */
+    void *value;  /* node value */
+    void *value1; /* node value */
+    int dflt;     /* default value for node */
+    int line;     /* line number declared on */
+    struct expr *when; /* conditions needed to respect this NODE */
+};
+
+union v {
+    int intval;
+    void *pval;
+};
+
+typedef union v VALUE;
+
+/* A user, host or group definition
+
+   The first 2 fields (name and hash) are used by the hash table
+   routines to hash this structure into a table.  Move them at your
+   peril
+*/
+
+struct entity {
+    char *name;                        /* username/groupname/hostname */
+    void *hash;                        /* hash table next pointer */
+    int line;                  /* line number defined on */
+    int type;                  /* set to S_user, S_host or S_group */
+
+    char *full_name;           /* users full name */
+    char *login;               /* Login password */
+    int nopasswd;               /* user requires no password */
+    char *global;              /* password to use if none set */
+    char *expires;             /* expiration date */
+    char *arap;                        /* our arap secret */
+    char *pap;                 /* our pap secret */
+    char *opap;                        /* our outbound pap secret */
+    char *chap;                        /* our chap secret */
+#ifdef MSCHAP
+    char *mschap;              /* our mschap secret */
+#endif /* MSCHAP */
+    char *msg;                 /* a message for this user */
+    char *before_author;       /* command to run before authorization */
+    char *after_author;                /* command to run after authorization */
+    char *key;                 /* host spesific key (N/A for S_user) */
+    int svc_dflt;              /* default authorization behaviour for svc or
+                                * cmd */
+                               /* =S_permit, S_deny or S_default */
+    NODE *svcs;                        /* pointer to svc nodes */
+#ifdef MAXSESS
+    int maxsess;               /* Max sessions/user */
+#endif /* MAXSESS */
+    char *time;                        /* Timestamp  */
+
+    struct tac_list to_parent_membership_list; /* ordered list of memberships to groups owning us: */
+    struct tac_list to_child_membership_list;  /* ordered list of memberships to entities in this group: */
+    unsigned to_child_membership_num;          /* # of 'to_child_membership_list' items */
+
+    struct {
+       unsigned seq;                           /* corresponds to global request_scan_seq */
+       enum eval_result belongs;               /* whether this ENTITY 'belongs' */
+    } request_scan;            /*   cfg_request() scanning */
+
+    struct {
+       unsigned seq;                           /* corresponds to global value_scan_seq */
+       unsigned seen:1;
+       struct membership *from;                /* from which we got to this one or NULL */
+    } value_scan;              /* cfg_get_value() scanning, many per request_scan */
+
+    struct {
+       unsigned seq;                           /* corresponds to global eval_scan_seq */
+       struct tac_list notify_expr_list;       /* contains expr.u.waiting_expr_node */
+                           /* may be from any of: eval_{want,solved,destroy}_entity_list: */
+       struct tac_list_node pending_entity_node;       /* we are interested in this entity */
+                       /* child memberships which are not yet check_eval-ed are NOT present here,
+                        * although when check_eval-entity finishes, all will be added here.
+                        * List refilling driven by check_eval_scan_entity(),
+                        * although each unsolved_child_node is added in check_eval_scan_membership().
+                        */
+       unsigned unsolved_to_child_membership_num;      /* when 0, we know we are ER_FALSE */
+       struct membership *unsolved_to_child_membership_first;
+    } eval_scan;               /*     expr_eval() scanning, many per value_scan */
+};
+#define PENDING_ENTITY_NODE_TO_ENTITY(pending_entity_node_) \
+       (&TAC_MEMBER_STRUCT(ENTITY, (pending_entity_node_), eval_scan.pending_entity_node))
+
+
+struct identity;
+
+extern const char *cfg_nodestring TAC_ARGS((int type));
+extern void cfg_clean_config TAC_ARGS((void));
+extern int cfg_get_intvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
+extern const char *cfg_get_pvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
+extern int cfg_read_config TAC_ARGS((const char *cfile));
+extern int cfg_user_exists TAC_ARGS((const char *username));
+extern const char *cfg_get_expires TAC_ARGS((const char *username, int recurse));
+extern const char *cfg_get_timestamp TAC_ARGS((const char *username, int recurse));
+extern const char *cfg_get_login_secret TAC_ARGS((const char *user, int recurse));
+extern int cfg_get_user_nopasswd TAC_ARGS((const char *user, int recurse));
+extern const char *cfg_get_arap_secret TAC_ARGS((const char *user, int recurse));
+extern const char *cfg_get_chap_secret TAC_ARGS((const char *user, int recurse));
+#ifdef MSCHAP
+extern const char *cfg_get_mschap_secret TAC_ARGS((const char *user, int recurse));
+#endif /* MSCHAP */
+extern const char *cfg_get_pap_secret TAC_ARGS((const char *user, int recurse));
+extern const char *cfg_get_opap_secret TAC_ARGS((const char *user, int recurse));
+extern const char *cfg_get_global_secret TAC_ARGS((const char *user, int recurse));
+#ifdef USE_PAM
+extern const char *cfg_get_pam_service TAC_ARGS((const char *user, int recurse));
+#endif /* PAM */
+extern int cfg_get_svc_node TAC_ARGS((const char *username, int svctype, const char *protocol, const char *svcname, int recurse, NODE **nodep));
+extern char **cfg_get_svc_attrs TAC_ARGS((NODE *svcnode, int *denyp));
+extern int cfg_no_user_permitted TAC_ARGS((void));
+extern const char *cfg_get_authen_default TAC_ARGS((void));
+extern int cfg_get_authen_default_method TAC_ARGS((void));
+extern const char *cfg_get_host_key TAC_ARGS((const char *host));
+extern void cfg_request_scan_begin TAC_ARGS((void));
+extern void cfg_request_identity TAC_ARGS((const struct identity *identity));
+extern enum eval_result cfg_authorize_cmd TAC_ARGS((const char *username, const char *cmd, const char *args));
+
+/* for use by cfgeval.c: */
+extern const char *entity_type_to_string TAC_ARGS((int entity_type));
+extern void scan_invalidate_entities TAC_ARGS((enum invalidate_scan what));
+extern ENTITY *entity_lookup TAC_ARGS((int type, const char *name));
+
+
+#endif /* CFGFILE_H */
index 9329b73..d6b3062 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
+
+#include "choose_authen.h"
 #include "expire.h"
+#include "enable.h"
+#include "report.h"
+#include "cfgfile.h"
+#include "default_fn.h"
+#include "default_v0_fn.h"
+#include "sendauth.h"
+#include "sendpass.h"
+#include "packet.h"
+#include "main.h"
+#include "do_author.h"                 /* for "struct identity" */
+
+#ifdef SKEY
+#include "skey_fn.h"
+#endif
 
-static int choose_login();
-static int choose_sendpass();
-static int choose_sendauth();
 
-int 
+static int choose_sendpass TAC_ARGS((struct authen_data *data, struct authen_type *type));
+static int choose_sendauth TAC_ARGS((struct authen_data *data, struct authen_type *type));
+static int choose_login TAC_ARGS((struct authen_data *data, struct authen_type *type));
+
+
+#if 0 /* unused */
+static int
 get_minor_version()
 {
     return(session.version & ~TAC_PLUS_MAJOR_VER_MASK);
 }
+#endif /* unused */
 
-/* 
+/*
  * Choose an authentication function. Return CHOOSE_OK if chosen,
- * CHOOSE_GETUSER if we need a username, CHOOSE_FAILED on failure 
+ * CHOOSE_GETUSER if we need a username, CHOOSE_FAILED on failure
  */
 
+int choose_authen TAC_ARGS((struct authen_data *data, struct authen_type *type));
+
 int
 choose_authen(data, type)
 struct authen_data *data;
@@ -51,7 +74,7 @@ struct authen_type *type;
 
     case TAC_PLUS_AUTHEN_LOGIN:
        /* For enabling, enable_fn handles everything. Must be minor
-        * version zero 
+        * version zero
         */
        if (data->service == TAC_PLUS_AUTHEN_SVC_ENABLE) {
            if (session.version != TAC_PLUS_VER_0) {
@@ -74,7 +97,7 @@ struct authen_type *type;
 
     /* never heard of this lot */
     report(LOG_ERR, "%s: %s %s Illegal packet ver=%d action=%d type=%d",
-          session.peer, 
+          session.peer,
           session.port,
           name ? name : "<unknown>",
           session.version,
@@ -84,14 +107,16 @@ struct authen_type *type;
     return(CHOOSE_FAILED);
 }
 
+static int choose_login TAC_ARGS((struct authen_data *data, struct authen_type *type));
+
 /* Choose an authentication function for action == LOGIN, service != enable */
 static int
 choose_login(data, type)
 struct authen_data *data;
 struct authen_type *type;
 {
-    char *name = data->NAS_id->username;
-    char *cfg_passwd;
+    const char *name = data->NAS_id->username;
+    const char *cfg_passwd;
 
     switch(type->authen_type) {
     case TAC_PLUS_AUTHEN_TYPE_ASCII:
@@ -108,14 +133,14 @@ struct authen_type *type;
        cfg_passwd = cfg_get_login_secret(name, TAC_PLUS_RECURSE);
        if (cfg_passwd && STREQ(cfg_passwd, "skey")) {
            if (debug & DEBUG_PASSWD_FLAG)
-               report(LOG_DEBUG, "%s %s: user %s requires skey", 
+               report(LOG_DEBUG, "%s %s: user %s requires skey",
                       session.peer, session.port, name);
 #ifdef SKEY
            type->authen_func = skey_fn;
            strcpy(type->authen_name, "skey_fn");
            return (CHOOSE_OK);
 #else /* SKEY */
-           report(LOG_ERR, 
+           report(LOG_ERR,
                   "%s %s: user %s s/key support has not been compiled in",
                   name ? name : "<unknown>",
                   session.peer, session.port);
@@ -130,7 +155,7 @@ struct authen_type *type;
 
     case TAC_PLUS_AUTHEN_TYPE_ARAP:
 #ifndef ARAP_DES
-       /* 
+       /*
         * If we have no des code we can't do ARAP via SENDAUTH. We'll
         * have to do it via SENDPASS. Return a down-rev reply
         * packet and hope the NAS is smart enough to deal with it.
@@ -145,7 +170,7 @@ struct authen_type *type;
 #ifdef MSCHAP
     case TAC_PLUS_AUTHEN_TYPE_MSCHAP:
 #ifndef MSCHAP_DES
-       /* 
+       /*
         * If we have no des code we can't do MSCHAP via LOGIN. We'll
         * have to do it via SENDPASS. Return a down-rev reply
         * packet and hope the NAS is smart enough to deal with it.
@@ -167,7 +192,7 @@ struct authen_type *type;
        }
 
        /* Version 1 login/[pap|chap|arap].
-        * The username must in the initial START packet 
+        * The username must in the initial START packet
         */
        if (!name[0]) {
            report(LOG_ERR, "%s %s: No user in START packet for PAP/CHAP/ARAP",
@@ -184,7 +209,7 @@ struct authen_type *type;
 
     /* Illegal value combination */
     report(LOG_ERR, "%s: %s %s Illegal packet ver=%d action=%d type=%d",
-          session.peer, 
+          session.peer,
           session.port,
           name ? name : "<unknown>",
           session.version,
@@ -193,6 +218,8 @@ struct authen_type *type;
     return(CHOOSE_FAILED);
 }
 
+static int choose_sendauth TAC_ARGS((struct authen_data *data, struct authen_type *type));
+
 static int
 choose_sendauth(data, type)
 struct authen_data *data;
@@ -204,7 +231,7 @@ struct authen_type *type;
 #ifdef MSCHAP
     case TAC_PLUS_AUTHEN_TYPE_MSCHAP:
 #ifndef MSCHAP_DES
-       /* 
+       /*
         * If we have no des code we can't do MSCHAP via SENDAUTH. We'll
         * have to do it via SENDPASS. Return a down-rev reply
         * packet and hope the NAS is smart enough to deal with it.
@@ -237,7 +264,7 @@ struct authen_type *type;
     }
     /* Illegal value combination */
     report(LOG_ERR, "%s: %s %s Illegal packet ver=%d action=%d type=%d",
-          session.peer, 
+          session.peer,
           session.port,
           name ? name : "<unknown>",
           session.version,
@@ -247,6 +274,8 @@ struct authen_type *type;
     return(CHOOSE_FAILED);
 }
 
+static int choose_sendpass TAC_ARGS((struct authen_data *data, struct authen_type *type));
+
 /* Compatibility routine for (obsolete) minor version == 0 */
 static int
 choose_sendpass(data, type)
@@ -282,13 +311,12 @@ struct authen_type *type;
 
     /* Illegal value combination */
     report(LOG_ERR, "%s: %s %s Illegal packet ver=%d action=%d type=%d",
-          session.peer, 
+          session.peer,
           session.port,
           name ? name : "<unknown>",
-          session.version, 
+          session.version,
           data->action,
           type->authen_type);
 
     return(CHOOSE_FAILED);
 }
-
diff --git a/choose_authen.h b/choose_authen.h
new file mode 100644 (file)
index 0000000..1276494
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef CHOOSE_AUTHEN_H
+#define CHOOSE_AUTHEN_H 1
+
+#include "tac_plus.h"
+
+#include <sys/types.h>         /* for u_* */
+
+
+/*
+ * This structure describes an authentication method.
+ *   authen_name     contains the name of the authentication method.
+ *   authen_func     is a pointer to the authentication function.
+ *   authen_method   numeric value of authentication method
+ */
+
+#define AUTHEN_NAME_SIZE 128
+
+struct authen_data;
+
+struct authen_type {
+    char authen_name[AUTHEN_NAME_SIZE];
+    int (*authen_func) TAC_ARGS((struct authen_data *data));
+    int authen_type;
+};
+
+/*
+ * The authen_data structure is the data structure for passing
+ * information to and from the authentication function
+ * (authen_type.authen_func).
+ */
+
+struct authen_data {
+    struct identity *NAS_id;   /* user identity */
+    char *server_msg;          /* null-terminated output msg */
+
+    int server_dlen;           /* output data length */
+    unsigned char *server_data;        /* output data */
+
+    char *client_msg;          /* null-terminated input msg a user typed */
+
+    int client_dlen;           /* input data length */
+    char *client_data;         /* input data */
+
+    void *method_data;         /* opaque private method data */
+    int action;                        /* what's to be done */
+    int service;               /* calling service */
+    int status;                        /* Authen status */
+    int type;                  /* Authen type */
+    u_char flags;               /* input & output flags fields */
+};
+
+/* return values for  choose_authen(); */
+
+#define CHOOSE_FAILED -1     /* failed to choose an authentication function */
+#define CHOOSE_OK      0     /* successfully chose an authentication function */
+#define CHOOSE_GETUSER 1     /* need a username before choosing */
+#define CHOOSE_BADTYPE 2     /* Invalid preferred authen function specified */
+
+
+extern int choose_authen TAC_ARGS((struct authen_data *data, struct authen_type *type));
+
+
+#endif /* CHOOSE_AUTHEN_H */
diff --git a/config.c b/config.c
deleted file mode 100644 (file)
index 6eaef53..0000000
--- a/config.c
+++ /dev/null
@@ -1,2206 +0,0 @@
-/*
-   Copyright (c) 1995-1998 by Cisco systems, 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 of the
-   software and supporting documentation, the name of Cisco Systems,
-   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 modification,
-   copying and distribution is by permission of Cisco Systems, Inc.
-
-   Cisco Systems, Inc. makes no representations about the suitability
-   of this software for any purpose.  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 "tac_plus.h"
-#include <stdio.h>
-#include <errno.h>
-#include "regexp.h"
-
-/*
-   <config>         := <decl>*
-
-   <decl>           := <top_level_decl> | <user_decl>
-
-   <top_level_decl> := <authen_default> |
-                       accounting file = <string>
-                       default authorization = permit |
-                       key = <string>
-
-   <authen_default> := default authentication = file <filename> 
-#if defined(DB)
-                   | db <string> )
-#endif
-   
-<permission>     := permit | deny
-
-   <filename>       := <string>
-
-   <password>       := <string>
-
-   <user_decl>      := user = <string> {
-                        [ default service = [ permit | deny ] ]
-                        <user_attr>*
-                        <svc>*
-                   }
-
-   <password_spec>  := file <filename> | 
-                      skey | 
-                      cleartext <password> |
-                      des <password> |
-
-#ifdef USE_PAM         
-                      pam <pam_service> |
-#endif                 
-#if defined(DB)                
-                       db <string>
-#endif
-                      nopassword
-
-   <user_attr>      :=   name     = <string> |
-                         login    = <password_spec> |
-                        member   = <string> |
-                        expires  = <string> |
-                        arap     = cleartext <string> |
-                        chap     = cleartext <string> |
-#ifdef MSCHAP
-                        ms-chap  = cleartext <string> |
-#endif
-                        pap      = cleartext <string> |
-                        pap      = des <string> |
-#ifdef USE_PAM 
-                        pap      = pam <pam_service> |
-#endif                 
-                        opap     = cleartext <string> |
-                        global   = cleartext <string> |
-                        msg      = <string>
-                        before authorization = <string> |
-                        after authorization = <string>
-
-   <svc>            := <svc_auth> | <cmd_auth>
-
-   <cmd_auth>       := cmd = <string> {
-                        <cmd-match>*
-                    }
-
-   <cmd-match>      := <permission> <string>
-
-   <svc_auth>       := service = ( exec | arap | slip | ppp protocol = <string> {
-                        [ default attribute = permit ]
-                        <attr_value_pair>*
-                    }
-
-   <attr_value_pair> := [ optional ] <string> = <string>
-
-*/
-
-static char sym_buf[MAX_INPUT_LINE_LEN];       /* parse buffer */
-static int sym_pos=0;           /* current place in sym_buf */
-static int sym_ch;             /* current parse character */
-static int sym_code;           /* parser output */
-static int sym_line = 1;       /* current line number for parsing */
-static FILE *cf = NULL;                /* config file pointer */
-static int sym_error = 0;      /* a parsing error has occurred */
-static int no_user_dflt = 0;   /* default if user doesn't exist */
-static char *authen_default = NULL;    /* top level authentication default */
-static int authen_default_method = 0; /*For method check */
-static char *nopasswd_str = "nopassword";
-
-/* A host definition structure. Currently unused, but when we start
-   configuring host-specific information e.g. per-host keys, this is
-   where it should be kept.
-
-   The first 2 fields (name and hash) are used by the hash table
-   routines to hash this structure into a table.  Do not (re)move them */
-
-struct host {
-    char *name;                        /* host name */
-    void *hash;                        /* hash table next pointer */
-    int line;                  /* line number defined on */
-    char *key;                 /* host spesific key */
-    char *type;                        /* host type         */
-};
-
-/* A user or group definition
-
-   The first 2 fields (name and hash) are used by the hash table
-   routines to hash this structure into a table.  Move them at your
-   peril */
-
-struct user {
-    char *name;                        /* username */
-    void *hash;                        /* hash table next pointer */
-    int line;                  /* line number defined on */
-    long flags;                        /* flags field */
-
-#define FLAG_ISUSER  1         /* this structure represents a user */
-#define FLAG_ISGROUP 2         /* this structure represents a group */
-#define FLAG_SEEN    4         /* for circular definition detection */
-
-    char *full_name;           /* users full name */
-    char *login;               /* Login password */
-    int nopasswd;               /* user requires no password */
-    char *global;              /* password to use if none set */
-    char *member;              /* group we are a member of */
-    char *expires;             /* expiration date */
-    char *arap;                        /* our arap secret */
-    char *pap;                 /* our pap secret */
-    char *opap;                        /* our outbound pap secret */
-    char *chap;                        /* our chap secret */
-#ifdef MSCHAP
-    char *mschap;              /* our mschap secret */
-#endif /* MSCHAP */
-    char *msg;                 /* a message for this user */
-    char *before_author;       /* command to run before authorization */
-    char *after_author;                /* command to run after authorization */
-    int svc_dflt;              /* default authorization behaviour for svc or
-                                * cmd */
-    NODE *svcs;                        /* pointer to svc nodes */
-#ifdef MAXSESS
-    int maxsess;               /* Max sessions/user */
-#endif /* MAXSESS */
-    char *time;                /* Timestamp  */
-};
-
-typedef struct host HOST;
-typedef struct user USER;
-
-/* Only the first 2 fields (name and hash) are used by the hash table
-   routines to hashh structures into a table.
-*/
-
-union hash {
-    struct user u;
-    struct host h;
-};
-
-typedef union hash HASH;
-
-void *grouptable[HASH_TAB_SIZE];/* Table of group declarations */
-void *usertable[HASH_TAB_SIZE];        /* Table of user declarations */
-void *hosttable[HASH_TAB_SIZE];        /* Table of host declarations */
-
-
-static void
- sym_get();
-
-
-#ifdef __STDC__
-#include <stdarg.h>            /* ANSI C, variable length args */
-static void
-parse_error(char *fmt,...)
-#else
-#include <varargs.h>           /* has 'vararg' definitions */
-/* VARARGS2 */
-static void
-parse_error(fmt, va_alist)
-char *fmt;
-
-va_dcl                         /* no terminating semi-colon */
-#endif
-{
-    char msg[256];             /* temporary string */
-    va_list ap;
-
-#ifdef __STDC__
-    va_start(ap, fmt);
-#else
-    va_start(ap);
-#endif
-    vsprintf(msg, fmt, ap);
-    va_end(ap);
-
-    report(LOG_ERR, "%s", msg);
-    fprintf(stderr, "Error: %s\n", msg);
-    tac_exit(1);
-}
-
-char *
-cfg_nodestring(type)
-    int type;
-{
-    switch (type) {
-    default:
-       return ("unknown node type");
-    case N_arg:
-       return ("N_arg");
-    case N_optarg:
-       return ("N_optarg");
-    case N_svc:
-       return ("N_svc");
-    case N_svc_exec:
-       return ("N_svc_exec");
-    case N_svc_slip:
-       return ("N_svc_slip");
-    case N_svc_ppp:
-       return ("N_svc_ppp");
-    case N_svc_arap:
-       return ("N_svc_arap");
-    case N_svc_cmd:
-       return ("N_svc_cmd");
-    case N_permit:
-       return ("N_permit");
-    case N_deny:
-       return ("N_deny");
-    }
-}
-
-static void
-free_attrs(node)
-NODE *node;
-{
-    NODE *next;
-
-    while (node) {
-       switch (node->type) {
-       case N_optarg:
-       case N_arg:
-           if (debug & DEBUG_CLEAN_FLAG)
-               report(LOG_DEBUG, "free_cmd_match %s %s",
-                      cfg_nodestring(node->type),
-                      node->value);
-           break;
-       default:
-           report(LOG_ERR, "Illegal node type %s for free_attrs", 
-                  cfg_nodestring(node->type));
-           return;
-       }
-
-       free(node->value);
-       next = node->next;
-       free(node);
-       node = next;
-    }
-}
-
-static void
-free_cmd_matches(node)
-NODE *node;
-{
-    NODE *next;
-
-    while (node) {
-       if (debug & DEBUG_CLEAN_FLAG)
-           report(LOG_DEBUG, "free_cmd_match %s %s",
-                  cfg_nodestring(node->type),
-                  node->value);
-
-       free(node->value);      /* text */
-       free(node->value1);     /* regexp compiled text */
-       next = node->next;
-       free(node);
-       node = next;
-    }
-}
-
-static void
-free_svcs(node)
-NODE *node;
-{
-    NODE *next;
-
-    while (node) {
-
-       switch (node->type) {
-       case N_svc_cmd:
-           if (debug & DEBUG_CLEAN_FLAG)
-               report(LOG_DEBUG, "free %s %s",
-                      cfg_nodestring(node->type), node->value);
-           free(node->value);  /* cmd name */
-           free_cmd_matches(node->value1);
-           next = node->next;
-           free(node);
-           node = next;
-           continue;
-
-       case N_svc:
-       case N_svc_ppp:
-           free(node->value1);
-           /* FALL-THROUGH */
-       case N_svc_exec:
-       case N_svc_arap:
-       case N_svc_slip:
-           if (debug & DEBUG_CLEAN_FLAG)
-               report(LOG_DEBUG, "free %s", cfg_nodestring(node->type));
-           free_attrs(node->value);
-           next = node->next;
-           free(node);
-           node = next;
-           continue;
-
-       default:
-           report(LOG_ERR, "Illegal node type %d for free_svcs", node->type);
-           return;
-       }
-    }
-}
-
-static void
-free_userstruct(user)
-USER *user;
-{
-    if (debug & DEBUG_CLEAN_FLAG)
-       report(LOG_DEBUG, "free %s %s",
-              (user->flags & FLAG_ISUSER) ? "user" : "group",
-              user->name);
-
-    if (user->name)
-       free(user->name);
-    if (user->full_name)
-       free(user->full_name);
-    if (user->login)
-       free(user->login);
-    if (user->member)
-       free(user->member);
-    if (user->expires)
-       free(user->expires);
-    if (user->time)
-       free(user->time);
-    if (user->arap)
-       free(user->arap);
-    if (user->chap)
-       free(user->chap);
-#ifdef MSCHAP
-    if (user->mschap)
-       free(user->mschap);
-#endif /* MSCHAP */
-    if (user->pap)
-       free(user->pap);
-    if (user->opap)
-       free(user->opap);
-    if (user->global)
-       free(user->global);
-    if (user->msg)
-       free(user->msg);
-    if (user->before_author)
-       free(user->before_author);
-    if (user->after_author)
-       free(user->after_author);
-    free_svcs(user->svcs);
-}
-
-static void
-free_hoststruct(host)
-HOST *host;
-{
-    if (debug & DEBUG_CLEAN_FLAG)
-       report(LOG_DEBUG, "free %s",
-               host->name);
-
-    if (host->name)
-       free(host->name);
-    
-    if (host->key)
-       free(host->key);
-    
-    if (host->type)
-       free(host->type);
-}
-
-/*
- * Exported routines
- */
-
-/* Free all allocated structures preparatory to re-reading the config file */
-void
-cfg_clean_config()
-{
-    int i;
-    USER *entry, *next;
-    HOST *host_entry,*hn;
-
-    if (authen_default) {
-       free(authen_default);
-       authen_default = NULL;
-    }
-   
-   if (authen_default_method) {
-       authen_default_method = 0;
-    }
-
-    if (session.key) {
-       free(session.key);
-       session.key = NULL;
-    }
-
-    if (session.acctfile) {
-       free(session.acctfile);
-       session.acctfile = NULL;
-    }
-    
-    if (session.db_acct) {
-       free(session.db_acct);
-       session.db_acct = NULL;
-    }
-
-    /* clean the hosttable */
-    for (i = 0; i < HASH_TAB_SIZE; i++) {
-       host_entry = (HOST *) hosttable[i];
-       while (host_entry) {
-           hn = host_entry->hash;
-           free_hoststruct(host_entry);
-           free(host_entry);
-           host_entry = hn;
-       }
-       hosttable[i] = NULL;
-    }
-
-    /* the grouptable */
-    for (i = 0; i < HASH_TAB_SIZE; i++) {
-       entry = (USER *) grouptable[i];
-       while (entry) {
-           next = entry->hash;
-           free_userstruct(entry);
-           free(entry);
-           entry = next;
-       }
-       grouptable[i] = NULL;
-    }
-
-    /* the usertable */
-    for (i = 0; i < HASH_TAB_SIZE; i++) {
-       entry = (USER *) usertable[i];
-       while (entry) {
-           next = entry->hash;
-           free_userstruct(entry);
-           free(entry);
-           entry = next;
-       }
-       usertable[i] = NULL;
-    }
-}
-
-static int
-parse_permission()
-{
-    int symbol = sym_code;
-
-    if (sym_code != S_permit && sym_code != S_deny) {
-       parse_error("expecting permit or deny but found '%s' on line %d",
-                   sym_buf, sym_line);
-       return (0);
-    }
-    sym_get();
-
-    return (symbol);
-}
-
-static int
-parse(symbol)
-int symbol;
-
-{
-    if (sym_code != symbol) {
-       parse_error("expecting '%s' but found '%s' on line %d",
-                   (symbol == S_string ? "string" : codestring(symbol)),
-                   sym_buf, sym_line);
-       return (1);
-    }
-    sym_get();
-    return (0);
-}
-
-static int
-parse_opt_svc_default()
-{
-    if (sym_code != S_default) {
-       return (0);
-    }
-
-    parse(S_default);
-    parse(S_svc);
-    parse(S_separator);
-    if (sym_code == S_permit) {
-       parse(S_permit);
-       return (S_permit);
-    }
-    parse(S_deny);
-    return (S_deny);
-}
-
-static int
-parse_opt_attr_default()
-{
-    if (sym_code != S_default)
-       return (S_deny);
-
-    parse(S_default);
-    parse(S_attr);
-    parse(S_separator);
-    parse(S_permit);
-    return (S_permit);
-}
-
-static int parse_user();
-static int parse_host();
-
-static void
- rch();
-
-/*
-   Parse lines in the config file, creating data structures
-   Return 1 on error, otherwise 0 */
-
-static int
-parse_decls()
-{
-    no_user_dflt = 0; /* default if user doesn't exist */
-
-    sym_code = 0;
-    rch();
-
-    bzero(grouptable, sizeof(grouptable));
-    bzero(usertable, sizeof(usertable));
-    bzero(hosttable, sizeof(hosttable)); 
-
-    sym_get();
-
-    /* Top level of parser */
-    while (1) {
-
-       switch (sym_code) {
-       case S_eof:
-           return (0);
-
-       case S_accounting:
-           sym_get();
-           parse(S_file);
-           parse(S_separator);
-           if (session.acctfile) 
-               free(session.acctfile);
-           session.acctfile = tac_strdup(sym_buf);
-           sym_get();
-           continue;
-
-#ifdef DB      
-       case S_db_accounting:
-           sym_get();
-           parse(S_separator);
-           if (session.db_acct) 
-               free(session.db_acct);
-           session.db_acct = tac_strdup(sym_buf);
-           sym_get();
-           continue;
-#endif
-
-       case S_default:
-           sym_get();
-           switch (sym_code) {
-           default:
-               parse_error(
-               "Expecting default authorization/authentication on lines %d",
-                           sym_line);
-               return (1);
-
-           case S_authentication:
-               if (authen_default) {
-                   parse_error(
-                   "Multiply defined authentication default on line %d",
-                               sym_line);
-                   return (1);
-               }
-               parse(S_authentication);
-               parse(S_separator);
-
-               switch(sym_code) {
-                
-               case S_file:
-#ifdef DB
-               case S_db:
-#endif
-#ifdef USE_LDAP
-               case S_ldap;
-#endif
-#ifdef USE_PAM
-               case S_pam:
-#endif
-                authen_default_method = sym_code;
-               break;
-
-               default:
-                parse_error("expecting default_method keyword after 'default authentication = ' on line %d",sym_line);
-               return (1);
-                }
-                sym_get();
-
-               authen_default = tac_strdup(sym_buf);
-               sym_get();
-               continue;
-
-           case S_authorization:
-               parse(S_authorization);
-               parse(S_separator);
-               parse(S_permit);
-               no_user_dflt = S_permit;
-               report(LOG_INFO, 
-                      "default authorization = permit is now deprecated. Please use user = DEFAULT instead");
-               continue;
-           }
-
-       case S_key:
-           /* Process a key declaration. */
-           sym_get();
-           parse(S_separator);
-           if (session.key) {
-               parse_error("multiply defined key on lines %d and %d",
-                           session.keyline, sym_line);
-               return (1);
-           }
-           session.key = tac_strdup(sym_buf);
-           session.keyline = sym_line;
-           sym_get();
-           continue;
-       
-       case S_host:
-           parse_host();
-           continue;
-       
-       case S_user:
-       case S_group:
-           parse_user();
-           continue;
-
-           /* case S_host: parse_host(); continue; */
-
-       default:
-           parse_error("Unrecognised token %s on line %d", sym_buf, sym_line);
-           return (1);
-       }
-    }
-}
-
-static NODE *parse_svcs();
-
-/* Assign a value to a field. Issue an error message and return 1 if
-   it's already been assigned. This is a macro because I was sick of
-   repeating the same code fragment over and over */
-
-#define ASSIGN(field) \
-sym_get(); parse(S_separator); if (field) { \
-       parse_error("Duplicate value for %s %s and %s on line %d", \
-                   codestring(sym_code), field, sym_buf, sym_line); \
-        tac_exit(1); \
-    } \
-    field = tac_strdup(sym_buf);
-
-static int
-parse_host()
-{
-    HOST *h;
-    HOST *host = (HOST *) tac_malloc(sizeof(HOST));
-    int save_sym;
-    char buf[MAX_INPUT_LINE_LEN];
-
-    bzero(host, sizeof(HOST));
-
-    sym_get();
-    parse(S_separator);
-    host->name = tac_strdup(sym_buf);
-    host->line = sym_line;
-    
-    h = hash_add_entry(hosttable, (void *) host);
-    
-    if (h) {
-        parse_error("multiply defined %s on lines %d and %d",
-                    host->name, h->line, sym_line);
-        return (1);
-    }
-
-    sym_get();
-    parse(S_openbra);
-    
-    while (1) {
-       switch (sym_code) {
-        case S_eof:
-            return (0);
-       case S_key:
-           ASSIGN(host->key);
-            sym_get();
-            continue;
-       case S_type:
-           ASSIGN(host->type);
-            sym_get();
-            continue;
-       
-       case S_closebra:
-            parse(S_closebra);
-            return (0);
-
-       default:
-           parse_error("Unrecognised keyword %s for host %s on line %d",
-                        sym_buf, host->name,sym_line);
-
-            return (0);
-        }
-    } /* while */
-} /* finish parse_host */
-
-
-static int
-parse_user()
-{
-    USER *n;
-    int isuser;
-    USER *user = (USER *) tac_malloc(sizeof(USER));
-    int save_sym;
-    char **fieldp;
-    char buf[MAX_INPUT_LINE_LEN];
-
-    bzero(user, sizeof(USER));
-
-    isuser = (sym_code == S_user);
-
-    sym_get();
-    parse(S_separator);
-    user->name = tac_strdup(sym_buf);
-    user->line = sym_line;
-
-    if (isuser) {
-       user->flags |= FLAG_ISUSER;
-       n = hash_add_entry(usertable, (void *) user);
-    } else {
-       user->flags |= FLAG_ISGROUP;
-       n = hash_add_entry(grouptable, (void *) user);
-    }
-
-    if (n) {
-       parse_error("multiply defined %s %s on lines %d and %d",
-                   isuser ? "user" : "group",
-                   user->name, n->line, sym_line);
-       return (1);
-    }
-    sym_get();
-    parse(S_openbra);
-
-    /* Is the default deny for svcs or cmds to be overridden? */
-    user->svc_dflt = parse_opt_svc_default();
-
-    while (1) {
-       switch (sym_code) {
-       case S_eof:
-           return (0);
-       
-       case S_time:
-          ASSIGN(user->time);
-          sym_get(); 
-          continue;
-
-       case S_before:
-           sym_get();
-           parse(S_authorization);
-           if (user->before_author)
-               free(user->before_author);
-           user->before_author = tac_strdup(sym_buf);
-           sym_get();
-           continue;
-
-       case S_after:
-           sym_get();
-           parse(S_authorization);
-           if (user->after_author)
-               free(user->after_author);
-           user->after_author = tac_strdup(sym_buf);
-           sym_get();
-           continue;
-
-       case S_svc:
-       case S_cmd:
-           
-           if (user->svcs) {   
-               /* 
-                * Already parsed some services/commands. Thanks to Gabor Kiss
-                * who found this bug.
-                */
-               NODE *p;
-               for (p=user->svcs; p->next; p=p->next) 
-                   /* NULL STMT */;
-               p->next = parse_svcs();
-           } else {
-               user->svcs = parse_svcs();
-           }
-           continue;
-
-       case S_login:
-           if (user->login) {
-               parse_error("Duplicate value for %s %s and %s on line %d",
-                           codestring(sym_code), user->login,
-                           sym_buf, sym_line);
-               tac_exit(1);
-           }
-           sym_get();
-           parse(S_separator);
-           switch(sym_code) {
-
-           case S_skey:
-               user->login = tac_strdup(sym_buf);
-               break;
-
-           case S_nopasswd:
-               /* set to dummy string, so that we detect a duplicate
-                * password definition attempt
-                */
-               user->login = tac_strdup(nopasswd_str);
-               user->nopasswd = 1;
-               break;
-               
-           case S_file:
-           case S_cleartext:
-           case S_des:
-#ifdef USE_PAM 
-           case S_pam: 
-#endif /* USE_PAM */           
-#ifdef DB
-           case S_db:
-#endif /* USE DB */
-               sprintf(buf, "%s ", sym_buf);
-               sym_get();
-               strcat(buf, sym_buf);
-               user->login = tac_strdup(buf);
-               break;
-       
-           default:
-#ifdef USE_PAM
-               parse_error(
- "expecting 'file', 'cleartext', 'pam'.'nopassword', 'skey', or 'des' keyword after 'login =' on line %d",
-                           sym_line);
-#else  
-               parse_error(
- "expecting 'file', 'cleartext', 'nopassword', 'skey', or 'des' keyword after 'login =' on line %d", 
-                           sym_line);
-#endif /* USE_PAM */                   
-           }
-           sym_get();
-           continue;
-
-       case S_pap:
-           if (user->pap) {
-               parse_error("Duplicate value for %s %s and %s on line %d",
-                           codestring(sym_code), user->pap,
-                           sym_buf, sym_line);
-               tac_exit(1);
-           }
-           sym_get();
-           parse(S_separator);
-           switch(sym_code) {
-
-           case S_cleartext:
-           case S_des:
-#ifdef USE_PAM 
-           case S_pam:
-#endif /*USE_PAM */                    
-               sprintf(buf, "%s ", sym_buf);
-               sym_get();
-               strcat(buf, sym_buf);
-               user->pap = tac_strdup(buf);
-               break;  
-
-               sprintf(buf, "%s ", sym_buf);
-               user->pap = tac_strdup(buf);
-               break;
-
-           default:
-#ifdef USE_PAM
-               parse_error(
- "expecting 'cleartext', 'pam', or 'des' keyword after 'pap =' on line %d",
- sym_line);
-#else
-               parse_error(
- "expecting 'cleartext', or 'des' keyword after 'pap =' on line %d", 
- sym_line);
-#endif /*USE_PAM */
-           }
-           sym_get();
-           continue;
-
-       case S_name:
-           ASSIGN(user->full_name);
-           sym_get();
-           continue;
-
-       case S_member:
-           ASSIGN(user->member);
-           sym_get();
-           continue;
-       
-
-       case S_expires:
-           ASSIGN(user->expires);
-           sym_get();
-           continue;
-       
-       case S_message:
-           ASSIGN(user->msg);
-           sym_get();
-           continue;
-
-       case S_arap:
-       case S_chap:
-#ifdef MSCHAP
-       case S_mschap:
-#endif /* MSCHAP */
-       case S_opap:
-       case S_global:
-           save_sym = sym_code;
-           sym_get(); 
-           parse(S_separator); 
-           sprintf(buf, "%s ", sym_buf);
-           parse(S_cleartext);
-           strcat(buf, sym_buf);
-
-           if (save_sym == S_arap)
-               fieldp = &user->arap;
-           if (save_sym == S_chap)
-               fieldp = &user->chap;
-#ifdef MSCHAP
-           if (save_sym == S_mschap)
-               fieldp = &user->mschap;
-#endif /* MSCHAP */
-           if (save_sym == S_pap)
-               fieldp = &user->pap;
-           if (save_sym == S_opap)
-               fieldp = &user->opap;
-           if (save_sym == S_global)
-               fieldp = &user->global;
-
-           if (*fieldp) {
-               parse_error("Duplicate value for %s %s and %s on line %d",
-                           codestring(save_sym), *fieldp, sym_buf, sym_line);
-               tac_exit(1);
-           }
-           *fieldp = tac_strdup(buf);
-           sym_get();
-           continue;
-
-       case S_closebra:
-           parse(S_closebra);
-           return (0);
-
-#ifdef MAXSESS
-       case S_maxsess:
-           sym_get(); 
-           parse(S_separator);
-           if (sscanf(sym_buf, "%d", &user->maxsess) != 1) {
-               parse_error("expecting integer, found '%s' on line %d",
-                   sym_buf, sym_line);
-           }
-           sym_get();
-           continue;
-#endif /* MAXSESS */
-       default:
-           if (STREQ(sym_buf, "password")) {
-               fprintf(stderr,
-                       "\npassword = <string> is obsolete. Use login = des <string>\n");
-           }
-           parse_error("Unrecognised keyword %s for user on line %d",
-                       sym_buf, sym_line);
-
-           return (0);
-       }
-    }
-}
-
-static NODE *parse_attrs();
-static NODE *parse_cmd_matches();
-
-static NODE *
-parse_svcs()
-{
-    NODE *result;
-
-    switch (sym_code) {
-    default:
-       return (NULL);
-    case S_svc:
-    case S_cmd:
-       break;
-    }
-
-    result = (NODE *) tac_malloc(sizeof(NODE));
-
-    bzero(result, sizeof(NODE));
-    result->line = sym_line;
-
-    /* cmd declaration */
-    if (sym_code == S_cmd) {
-       parse(S_cmd);
-       parse(S_separator);
-       result->value = tac_strdup(sym_buf);
-
-       sym_get();
-       parse(S_openbra);
-
-       result->value1 = parse_cmd_matches();
-       result->type = N_svc_cmd;
-
-       parse(S_closebra);
-       result->next = parse_svcs();
-       return (result);
-    }
-
-    /* svc declaration */
-    parse(S_svc);
-    parse(S_separator);
-    switch (sym_code) {
-    default:
-       parse_error("expecting service type but found %s on line %d",
-                   sym_buf, sym_line);
-       return (NULL);
-
-    case S_string:
-       result->type = N_svc;
-       /* should perhaps check that this is an allowable service name */
-       result->value1 = tac_strdup(sym_buf);
-       break;
-    case S_exec:
-       result->type = N_svc_exec;
-       break;
-    case S_arap:
-       result->type = N_svc_arap;
-       break;
-    case S_slip:
-       result->type = N_svc_slip;
-       break;
-    case S_ppp:
-       result->type = N_svc_ppp;
-       parse(S_ppp);
-       parse(S_protocol);
-       parse(S_separator);
-       /* Should perhaps check that this is a known PPP protocol name */
-       result->value1 = tac_strdup(sym_buf);
-       break;
-    }
-    sym_get();
-    parse(S_openbra);
-    result->dflt = parse_opt_attr_default();
-    result->value = parse_attrs();
-    parse(S_closebra);
-    result->next = parse_svcs();
-    return (result);
-}
-
-/*  <cmd-match>         := <permission> <string> */
-
-static NODE *
-parse_cmd_matches()
-{
-    NODE *result;
-
-    if (sym_code != S_permit && sym_code != S_deny) {
-       return (NULL);
-    }
-    result = (NODE *) tac_malloc(sizeof(NODE));
-
-    bzero(result, sizeof(NODE));
-    result->line = sym_line;
-
-    result->type = (parse_permission() == S_permit) ? N_permit : N_deny;
-    result->value = tac_strdup(sym_buf);
-
-    result->value1 = (void *) regcomp(result->value);
-    if (!result->value1) {
-       report(LOG_ERR, "in regular expression %s on line %d",
-              sym_buf, sym_line);
-       tac_exit(1);
-    }
-    sym_get();
-
-    result->next = parse_cmd_matches();
-
-    return (result);
-}
-
-static NODE *
-parse_attrs()
-{
-    NODE *result;
-    char buf[MAX_INPUT_LINE_LEN];
-    int optional = 0;
-
-    if (sym_code == S_closebra) {
-       return (NULL);
-    }
-    result = (NODE *) tac_malloc(sizeof(NODE));
-
-    bzero(result, sizeof(NODE));
-    result->line = sym_line;
-
-    if (sym_code == S_optional) {
-       optional++;
-       sym_get();
-    }
-    result->type = optional ? N_optarg : N_arg;
-
-    strcpy(buf, sym_buf);
-    parse(S_string);
-    strcat(buf, sym_buf);
-    parse(S_separator);
-    strcat(buf, sym_buf);
-    parse(S_string);
-
-    result->value = tac_strdup(buf);
-    result->next = parse_attrs();
-    return (result);
-}
-
-
-static void
- getsym();
-
-static void
-sym_get()
-{
-    getsym();
-
-    if (debug & DEBUG_PARSE_FLAG) {
-       report(LOG_DEBUG, "line=%d sym=%s code=%d buf='%s'",
-              sym_line, codestring(sym_code), sym_code, sym_buf);
-    }
-}
-
-static char *
-sym_buf_add(c)
-char c;
-{
-    if (sym_pos >= MAX_INPUT_LINE_LEN) {
-       sym_buf[MAX_INPUT_LINE_LEN-1] = '\0';
-       if (debug & DEBUG_PARSE_FLAG) {
-           report(LOG_DEBUG, "line too long: line=%d sym=%s code=%d buf='%s'",
-                  sym_line, codestring(sym_code), sym_code, sym_buf);
-       }
-       return(NULL);
-    }
-
-    sym_buf[sym_pos++] = c;
-    return(sym_buf);
-}
-    
-static void
-getsym()
-{
-
-next:
-    switch (sym_ch) {
-
-    case EOF:
-       sym_code = S_eof;
-       return;
-
-    case '\n':
-       sym_line++;
-       rch();
-       goto next;
-
-    case '\t':
-    case ' ':
-       while (sym_ch == ' ' || sym_ch == '\t')
-           rch();
-       goto next;
-
-    case '=':
-       strcpy(sym_buf, "=");
-       sym_code = S_separator;
-       rch();
-       return;
-
-    case '{':
-       strcpy(sym_buf, "{");
-       sym_code = S_openbra;
-       rch();
-       return;
-
-    case '}':
-       strcpy(sym_buf, "}");
-       sym_code = S_closebra;
-       rch();
-       return;
-
-    case '#':
-       while ((sym_ch != '\n') && (sym_ch != EOF))
-           rch();
-       goto next;
-
-    case '"':
-       rch();
-       sym_pos = 0;
-       while (1) {
-
-           if (sym_ch == '"') {
-               break;
-           }
-
-           /* backslash-double-quote is supported inside strings */
-           /* also allow \n */
-           if (sym_ch == '\\') {
-               rch();
-               switch (sym_ch) {
-               case 'n':
-                   /* preserve the slash for \n */
-                   if (!sym_buf_add('\\')) {
-                       sym_code = S_unknown;
-                       rch();
-                       return;
-                   }
-                   
-                   /* fall through */
-               case '"':
-                   if (!sym_buf_add(sym_ch)) {
-                       sym_code = S_unknown;
-                       rch();
-                       return;
-                   }
-                   rch();
-                   continue;
-               default:
-                   sym_code = S_unknown;
-                   rch();
-                   return;
-               }
-           }
-           if (!sym_buf_add(sym_ch)) {
-               sym_code = S_unknown;
-               rch();
-               return;
-           }
-           rch();
-       }
-       rch();
-
-       if (!sym_buf_add('\0')) {
-           sym_code = S_unknown;
-           rch();
-           return;
-       }
-       sym_code = S_string;
-       return;
-
-    default:
-       sym_pos = 0;
-       while (sym_ch != '\t' && sym_ch != ' ' && sym_ch != '='
-              && sym_ch != '\n') {
-
-           if (!sym_buf_add(sym_ch)) {
-               sym_code = S_unknown;
-               rch();
-               return;
-           }
-           rch();
-       }
-
-       if (!sym_buf_add('\0')) {
-           sym_code = S_unknown;
-           rch();
-           return;
-       }
-       sym_code = keycode(sym_buf);
-       if (sym_code == S_unknown)
-           sym_code = S_string;
-       return;
-    }
-}
-
-static void
-rch()
-{
-    if (sym_error) {
-       sym_ch = EOF;
-       return;
-    }
-    sym_ch = getc(cf);
-
-    if (parse_only && sym_ch != EOF)
-       fprintf(stderr, "%c", sym_ch);
-}
-
-
-/* For a user or group, find the value of a field. Does not recurse. */
-VALUE
-get_value(user, field)
-USER *user;
-int field;
-{
-    VALUE v;
-
-    v.intval = 0;
-
-    if (!user) {
-       parse_error("get_value: illegal user");
-       return (v);
-    }
-    switch (field) {
-
-    case S_name:
-       v.pval = user->name;
-       break;
-
-    case S_login:
-       v.pval = user->login;
-       break;
-
-    case S_global:
-       v.pval = user->global;
-       break;
-
-    case S_member:
-       v.pval = user->member;
-       break;
-
-    case S_expires:
-       v.pval = user->expires;
-       break;
-
-    case S_arap:
-       v.pval = user->arap;
-       break;
-
-    case S_chap:
-       v.pval = user->chap;
-       break;
-
-#ifdef MSCHAP
-    case S_mschap:
-       v.pval = user->mschap;
-       break;
-#endif /* MSCHAP */
-
-    case S_pap:
-       v.pval = user->pap;
-       break;
-
-    case S_opap:
-       v.pval = user->opap;
-       break;
-
-    case S_message:
-       v.pval = user->msg;
-       break;
-
-    case S_svc:
-       v.pval = user->svcs;
-       break;
-
-    case S_before:
-       v.pval = user->before_author;
-       break;
-
-    case S_after:
-       v.pval = user->after_author;
-       break;
-
-    case S_svc_dflt:
-       v.intval = user->svc_dflt;
-       break;
-
-#ifdef MAXSESS
-    case S_maxsess:
-       v.intval = user->maxsess;
-       break;
-#endif 
-
-    case S_nopasswd:
-       v.intval = user->nopasswd;
-       break;
-       
-    case S_time:
-       v.pval = user->time;
-       break;
-
-    default:
-       report(LOG_ERR, "get_value: unknown field %d", field);
-       break;
-    }
-    return (v);
-}
-
-/* For host , find value of field. Doesn't recursive */
-VALUE
-get_hvalue(host, field)
-HOST *host;
-int field;
-{
-    VALUE v;
-    v.intval = 0;
-    if(!host) {
-       parse_error("get_hvalue: illegal host");
-        return (v);
-    }
-    switch (field) {
-       case S_name:
-        v.pval = host->name;
-        break;
-       
-       case S_key:
-       v.pval = host->key;
-       break;
-       
-       default:
-        report(LOG_ERR, "get_value: unknown field %d", field);
-        break;
-    }
-    return (v);
-}
-
-
-/* For each user, check she doesn't circularly reference a
-   group. Return 1 if it does */
-static int
-circularity_check()
-{
-    USER *user, *entry, *group;
-    USER **users = (USER **) hash_get_entries(usertable);
-    USER **groups = (USER **) hash_get_entries(grouptable);
-    USER **p, **q;
-
-    /* users */
-    for (p = users; *p; p++) {
-       user = *p;
-
-       if (debug & DEBUG_PARSE_FLAG)
-           report(LOG_DEBUG, "circularity_check: user=%s", user->name);
-
-       /* Initialise all groups "seen" flags to zero */
-       for (q = groups; *q; q++) {
-           group = *q;
-           group->flags &= ~FLAG_SEEN;
-       }
-
-       entry = user;
-
-       while (entry) {
-           /* check groups we are a member of */
-           char *groupname = entry->member;
-
-           if (debug & DEBUG_PARSE_FLAG)
-               report(LOG_DEBUG, "\tmember of group %s",
-                      groupname ? groupname : "<none>");
-
-
-           /* if not a member of any groups, go on to next user */
-           if (!groupname)
-               break;
-
-           group = (USER *) hash_lookup(grouptable, groupname);
-           if (!group) {
-               report(LOG_ERR, "%s=%s, group %s does not exist",
-                      (entry->flags & FLAG_ISUSER) ? "user" : "group",
-                      entry->name, groupname);
-               free(users);
-               free(groups);
-               return (1);
-           }
-           if (group->flags & FLAG_SEEN) {
-               report(LOG_ERR, "recursively defined groups");
-
-               /* print all seen "groups" */
-               for (q = groups; *q; q++) {
-                   group = *q;
-                   if (group->flags & FLAG_SEEN)
-                       report(LOG_ERR, "%s", group->name);
-               }
-               free(users);
-               free(groups);
-               return (1);
-           }
-           group->flags |= FLAG_SEEN;  /* mark group as seen */
-           entry = group;
-       }
-    }
-    free(users);
-    free(groups);
-    return (0);
-}
-
-
-/* Return a value for a group or user (isuser says if
-   this name is a group or a user name).
-
-   If no value exists, and recurse is true, also check groups we are a
-   member of, recursively.
-
-   Returns void * because it can return a string or a node pointer
-   (should really return a union pointer).
-*/
-static VALUE
-cfg_get_value(name, isuser, attr, recurse)
-char *name;
-int isuser, attr, recurse;
-{
-    USER *user, *group;
-    VALUE value;
-
-    value.pval = NULL;
-
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_get_value: name=%s isuser=%d attr=%s rec=%d",
-              name, isuser, codestring(attr), recurse);
-
-    /* find the user/group entry */
-
-    user = (USER *) hash_lookup(isuser ? usertable : grouptable, name);
-
-    if (!user) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_value: no user/group named %s", name);
-       return (value);
-    }
-
-    /* found the entry. Lookup value from attr=value */
-    value = get_value(user, attr);
-
-    if (value.pval || !recurse) {
-       return (value);
-    }
-    /* no value. Check containing group */
-    if (user->member)
-       group = (USER *) hash_lookup(grouptable, user->member);
-    else
-       group = NULL;
-
-    while (group) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_value: recurse group = %s",
-                  group->name);
-
-       value = get_value(group, attr);
-
-       if (value.pval) {
-           return (value);
-       }
-       /* still nothing. Check containing group and so on */
-
-       if (group->member)
-           group = (USER *) hash_lookup(grouptable, group->member);
-       else
-           group = NULL;
-    }
-
-    /* no value for this user or her containing groups */
-    value.pval = NULL;
-    return (value);
-}
-
-
-/* Wrappers for cfg_get_value */
-int
-cfg_get_intvalue(name, isuser, attr, recurse)
-char *name;
-int isuser, attr, recurse;
-{
-    int val = cfg_get_value(name, isuser, attr, recurse).intval;
-
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_get_intvalue: returns %d", val);
-    return(val);
-}
-
-char *
-cfg_get_pvalue(name, isuser, attr, recurse)
-char *name;
-int isuser, attr, recurse;
-{
-    char *p = cfg_get_value(name, isuser, attr, recurse).pval;
-
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_get_pvalue: returns %s", 
-              p ? p : "NULL");
-    return(p);
-}
-
-/* For getting host values */
-static VALUE
-cfg_get_hvalue(name, attr)
-char *name;
-int attr;
-{
-    HOST *host;
-    VALUE value;
-
-    value.pval = NULL;
-    if (debug & DEBUG_CONFIG_FLAG)
-        report(LOG_DEBUG, "cfg_get_hvalue: name=%s attr=%s ",
-               name, codestring(attr));
-    
-    /* find the host entry in hash table */
-
-    host = (HOST *) hash_lookup( hosttable, name);
-
-    if (!host) {
-        if (debug & DEBUG_CONFIG_FLAG)
-            report(LOG_DEBUG, "cfg_get_hvalue: no host named %s", name);
-        return (value);
-    }
-
-    /* found the entry. Lookup value from attr=value */
-    value = get_hvalue(host, attr);
-
-    if (value.pval) {
-        return (value);
-    }
-    /* No any value for this host */    
-    value.pval = NULL;
-    return (value);
-}
-
-/* Wrappers for cfg_get_hvalue */
-char *
-cfg_get_phvalue(name, attr)
-char *name;
-int attr;
-{
-    char *p = cfg_get_hvalue(name, attr).pval;
-
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_get_phvalue: returns %s", 
-              p ? p : "NULL");
-    return(p);
-}
-
-/*
-   Read the config file and do some basic sanity checking on
-   it. Return 1 if we find any errors. */
-
-cfg_read_config(cfile)
-char *cfile;
-{
-    sym_line = 1;
-
-    if ((cf = fopen(cfile, "r")) == NULL) {
-       report(LOG_ERR, "read_config: fopen() error for file %s %s, exiting",
-              cfile, sys_errlist[errno]);
-       return (1);
-    }
-    if (parse_decls() || sym_error) {
-       fclose(cf);
-       return (1);
-    }
-
-    if (circularity_check()) {
-       fclose(cf);
-       return (1);
-    }
-
-    fclose(cf);
-    return (0);
-}
-
-/* return 1 if user exists, 0 otherwise */
-int
-cfg_user_exists(username)
-char *username;
-{
-    USER *user = (USER *) hash_lookup(usertable, username);
-
-    return (user != NULL);
-}
-
-/* return expiry string of user. If none, try groups she is a member
-   on, and so on, recursively if recurse is non-zero */
-char *
-cfg_get_expires(username, recurse)
-char *username;
-
-{
-    return (cfg_get_pvalue(username, TAC_IS_USER, S_expires, recurse));
-}
-
-/* return time string of user. If none, try groups she is a member
-   on, and so on, recursively if recurse is non-zero */
-char *
-cfg_get_timestamp(username, recurse)
-char *username;
-{
-    return (cfg_get_pvalue(username, TAC_IS_USER, S_time, recurse));
-}
-
-
-/* return password string of user. If none, try groups she is a member
-   on, and so on, recursively if recurse is non-zero */
-char *
-cfg_get_login_secret(user, recurse)
-char *user;
-
-{
-    return (cfg_get_pvalue(user, TAC_IS_USER, S_login, recurse));
-}
-
-/* return value of the nopasswd field. If none, try groups she is a member
-   on, and so on, recursively if recurse is non-zero */
-int
-cfg_get_user_nopasswd(user, recurse)
-    char *user;
-{
-    return (cfg_get_intvalue(user, TAC_IS_USER, S_nopasswd, recurse));
-}
-
-/* return user's secret. If none, try groups she is a member
-   on, and so on, recursively if recurse is non-zero */
-char *
-cfg_get_arap_secret(user, recurse)
-char *user;
-
-{
-    return (cfg_get_pvalue(user, TAC_IS_USER, S_arap, recurse));
-}
-
-char *
-cfg_get_chap_secret(user, recurse)
-char *user;
-
-{
-    return (cfg_get_pvalue(user, TAC_IS_USER, S_chap, recurse));
-}
-
-#ifdef MSCHAP
-char *
-cfg_get_mschap_secret(user, recurse)
-char *user;
-
-{
-    return (cfg_get_pvalue(user, TAC_IS_USER, S_mschap, recurse));
-}
-#endif /* MSCHAP */
-
-char *
-cfg_get_pap_secret(user, recurse)
-char *user;
-{
-    return (cfg_get_pvalue(user, TAC_IS_USER, S_pap, recurse));
-}
-
-char *
-cfg_get_opap_secret(user, recurse)
-char *user;
-{
-    return (cfg_get_pvalue(user, TAC_IS_USER, S_opap, recurse));
-}
-
-/* return the global password for the user (or the group, etc.) */
-
-char *
-cfg_get_global_secret(user, recurse)
-char *user;
-
-{
-    return (cfg_get_pvalue(user, TAC_IS_USER, S_global, recurse));
-}
-
-#ifdef USE_PAM
-/* Return a pointer to a node representing a PAM Service name */
-char *
-cfg_get_pam_service(user,recurse)
-char *user;
-
-{
- char *cfg_passwd;
- char *p;   
-
-cfg_passwd = cfg_get_pap_secret(user, recurse);
-if (!cfg_passwd) {
-               cfg_passwd = cfg_get_global_secret(user, recurse);
-}
-if (!cfg_passwd && !cfg_user_exists(user)) {
-        cfg_passwd = cfg_get_authen_default();
-        switch (cfg_get_authen_default_method()) {
-               case (S_pam): 
-                       if (debug & DEBUG_AUTHOR_FLAG)
-                        report(LOG_DEBUG, "Get Default PAM Service :%s",cfg_passwd);
-                       return(cfg_passwd);
-                       break;
-               default:
-                       if (debug & DEBUG_AUTHOR_FLAG)
-                        report(LOG_DEBUG, "I havent find any PAM Service!!");
-                       return(NULL);/* Haven't any PAM Service!! */
-       }
-}
-
-p=tac_find_substring("pam ", cfg_passwd);
-
-if(p) {  /* We find PAM services */
-       if (debug & DEBUG_AUTHOR_FLAG)
-               report(LOG_DEBUG, "I get PAM sevice:%s",p);
-return (p);
-}
-
-if (debug & DEBUG_AUTHOR_FLAG)
-       report(LOG_DEBUG, "No any PAM Sevice");
-
-return(NULL);
-}
-
-#endif /* For PAM */
-       
-
-
-/* Return a pointer to a node representing a given service
-   authorization, taking care of recursion issues correctly. Protocol
-   is only read if the type is N_svc_ppp. svcname is only read if type
-   is N_svc.
-*/
-
-NODE *
-cfg_get_svc_node(username, type, protocol, svcname, recurse)
-char *username;
-int type;
-char *protocol, *svcname;
-int recurse;
-{
-    USER *user, *group;
-    NODE *svc;
-
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, 
-              "cfg_get_svc_node: username=%s %s proto=%s svcname=%s rec=%d",
-              username, 
-              cfg_nodestring(type), 
-              protocol ? protocol : "", 
-              svcname ? svcname : "", 
-              recurse);
-
-    /* find the user/group entry */
-    user = (USER *) hash_lookup(usertable, username);
-
-    if (!user) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_svc_node: no user named %s", username);
-       return (NULL);
-    }
-
-    /* found the user entry. Find svc node */
-    for(svc = (NODE *) get_value(user, S_svc).pval; svc; svc = svc->next) {
-
-       if (svc->type != type) 
-           continue;
-
-       if (type == N_svc_ppp && !STREQ(svc->value1, protocol)) {
-           continue;
-       }
-
-       if (type == N_svc && !STREQ(svc->value1, svcname)) {
-           continue;
-       }
-
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, 
-                  "cfg_get_svc_node: found %s proto=%s svcname=%s",
-                  cfg_nodestring(type), 
-                  protocol ? protocol : "", 
-                  svcname ? svcname : "");
-
-       return(svc);
-    }
-
-    if (!recurse) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_svc_node: returns NULL");
-       return (NULL);
-    }
-
-    /* no matching node. Check containing group */
-    if (user->member)
-       group = (USER *) hash_lookup(grouptable, user->member);
-    else
-       group = NULL;
-
-    while (group) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_svc_node: recurse group = %s",
-                  group->name);
-
-       for(svc = (NODE *) get_value(group, S_svc).pval; svc; svc = svc->next) {
-
-           if (svc->type != type) 
-               continue;
-
-           if (type == N_svc_ppp && !STREQ(svc->value1, protocol)) {
-               continue;
-           }
-
-           if (type == N_svc && !STREQ(svc->value1, svcname)) {
-               continue;
-           }
-
-           if (debug & DEBUG_CONFIG_FLAG)
-               report(LOG_DEBUG, 
-                      "cfg_get_svc_node: found %s proto=%s svcname=%s",
-                      cfg_nodestring(type), 
-                      protocol ? protocol : "", 
-                      svcname ? svcname : "");
-
-           return(svc);
-       }
-
-       /* still nothing. Check containing group and so on */
-
-       if (group->member)
-           group = (USER *) hash_lookup(grouptable, group->member);
-       else
-           group = NULL;
-    }
-
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_get_svc_node: returns NULL");
-
-    /* no matching svc node for this user or her containing groups */
-    return (NULL);
-}
-
-/* Return a pointer to the node representing a set of command regexp
-   matches for a user and command, handling recursion issues correctly */
-NODE *
-cfg_get_cmd_node(name, cmdname, recurse)
-char *name, *cmdname;
-int recurse;
-
-{
-    USER *user, *group;
-    NODE *svc;
-
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_get_cmd_node: name=%s cmdname=%s rec=%d",
-              name, cmdname, recurse);
-
-    /* find the user/group entry */
-    user = (USER *) hash_lookup(usertable, name);
-
-    if (!user) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_cmd_node: no user named %s", name);
-       return (NULL);
-    }
-    /* found the user entry. Find svc node */
-    svc = (NODE *) get_value(user, S_svc).pval;
-
-    while (svc) {
-       if (svc->type == N_svc_cmd && STREQ(svc->value, cmdname)) {
-           if (debug & DEBUG_CONFIG_FLAG)
-               report(LOG_DEBUG, "cfg_get_cmd_node: found cmd %s %s node",
-                      cmdname, cfg_nodestring(svc->type));
-           return (svc);
-       }
-       svc = svc->next;
-    }
-
-    if (!recurse) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_cmd_node: returns NULL");
-       return (NULL);
-    }
-    /* no matching node. Check containing group */
-    if (user->member)
-       group = (USER *) hash_lookup(grouptable, user->member);
-    else
-       group = NULL;
-
-    while (group) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_get_cmd_node: recurse group = %s",
-                  group->name);
-
-       svc = get_value(group, S_svc).pval;
-
-       while (svc) {
-           if (svc->type == N_svc_cmd && STREQ(svc->value, cmdname)) {
-               if (debug & DEBUG_CONFIG_FLAG)
-                   report(LOG_DEBUG, "cfg_get_cmd_node: found cmd %s node %s",
-                          cmdname, cfg_nodestring(svc->type));
-               return (svc);
-           }
-           svc = svc->next;
-       }
-
-       /* still nothing. Check containing group and so on */
-
-       if (group->member)
-           group = (USER *) hash_lookup(grouptable, group->member);
-       else
-           group = NULL;
-    }
-
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_get_cmd_node: returns NULL");
-
-    /* no matching cmd node for this user or her containing groups */
-    return (NULL);
-}
-
-/* Return an array of character strings representing configured AV
- * pairs, given a username and a service node. 
- *
- * In the AV strings returned, manipulate the separator character to
- * indicate which args are optional and which are mandatory.
- *
- * Lastly, indicate what default permission was configured by setting
- * denyp */
-
-char **
-cfg_get_svc_attrs(svcnode, denyp)
-NODE *svcnode;
-int *denyp;
-{
-    int i;
-    NODE *node;
-    char **args;
-
-    *denyp = 1;
-
-    if (!svcnode)
-       return (NULL);
-
-    *denyp = (svcnode->dflt == S_deny);
-
-    i = 0;
-    for (node = svcnode->value; node; node = node->next)
-       i++;
-
-    args = (char **) tac_malloc(sizeof(char *) * (i + 1));
-
-    i = 0;
-    for (node = svcnode->value; node; node = node->next) {
-       char *arg = tac_strdup(node->value);
-       char *p = index(arg, '=');
-
-       if (p && node->type == N_optarg)
-           *p = '*';
-       args[i++] = arg;
-    }
-    args[i] = NULL;
-    return (args);
-}
-
-
-int
-cfg_user_svc_default_is_permit(user)
-char *user;
-
-{
-    int permit = cfg_get_intvalue(user, TAC_IS_USER, S_svc_dflt,
-                              TAC_PLUS_RECURSE);
-
-    switch (permit) {
-    default:                   /* default is deny */
-    case S_deny:
-       return (0);
-    case S_permit:
-       return (1);
-    }
-}
-
-int
-cfg_no_user_permitted()
-{
-    if (no_user_dflt == S_permit)
-       return (1);
-    return (0);
-}
-
-
-char *
-cfg_get_authen_default()
-{
-    return (authen_default);
-}
-
-/* For describe authentication method(pam,file,db..etc) */
-int 
-cfg_get_authen_default_method()
-{
-   return (authen_default_method);
-}
-
-
-/* Return 1 if this user has any ppp services configured. Used for
-   authorizing ppp/lcp requests */
-int
-cfg_ppp_is_configured(username, recurse)
-    char *username;
-    int recurse;
-{
-    USER *user, *group;
-    NODE *svc;
-
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_ppp_is_configured: username=%s rec=%d",
-              username, recurse);
-
-    /* find the user/group entry */
-    user = (USER *) hash_lookup(usertable, username);
-
-    if (!user) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_ppp_is_configured: no user named %s", 
-                  username);
-       return (0);
-    }
-
-    /* found the user entry. Find svc node */
-    for(svc = (NODE *) get_value(user, S_svc).pval; svc; svc = svc->next) {
-
-       if (svc->type != N_svc_ppp) 
-           continue;
-
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_ppp_is_configured: found svc ppp %s node",
-                  svc->value1);
-       
-       return(1);
-    }
-
-    if (!recurse) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_ppp_is_configured: returns 0");
-       return (0);
-    }
-
-    /* no matching node. Check containing group */
-    if (user->member)
-       group = (USER *) hash_lookup(grouptable, user->member);
-    else
-       group = NULL;
-
-    while (group) {
-       if (debug & DEBUG_CONFIG_FLAG)
-           report(LOG_DEBUG, "cfg_ppp_is_configured: recurse group = %s",
-                  group->name);
-
-       for(svc = (NODE *) get_value(group, S_svc).pval; svc; svc = svc->next) {
-
-           if (svc->type != N_svc_ppp)
-               continue;
-
-           if (debug & DEBUG_CONFIG_FLAG)
-               report(LOG_DEBUG, "cfg_ppp_is_configured: found svc ppp %s node",
-                      svc->value1);
-       
-           return(1);
-       }
-
-       /* still nothing. Check containing group and so on */
-
-       if (group->member)
-           group = (USER *) hash_lookup(grouptable, group->member);
-       else
-           group = NULL;
-    }
-
-    if (debug & DEBUG_CONFIG_FLAG)
-       report(LOG_DEBUG, "cfg_ppp_is_configured: returns 0");
-
-    /* no PPP svc nodes for this user or her containing groups */
-    return (0);
-}
-
-/* For getting host key */
-char *
-cfg_get_host_key(host)
-char *host;
-{
-    return (cfg_get_phvalue(host, S_key));
-}
-
diff --git a/config.guess b/config.guess
deleted file mode 100644 (file)
index e1b5871..0000000
+++ /dev/null
@@ -1,1121 +0,0 @@
-#! /bin/sh
-# Attempt to guess a canonical system name.
-#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999
-#   Free Software Foundation, Inc.
-#
-# This file is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Written by Per Bothner <bothner@cygnus.com>.
-# The master version of this file is at the FSF in /home/gd/gnu/lib.
-# Please send patches to <autoconf-patches@gnu.org>.
-#
-# This script attempts to guess a canonical system name similar to
-# config.sub.  If it succeeds, it prints the system name on stdout, and
-# exits with 0.  Otherwise, it exits with 1.
-#
-# The plan is that this can be called by configure scripts if you
-# don't specify an explicit system type (host/target name).
-#
-# Only a few systems have been added to this list; please add others
-# (but try to keep the structure clean).
-#
-
-# Use $HOST_CC if defined. $CC may point to a cross-compiler
-if test x"$CC_FOR_BUILD" = x; then
-  if test x"$HOST_CC" != x; then
-    CC_FOR_BUILD="$HOST_CC"
-  else
-    if test x"$CC" != x; then
-      CC_FOR_BUILD="$CC"
-    else
-      CC_FOR_BUILD=cc
-    fi
-  fi
-fi
-
-
-# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
-# (ghazi@noc.rutgers.edu 8/24/94.)
-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
-       PATH=$PATH:/.attbin ; export PATH
-fi
-
-UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
-UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
-UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
-
-dummy=dummy-$$
-trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15
-
-# Note: order is significant - the case branches are not exclusive.
-
-case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
-    alpha:OSF1:*:*)
-       if test $UNAME_RELEASE = "V4.0"; then
-               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
-       fi
-       # A Vn.n version is a released version.
-       # A Tn.n version is a released field test version.
-       # A Xn.n version is an unreleased experimental baselevel.
-       # 1.2 uses "1.2" for uname -r.
-       cat <<EOF >$dummy.s
-       .globl main
-       .ent main
-main:
-       .frame \$30,0,\$26,0
-       .prologue 0
-       .long 0x47e03d80 # implver $0
-       lda \$2,259
-       .long 0x47e20c21 # amask $2,$1
-       srl \$1,8,\$2
-       sll \$2,2,\$2
-       sll \$0,3,\$0
-       addl \$1,\$0,\$0
-       addl \$2,\$0,\$0
-       ret \$31,(\$26),1
-       .end main
-EOF
-       $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
-       if test "$?" = 0 ; then
-               ./$dummy
-               case "$?" in
-                       7)
-                               UNAME_MACHINE="alpha"
-                               ;;
-                       15)
-                               UNAME_MACHINE="alphaev5"
-                               ;;
-                       14)
-                               UNAME_MACHINE="alphaev56"
-                               ;;
-                       10)
-                               UNAME_MACHINE="alphapca56"
-                               ;;
-                       16)
-                               UNAME_MACHINE="alphaev6"
-                               ;;
-               esac
-       fi
-       rm -f $dummy.s $dummy
-       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-       exit 0 ;;
-    Alpha\ *:Windows_NT*:*)
-       # How do we know it's Interix rather than the generic POSIX subsystem?
-       # Should we change UNAME_MACHINE based on the output of uname instead
-       # of the specific Alpha model?
-       echo alpha-pc-interix
-       exit 0 ;;
-    21064:Windows_NT:50:3)
-       echo alpha-dec-winnt3.5
-       exit 0 ;;
-    Amiga*:UNIX_System_V:4.0:*)
-       echo m68k-cbm-sysv4
-       exit 0;;
-    amiga:NetBSD:*:*)
-      echo m68k-cbm-netbsd${UNAME_RELEASE}
-      exit 0 ;;
-    amiga:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    *:[Aa]miga[Oo][Ss]:*:*)
-       echo ${UNAME_MACHINE}-unknown-amigaos
-       exit 0 ;;
-    arc64:OpenBSD:*:*)
-       echo mips64el-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    arc:OpenBSD:*:*)
-       echo mipsel-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    hkmips:OpenBSD:*:*)
-       echo mips-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    pmax:OpenBSD:*:*)
-       echo mipsel-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    sgi:OpenBSD:*:*)
-       echo mips-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    wgrisc:OpenBSD:*:*)
-       echo mipsel-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    *:OS/390:*:*)
-       echo i370-ibm-openedition
-       exit 0 ;;
-    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
-       echo arm-acorn-riscix${UNAME_RELEASE}
-       exit 0;;
-    arm32:NetBSD:*:*)
-       echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
-       exit 0 ;;
-    SR2?01:HI-UX/MPP:*:*)
-       echo hppa1.1-hitachi-hiuxmpp
-       exit 0;;
-    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
-       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
-       if test "`(/bin/universe) 2>/dev/null`" = att ; then
-               echo pyramid-pyramid-sysv3
-       else
-               echo pyramid-pyramid-bsd
-       fi
-       exit 0 ;;
-    NILE*:*:*:dcosx)
-       echo pyramid-pyramid-svr4
-       exit 0 ;;
-    sun4H:SunOS:5.*:*)
-       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit 0 ;;
-    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
-       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit 0 ;;
-    i86pc:SunOS:5.*:*)
-       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit 0 ;;
-    sun4*:SunOS:6*:*)
-       # According to config.sub, this is the proper way to canonicalize
-       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
-       # it's likely to be more like Solaris than SunOS4.
-       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit 0 ;;
-    sun4*:SunOS:*:*)
-       case "`/usr/bin/arch -k`" in
-           Series*|S4*)
-               UNAME_RELEASE=`uname -v`
-               ;;
-       esac
-       # Japanese Language versions have a version number like `4.1.3-JL'.
-       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
-       exit 0 ;;
-    sun3*:SunOS:*:*)
-       echo m68k-sun-sunos${UNAME_RELEASE}
-       exit 0 ;;
-    sun*:*:4.2BSD:*)
-       UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
-       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
-       case "`/bin/arch`" in
-           sun3)
-               echo m68k-sun-sunos${UNAME_RELEASE}
-               ;;
-           sun4)
-               echo sparc-sun-sunos${UNAME_RELEASE}
-               ;;
-       esac
-       exit 0 ;;
-    aushp:SunOS:*:*)
-       echo sparc-auspex-sunos${UNAME_RELEASE}
-       exit 0 ;;
-    atari*:NetBSD:*:*)
-       echo m68k-atari-netbsd${UNAME_RELEASE}
-       exit 0 ;;
-    atari*:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    # The situation for MiNT is a little confusing.  The machine name
-    # can be virtually everything (everything which is not
-    # "atarist" or "atariste" at least should have a processor 
-    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
-    # to the lowercase version "mint" (or "freemint").  Finally
-    # the system name "TOS" denotes a system which is actually not
-    # MiNT.  But MiNT is downward compatible to TOS, so this should
-    # be no problem.
-    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
-        echo m68k-atari-mint${UNAME_RELEASE}
-       exit 0 ;;
-    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
-       echo m68k-atari-mint${UNAME_RELEASE}
-        exit 0 ;;
-    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
-        echo m68k-atari-mint${UNAME_RELEASE}
-       exit 0 ;;
-    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
-        echo m68k-milan-mint${UNAME_RELEASE}
-        exit 0 ;;
-    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
-        echo m68k-hades-mint${UNAME_RELEASE}
-        exit 0 ;;
-    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
-        echo m68k-unknown-mint${UNAME_RELEASE}
-        exit 0 ;;
-    sun3*:NetBSD:*:*)
-       echo m68k-sun-netbsd${UNAME_RELEASE}
-       exit 0 ;;
-    sun3*:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    mac68k:NetBSD:*:*)
-       echo m68k-apple-netbsd${UNAME_RELEASE}
-       exit 0 ;;
-    mac68k:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    mvme68k:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    mvme88k:OpenBSD:*:*)
-       echo m88k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    powerpc:machten:*:*)
-       echo powerpc-apple-machten${UNAME_RELEASE}
-       exit 0 ;;
-    macppc:NetBSD:*:*)
-        echo powerpc-apple-netbsd${UNAME_RELEASE}
-        exit 0 ;;
-    RISC*:Mach:*:*)
-       echo mips-dec-mach_bsd4.3
-       exit 0 ;;
-    RISC*:ULTRIX:*:*)
-       echo mips-dec-ultrix${UNAME_RELEASE}
-       exit 0 ;;
-    VAX*:ULTRIX*:*:*)
-       echo vax-dec-ultrix${UNAME_RELEASE}
-       exit 0 ;;
-    2020:CLIX:*:* | 2430:CLIX:*:*)
-       echo clipper-intergraph-clix${UNAME_RELEASE}
-       exit 0 ;;
-    mips:*:*:UMIPS | mips:*:*:RISCos)
-       sed 's/^        //' << EOF >$dummy.c
-#ifdef __cplusplus
-       int main (int argc, char *argv[]) {
-#else
-       int main (argc, argv) int argc; char *argv[]; {
-#endif
-       #if defined (host_mips) && defined (MIPSEB)
-       #if defined (SYSTYPE_SYSV)
-         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
-       #endif
-       #if defined (SYSTYPE_SVR4)
-         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
-       #endif
-       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
-         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
-       #endif
-       #endif
-         exit (-1);
-       }
-EOF
-       $CC_FOR_BUILD $dummy.c -o $dummy \
-         && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
-         && rm $dummy.c $dummy && exit 0
-       rm -f $dummy.c $dummy
-       echo mips-mips-riscos${UNAME_RELEASE}
-       exit 0 ;;
-    Night_Hawk:Power_UNIX:*:*)
-       echo powerpc-harris-powerunix
-       exit 0 ;;
-    m88k:CX/UX:7*:*)
-       echo m88k-harris-cxux7
-       exit 0 ;;
-    m88k:*:4*:R4*)
-       echo m88k-motorola-sysv4
-       exit 0 ;;
-    m88k:*:3*:R3*)
-       echo m88k-motorola-sysv3
-       exit 0 ;;
-    AViiON:dgux:*:*)
-        # DG/UX returns AViiON for all architectures
-        UNAME_PROCESSOR=`/usr/bin/uname -p`
-       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110]
-       then
-           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
-              [ ${TARGET_BINARY_INTERFACE}x = x ]
-           then
-               echo m88k-dg-dgux${UNAME_RELEASE}
-           else
-               echo m88k-dg-dguxbcs${UNAME_RELEASE}
-           fi
-       else
-           echo i586-dg-dgux${UNAME_RELEASE}
-       fi
-       exit 0 ;;
-    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
-       echo m88k-dolphin-sysv3
-       exit 0 ;;
-    M88*:*:R3*:*)
-       # Delta 88k system running SVR3
-       echo m88k-motorola-sysv3
-       exit 0 ;;
-    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
-       echo m88k-tektronix-sysv3
-       exit 0 ;;
-    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
-       echo m68k-tektronix-bsd
-       exit 0 ;;
-    *:IRIX*:*:*)
-       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
-       exit 0 ;;
-    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
-       echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
-       exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
-    i?86:AIX:*:*)
-       echo i386-ibm-aix
-       exit 0 ;;
-    *:AIX:2:3)
-       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
-               sed 's/^                //' << EOF >$dummy.c
-               #include <sys/systemcfg.h>
-
-               main()
-                       {
-                       if (!__power_pc())
-                               exit(1);
-                       puts("powerpc-ibm-aix3.2.5");
-                       exit(0);
-                       }
-EOF
-               $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
-               rm -f $dummy.c $dummy
-               echo rs6000-ibm-aix3.2.5
-       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
-               echo rs6000-ibm-aix3.2.4
-       else
-               echo rs6000-ibm-aix3.2
-       fi
-       exit 0 ;;
-    *:AIX:*:4)
-       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
-       if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then
-               IBM_ARCH=rs6000
-       else
-               IBM_ARCH=powerpc
-       fi
-       if [ -x /usr/bin/oslevel ] ; then
-               IBM_REV=`/usr/bin/oslevel`
-       else
-               IBM_REV=4.${UNAME_RELEASE}
-       fi
-       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
-       exit 0 ;;
-    *:AIX:*:*)
-       echo rs6000-ibm-aix
-       exit 0 ;;
-    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
-       echo romp-ibm-bsd4.4
-       exit 0 ;;
-    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC NetBSD and
-       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
-       exit 0 ;;                           # report: romp-ibm BSD 4.3
-    *:BOSX:*:*)
-       echo rs6000-bull-bosx
-       exit 0 ;;
-    DPX/2?00:B.O.S.:*:*)
-       echo m68k-bull-sysv3
-       exit 0 ;;
-    9000/[34]??:4.3bsd:1.*:*)
-       echo m68k-hp-bsd
-       exit 0 ;;
-    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
-       echo m68k-hp-bsd4.4
-       exit 0 ;;
-    9000/[34678]??:HP-UX:*:*)
-       case "${UNAME_MACHINE}" in
-           9000/31? )            HP_ARCH=m68000 ;;
-           9000/[34]?? )         HP_ARCH=m68k ;;
-           9000/[678][0-9][0-9])
-              sed 's/^              //' << EOF >$dummy.c
-              #include <stdlib.h>
-              #include <unistd.h>
-
-              int main ()
-              {
-              #if defined(_SC_KERNEL_BITS)
-                  long bits = sysconf(_SC_KERNEL_BITS);
-              #endif
-                  long cpu  = sysconf (_SC_CPU_VERSION);
-
-                  switch (cpu)
-               {
-               case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
-               case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
-               case CPU_PA_RISC2_0:
-              #if defined(_SC_KERNEL_BITS)
-                   switch (bits)
-                       {
-                       case 64: puts ("hppa2.0w"); break;
-                       case 32: puts ("hppa2.0n"); break;
-                       default: puts ("hppa2.0"); break;
-                       } break;
-              #else  /* !defined(_SC_KERNEL_BITS) */
-                   puts ("hppa2.0"); break;
-              #endif
-               default: puts ("hppa1.0"); break;
-               }
-                  exit (0);
-              }
-EOF
-       (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
-       rm -f $dummy.c $dummy
-       esac
-       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
-       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
-       exit 0 ;;
-    3050*:HI-UX:*:*)
-       sed 's/^        //' << EOF >$dummy.c
-       #include <unistd.h>
-       int
-       main ()
-       {
-         long cpu = sysconf (_SC_CPU_VERSION);
-         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
-            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
-            results, however.  */
-         if (CPU_IS_PA_RISC (cpu))
-           {
-             switch (cpu)
-               {
-                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
-                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
-                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
-                 default: puts ("hppa-hitachi-hiuxwe2"); break;
-               }
-           }
-         else if (CPU_IS_HP_MC68K (cpu))
-           puts ("m68k-hitachi-hiuxwe2");
-         else puts ("unknown-hitachi-hiuxwe2");
-         exit (0);
-       }
-EOF
-       $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
-       rm -f $dummy.c $dummy
-       echo unknown-hitachi-hiuxwe2
-       exit 0 ;;
-    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
-       echo hppa1.1-hp-bsd
-       exit 0 ;;
-    9000/8??:4.3bsd:*:*)
-       echo hppa1.0-hp-bsd
-       exit 0 ;;
-    *9??*:MPE/iX:*:*)
-       echo hppa1.0-hp-mpeix
-       exit 0 ;;
-    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
-       echo hppa1.1-hp-osf
-       exit 0 ;;
-    hp8??:OSF1:*:*)
-       echo hppa1.0-hp-osf
-       exit 0 ;;
-    i?86:OSF1:*:*)
-       if [ -x /usr/sbin/sysversion ] ; then
-           echo ${UNAME_MACHINE}-unknown-osf1mk
-       else
-           echo ${UNAME_MACHINE}-unknown-osf1
-       fi
-       exit 0 ;;
-    parisc*:Lites*:*:*)
-       echo hppa1.1-hp-lites
-       exit 0 ;;
-    hppa*:OpenBSD:*:*)
-       echo hppa-unknown-openbsd
-       exit 0 ;;
-    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
-       echo c1-convex-bsd
-        exit 0 ;;
-    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
-       if getsysinfo -f scalar_acc
-       then echo c32-convex-bsd
-       else echo c2-convex-bsd
-       fi
-        exit 0 ;;
-    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
-       echo c34-convex-bsd
-        exit 0 ;;
-    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
-       echo c38-convex-bsd
-        exit 0 ;;
-    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
-       echo c4-convex-bsd
-        exit 0 ;;
-    CRAY*X-MP:*:*:*)
-       echo xmp-cray-unicos
-        exit 0 ;;
-    CRAY*Y-MP:*:*:*)
-       echo ymp-cray-unicos${UNAME_RELEASE}
-       exit 0 ;;
-    CRAY*[A-Z]90:*:*:*)
-       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
-       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
-             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
-       exit 0 ;;
-    CRAY*TS:*:*:*)
-       echo t90-cray-unicos${UNAME_RELEASE}
-       exit 0 ;;
-    CRAY*T3E:*:*:*)
-       echo alpha-cray-unicosmk${UNAME_RELEASE}
-       exit 0 ;;
-    CRAY-2:*:*:*)
-       echo cray2-cray-unicos
-        exit 0 ;;
-    F300:UNIX_System_V:*:*)
-        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
-        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
-        echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
-        exit 0 ;;
-    F301:UNIX_System_V:*:*)
-       echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
-       exit 0 ;;
-    hp3[0-9][05]:NetBSD:*:*)
-       echo m68k-hp-netbsd${UNAME_RELEASE}
-       exit 0 ;;
-    hp300:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    i?86:BSD/386:*:* | i?86:BSD/OS:*:*)
-       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
-       exit 0 ;;
-    sparc*:BSD/OS:*:*)
-       echo sparc-unknown-bsdi${UNAME_RELEASE}
-       exit 0 ;;
-    *:BSD/OS:*:*)
-       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
-       exit 0 ;;
-    *:FreeBSD:*:*)
-       if test -x /usr/bin/objformat; then
-           if test "elf" = "`/usr/bin/objformat`"; then
-               echo ${UNAME_MACHINE}-unknown-freebsdelf`echo ${UNAME_RELEASE}|sed -e 's/[-_].*//'`
-               exit 0
-           fi
-       fi
-       echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
-       exit 0 ;;
-    *:NetBSD:*:*)
-       echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*//'`
-       exit 0 ;;
-    *:OpenBSD:*:*)
-       echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
-       exit 0 ;;
-    i*:CYGWIN*:*)
-       echo ${UNAME_MACHINE}-pc-cygwin
-       exit 0 ;;
-    i*:MINGW*:*)
-       echo ${UNAME_MACHINE}-pc-mingw32
-       exit 0 ;;
-    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
-       # How do we know it's Interix rather than the generic POSIX subsystem?
-       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
-       # UNAME_MACHINE based on the output of uname instead of i386?
-       echo i386-pc-interix
-       exit 0 ;;
-    i*:UWIN*:*)
-       echo ${UNAME_MACHINE}-pc-uwin
-       exit 0 ;;
-    p*:CYGWIN*:*)
-       echo powerpcle-unknown-cygwin
-       exit 0 ;;
-    prep*:SunOS:5.*:*)
-       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit 0 ;;
-    *:GNU:*:*)
-       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
-       exit 0 ;;
-    *:Linux:*:*)
-
-       # The BFD linker knows what the default object file format is, so
-       # first see if it will tell us. cd to the root directory to prevent
-       # problems with other programs or directories called `ld' in the path.
-       ld_help_string=`cd /; ld --help 2>&1`
-       ld_supported_emulations=`echo $ld_help_string \
-                        | sed -ne '/supported emulations:/!d
-                                   s/[         ][      ]*/ /g
-                                   s/.*supported emulations: *//
-                                   s/ .*//
-                                   p'`
-        case "$ld_supported_emulations" in
-         *ia64)
-               echo "${UNAME_MACHINE}-unknown-linux"
-               exit 0
-               ;;
-         i?86linux)
-               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
-               exit 0
-               ;;
-         i?86coff)
-               echo "${UNAME_MACHINE}-pc-linux-gnucoff"
-               exit 0
-               ;;
-         sparclinux)
-               echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
-               exit 0
-               ;;
-         armlinux)
-               echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
-               exit 0
-               ;;
-         elf32arm*)
-               echo "${UNAME_MACHINE}-unknown-linux-gnu"
-               exit 0
-               ;;
-         armelf_linux*)
-               echo "${UNAME_MACHINE}-unknown-linux-gnu"
-               exit 0
-               ;;
-         m68klinux)
-               echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
-               exit 0
-               ;;
-         elf32ppc)
-               # Determine Lib Version
-               cat >$dummy.c <<EOF
-#include <features.h>
-#if defined(__GLIBC__)
-extern char __libc_version[];
-extern char __libc_release[];
-#endif
-main(argc, argv)
-     int argc;
-     char *argv[];
-{
-#if defined(__GLIBC__)
-  printf("%s %s\n", __libc_version, __libc_release);
-#else
-  printf("unkown\n");
-#endif
-  return 0;
-}
-EOF
-               LIBC=""
-               $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null
-               if test "$?" = 0 ; then
-                       ./$dummy | grep 1\.99 > /dev/null
-                       if test "$?" = 0 ; then
-                               LIBC="libc1"
-                       fi
-               fi      
-               rm -f $dummy.c $dummy
-               echo powerpc-unknown-linux-gnu${LIBC}
-               exit 0
-               ;;
-       esac
-
-       if test "${UNAME_MACHINE}" = "alpha" ; then
-               sed 's/^        //'  <<EOF >$dummy.s
-               .globl main
-               .ent main
-       main:
-               .frame \$30,0,\$26,0
-               .prologue 0
-               .long 0x47e03d80 # implver $0
-               lda \$2,259
-               .long 0x47e20c21 # amask $2,$1
-               srl \$1,8,\$2
-               sll \$2,2,\$2
-               sll \$0,3,\$0
-               addl \$1,\$0,\$0
-               addl \$2,\$0,\$0
-               ret \$31,(\$26),1
-               .end main
-EOF
-               LIBC=""
-               $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
-               if test "$?" = 0 ; then
-                       ./$dummy
-                       case "$?" in
-                       7)
-                               UNAME_MACHINE="alpha"
-                               ;;
-                       15)
-                               UNAME_MACHINE="alphaev5"
-                               ;;
-                       14)
-                               UNAME_MACHINE="alphaev56"
-                               ;;
-                       10)
-                               UNAME_MACHINE="alphapca56"
-                               ;;
-                       16)
-                               UNAME_MACHINE="alphaev6"
-                               ;;
-                       esac
-
-                       objdump --private-headers $dummy | \
-                         grep ld.so.1 > /dev/null
-                       if test "$?" = 0 ; then
-                               LIBC="libc1"
-                       fi
-               fi
-               rm -f $dummy.s $dummy
-               echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
-       elif test "${UNAME_MACHINE}" = "mips" ; then
-         cat >$dummy.c <<EOF
-#ifdef __cplusplus
-       int main (int argc, char *argv[]) {
-#else
-       int main (argc, argv) int argc; char *argv[]; {
-#endif
-#ifdef __MIPSEB__
-  printf ("%s-unknown-linux-gnu\n", argv[1]);
-#endif
-#ifdef __MIPSEL__
-  printf ("%sel-unknown-linux-gnu\n", argv[1]);
-#endif
-  return 0;
-}
-EOF
-         $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
-         rm -f $dummy.c $dummy
-       else
-         # Either a pre-BFD a.out linker (linux-gnuoldld)
-         # or one that does not give us useful --help.
-         # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
-         # If ld does not provide *any* "supported emulations:"
-         # that means it is gnuoldld.
-         echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
-         test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
-
-         case "${UNAME_MACHINE}" in
-         i?86)
-           VENDOR=pc;
-           ;;
-         *)
-           VENDOR=unknown;
-           ;;
-         esac
-         # Determine whether the default compiler is a.out or elf
-         cat >$dummy.c <<EOF
-#include <features.h>
-#ifdef __cplusplus
-       int main (int argc, char *argv[]) {
-#else
-       int main (argc, argv) int argc; char *argv[]; {
-#endif
-#ifdef __ELF__
-# ifdef __GLIBC__
-#  if __GLIBC__ >= 2
-    printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
-#  else
-    printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
-#  endif
-# else
-   printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
-# endif
-#else
-  printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
-#endif
-  return 0;
-}
-EOF
-         $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
-         rm -f $dummy.c $dummy
-       fi ;;
-# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
-# are messed up and put the nodename in both sysname and nodename.
-    i?86:DYNIX/ptx:4*:*)
-       echo i386-sequent-sysv4
-       exit 0 ;;
-    i?86:UNIX_SV:4.2MP:2.*)
-        # Unixware is an offshoot of SVR4, but it has its own version
-        # number series starting with 2...
-        # I am not positive that other SVR4 systems won't match this,
-       # I just have to hope.  -- rms.
-        # Use sysv4.2uw... so that sysv4* matches it.
-       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
-       exit 0 ;;
-    i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
-       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
-       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
-               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
-       else
-               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
-       fi
-       exit 0 ;;
-    i?86:*:5:7*)
-        # Fixed at (any) Pentium or better
-        UNAME_MACHINE=i586
-        if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then
-           echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION}
-       else
-           echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
-       fi
-       exit 0 ;;
-    i?86:*:3.2:*)
-       if test -f /usr/options/cb.name; then
-               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
-               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
-       elif /bin/uname -X 2>/dev/null >/dev/null ; then
-               UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
-               (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
-               (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
-                       && UNAME_MACHINE=i586
-               (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
-                       && UNAME_MACHINE=i686
-               (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
-                       && UNAME_MACHINE=i686
-               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
-       else
-               echo ${UNAME_MACHINE}-pc-sysv32
-       fi
-       exit 0 ;;
-    pc:*:*:*)
-        # uname -m prints for DJGPP always 'pc', but it prints nothing about
-        # the processor, so we play safe by assuming i386.
-       echo i386-pc-msdosdjgpp
-        exit 0 ;;
-    Intel:Mach:3*:*)
-       echo i386-pc-mach3
-       exit 0 ;;
-    paragon:*:*:*)
-       echo i860-intel-osf1
-       exit 0 ;;
-    i860:*:4.*:*) # i860-SVR4
-       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
-         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
-       else # Add other i860-SVR4 vendors below as they are discovered.
-         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
-       fi
-       exit 0 ;;
-    mini*:CTIX:SYS*5:*)
-       # "miniframe"
-       echo m68010-convergent-sysv
-       exit 0 ;;
-    M68*:*:R3V[567]*:*)
-       test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
-    3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
-       OS_REL=''
-       test -r /etc/.relid \
-       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
-       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
-         && echo i486-ncr-sysv4.3${OS_REL} && exit 0
-       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
-         && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
-    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
-        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
-          && echo i486-ncr-sysv4 && exit 0 ;;
-    m68*:LynxOS:2.*:*)
-       echo m68k-unknown-lynxos${UNAME_RELEASE}
-       exit 0 ;;
-    mc68030:UNIX_System_V:4.*:*)
-       echo m68k-atari-sysv4
-       exit 0 ;;
-    i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*)
-       echo i386-unknown-lynxos${UNAME_RELEASE}
-       exit 0 ;;
-    TSUNAMI:LynxOS:2.*:*)
-       echo sparc-unknown-lynxos${UNAME_RELEASE}
-       exit 0 ;;
-    rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
-       echo rs6000-unknown-lynxos${UNAME_RELEASE}
-       exit 0 ;;
-    SM[BE]S:UNIX_SV:*:*)
-       echo mips-dde-sysv${UNAME_RELEASE}
-       exit 0 ;;
-    RM*:ReliantUNIX-*:*:*)
-       echo mips-sni-sysv4
-       exit 0 ;;
-    RM*:SINIX-*:*:*)
-       echo mips-sni-sysv4
-       exit 0 ;;
-    *:SINIX-*:*:*)
-       if uname -p 2>/dev/null >/dev/null ; then
-               UNAME_MACHINE=`(uname -p) 2>/dev/null`
-               echo ${UNAME_MACHINE}-sni-sysv4
-       else
-               echo ns32k-sni-sysv
-       fi
-       exit 0 ;;
-    PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
-                           # says <Richard.M.Bartel@ccMail.Census.GOV>
-        echo i586-unisys-sysv4
-        exit 0 ;;
-    *:UNIX_System_V:4*:FTX*)
-       # From Gerald Hewes <hewes@openmarket.com>.
-       # How about differentiating between stratus architectures? -djm
-       echo hppa1.1-stratus-sysv4
-       exit 0 ;;
-    *:*:*:FTX*)
-       # From seanf@swdc.stratus.com.
-       echo i860-stratus-sysv4
-       exit 0 ;;
-    mc68*:A/UX:*:*)
-       echo m68k-apple-aux${UNAME_RELEASE}
-       exit 0 ;;
-    news*:NEWS-OS:*:6*)
-       echo mips-sony-newsos6
-       exit 0 ;;
-    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
-       if [ -d /usr/nec ]; then
-               echo mips-nec-sysv${UNAME_RELEASE}
-       else
-               echo mips-unknown-sysv${UNAME_RELEASE}
-       fi
-        exit 0 ;;
-    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
-       echo powerpc-be-beos
-       exit 0 ;;
-    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
-       echo powerpc-apple-beos
-       exit 0 ;;
-    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
-       echo i586-pc-beos
-       exit 0 ;;
-    SX-4:SUPER-UX:*:*)
-       echo sx4-nec-superux${UNAME_RELEASE}
-       exit 0 ;;
-    SX-5:SUPER-UX:*:*)
-       echo sx5-nec-superux${UNAME_RELEASE}
-       exit 0 ;;
-    Power*:Rhapsody:*:*)
-       echo powerpc-apple-rhapsody${UNAME_RELEASE}
-       exit 0 ;;
-    *:Rhapsody:*:*)
-       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
-       exit 0 ;;
-    *:QNX:*:4*)
-       echo i386-qnx-qnx${UNAME_VERSION}
-       exit 0 ;;
-esac
-
-#echo '(No uname command or uname output not recognized.)' 1>&2
-#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
-
-cat >$dummy.c <<EOF
-#ifdef _SEQUENT_
-# include <sys/types.h>
-# include <sys/utsname.h>
-#endif
-main ()
-{
-#if defined (sony)
-#if defined (MIPSEB)
-  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
-     I don't know....  */
-  printf ("mips-sony-bsd\n"); exit (0);
-#else
-#include <sys/param.h>
-  printf ("m68k-sony-newsos%s\n",
-#ifdef NEWSOS4
-          "4"
-#else
-         ""
-#endif
-         ); exit (0);
-#endif
-#endif
-
-#if defined (__arm) && defined (__acorn) && defined (__unix)
-  printf ("arm-acorn-riscix"); exit (0);
-#endif
-
-#if defined (hp300) && !defined (hpux)
-  printf ("m68k-hp-bsd\n"); exit (0);
-#endif
-
-#if defined (NeXT)
-#if !defined (__ARCHITECTURE__)
-#define __ARCHITECTURE__ "m68k"
-#endif
-  int version;
-  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
-  if (version < 4)
-    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
-  else
-    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
-  exit (0);
-#endif
-
-#if defined (MULTIMAX) || defined (n16)
-#if defined (UMAXV)
-  printf ("ns32k-encore-sysv\n"); exit (0);
-#else
-#if defined (CMU)
-  printf ("ns32k-encore-mach\n"); exit (0);
-#else
-  printf ("ns32k-encore-bsd\n"); exit (0);
-#endif
-#endif
-#endif
-
-#if defined (__386BSD__)
-  printf ("i386-pc-bsd\n"); exit (0);
-#endif
-
-#if defined (sequent)
-#if defined (i386)
-  printf ("i386-sequent-dynix\n"); exit (0);
-#endif
-#if defined (ns32000)
-  printf ("ns32k-sequent-dynix\n"); exit (0);
-#endif
-#endif
-
-#if defined (_SEQUENT_)
-    struct utsname un;
-
-    uname(&un);
-
-    if (strncmp(un.version, "V2", 2) == 0) {
-       printf ("i386-sequent-ptx2\n"); exit (0);
-    }
-    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
-       printf ("i386-sequent-ptx1\n"); exit (0);
-    }
-    printf ("i386-sequent-ptx\n"); exit (0);
-
-#endif
-
-#if defined (vax)
-#if !defined (ultrix)
-  printf ("vax-dec-bsd\n"); exit (0);
-#else
-  printf ("vax-dec-ultrix\n"); exit (0);
-#endif
-#endif
-
-#if defined (alliant) && defined (i860)
-  printf ("i860-alliant-bsd\n"); exit (0);
-#endif
-
-  exit (1);
-}
-EOF
-
-$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0
-rm -f $dummy.c $dummy
-
-# Apollos put the system type in the environment.
-
-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
-
-# Convex versions that predate uname can use getsysinfo(1)
-
-if [ -x /usr/convex/getsysinfo ]
-then
-    case `getsysinfo -f cpu_type` in
-    c1*)
-       echo c1-convex-bsd
-       exit 0 ;;
-    c2*)
-       if getsysinfo -f scalar_acc
-       then echo c32-convex-bsd
-       else echo c2-convex-bsd
-       fi
-       exit 0 ;;
-    c34*)
-       echo c34-convex-bsd
-       exit 0 ;;
-    c38*)
-       echo c38-convex-bsd
-       exit 0 ;;
-    c4*)
-       echo c4-convex-bsd
-       exit 0 ;;
-    esac
-fi
-
-#echo '(Unable to guess system type)' 1>&2
-
-exit 1
diff --git a/config.h.in b/config.h.in
deleted file mode 100644 (file)
index 972a579..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/* config.h.in.  Generated automatically from configure.in by autoheader.  */
-
-/* Define to empty if the keyword does not work.  */
-#undef const
-
-/* Define if you don't have vprintf but do have _doprnt.  */
-#undef HAVE_DOPRNT
-
-/* Define if you have the vprintf function.  */
-#undef HAVE_VPRINTF
-
-/* Define if you have the wait3 system call.  */
-#undef HAVE_WAIT3
-
-/* Define as the return type of signal handlers (int or void).  */
-#undef RETSIGTYPE
-
-/* Define if the `setpgrp' function takes no argument.  */
-#undef SETPGRP_VOID
-
-/* Define if you have the ANSI C header files.  */
-#undef STDC_HEADERS
-
-/* Define if you can safely include both <sys/time.h> and <time.h>.  */
-#undef TIME_WITH_SYS_TIME
-
-/* Define if you have the regcomp function.  */
-#undef HAVE_REGCOMP
-
-/* Define if you have the select function.  */
-#undef HAVE_SELECT
-
-/* Define if you have the socket function.  */
-#undef HAVE_SOCKET
-
-/* Define if you have the strcspn function.  */
-#undef HAVE_STRCSPN
-
-/* Define if you have the strdup function.  */
-#undef HAVE_STRDUP
-
-/* Define if you have the strstr function.  */
-#undef HAVE_STRSTR
-
-/* Define if you have the strtol function.  */
-#undef HAVE_STRTOL
-
-/* Define if you have the <fcntl.h> header file.  */
-#undef HAVE_FCNTL_H
-
-/* Define if you have the <malloc.h> header file.  */
-#undef HAVE_MALLOC_H
-
-/* Define if you have the <strings.h> header file.  */
-#undef HAVE_STRINGS_H
-
-/* Define if you have the <sys/file.h> header file.  */
-#undef HAVE_SYS_FILE_H
-
-/* Define if you have the <sys/ioctl.h> header file.  */
-#undef HAVE_SYS_IOCTL_H
-
-/* Define if you have the <sys/time.h> header file.  */
-#undef HAVE_SYS_TIME_H
-
-/* Define if you have the <syslog.h> header file.  */
-#undef HAVE_SYSLOG_H
-
-/* Define if you have the <unistd.h> header file.  */
-#undef HAVE_UNISTD_H
-
-/* Define if you have the c library (-lc).  */
-#undef HAVE_LIBC
-
-/* Define if you have the crypt library (-lcrypt).  */
-#undef HAVE_LIBCRYPT
-
-/* Define if you have the dl library (-ldl).  */
-#undef HAVE_LIBDL
-
-/* Define if you have the og library (-log).  */
-#undef HAVE_LIBOG
-
-/* Define if you have the pam library (-lpam).  */
-#undef HAVE_LIBPAM
-
-/* Define this if you have shadow passwords in /etc/passwd and
- * /etc/shadow. Note that you usually need to be root to read
- * /etc/shadow */
-#undef SHADOW_PASSWORDS
-
diff --git a/config.sub b/config.sub
deleted file mode 100644 (file)
index 28426bb..0000000
+++ /dev/null
@@ -1,1232 +0,0 @@
-#! /bin/sh
-# Configuration validation subroutine script, version 1.1.
-#   Copyright (C) 1991, 92-97, 1998, 1999 Free Software Foundation, Inc.
-# This file is (in principle) common to ALL GNU software.
-# The presence of a machine in this file suggests that SOME GNU software
-# can handle that machine.  It does not imply ALL GNU software can.
-#
-# This file is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Configuration subroutine to validate and canonicalize a configuration type.
-# Supply the specified configuration type as an argument.
-# If it is invalid, we print an error message on stderr and exit with code 1.
-# Otherwise, we print the canonical config type on stdout and succeed.
-
-# This file is supposed to be the same for all GNU packages
-# and recognize all the CPU types, system types and aliases
-# that are meaningful with *any* GNU software.
-# Each package is responsible for reporting which valid configurations
-# it does not support.  The user should be able to distinguish
-# a failure to support a valid configuration from a meaningless
-# configuration.
-
-# The goal of this file is to map all the various variations of a given
-# machine specification into a single specification in the form:
-#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
-# or in some cases, the newer four-part form:
-#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
-# It is wrong to echo any other type of specification.
-
-if [ x$1 = x ]
-then
-       echo Configuration name missing. 1>&2
-       echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
-       echo "or     $0 ALIAS" 1>&2
-       echo where ALIAS is a recognized configuration type. 1>&2
-       exit 1
-fi
-
-# First pass through any local machine types.
-case $1 in
-       *local*)
-               echo $1
-               exit 0
-               ;;
-       *)
-       ;;
-esac
-
-# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
-# Here we must recognize all the valid KERNEL-OS combinations.
-maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
-case $maybe_os in
-  linux-gnu*)
-    os=-$maybe_os
-    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
-    ;;
-  *)
-    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
-    if [ $basic_machine != $1 ]
-    then os=`echo $1 | sed 's/.*-/-/'`
-    else os=; fi
-    ;;
-esac
-
-### Let's recognize common machines as not being operating systems so
-### that things like config.sub decstation-3100 work.  We also
-### recognize some manufacturers as not being operating systems, so we
-### can provide default operating systems below.
-case $os in
-       -sun*os*)
-               # Prevent following clause from handling this invalid input.
-               ;;
-       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
-       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
-       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
-       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-       -apple)
-               os=
-               basic_machine=$1
-               ;;
-       -sim | -cisco | -oki | -wec | -winbond)
-               os=
-               basic_machine=$1
-               ;;
-       -scout)
-               ;;
-       -wrs)
-               os=-vxworks
-               basic_machine=$1
-               ;;
-       -hiux*)
-               os=-hiuxwe2
-               ;;
-       -sco5)
-               os=-sco3.2v5
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -sco4)
-               os=-sco3.2v4
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -sco3.2.[4-9]*)
-               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -sco3.2v[4-9]*)
-               # Don't forget version if it is 3.2v4 or newer.
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -sco*)
-               os=-sco3.2v2
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -udk*)
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -isc)
-               os=-isc2.2
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -clix*)
-               basic_machine=clipper-intergraph
-               ;;
-       -isc*)
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -lynx*)
-               os=-lynxos
-               ;;
-       -ptx*)
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
-               ;;
-       -windowsnt*)
-               os=`echo $os | sed -e 's/windowsnt/winnt/'`
-               ;;
-       -psos*)
-               os=-psos
-               ;;
-       -mint | -mint[0-9]*)
-               basic_machine=m68k-atari
-               os=-mint
-               ;;
-esac
-
-# Decode aliases for certain CPU-COMPANY combinations.
-case $basic_machine in
-       # Recognize the basic CPU types without company name.
-       # Some are omitted here because they have special meanings below.
-       tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
-               | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
-               | 580 | i960 | h8300 \
-               | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
-               | alpha | alphaev[4-7] | alphaev56 | alphapca5[67] \
-               | we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \
-               | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \
-               | mips64orion | mips64orionel | mipstx39 | mipstx39el \
-               | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
-               | mips64vr5000 | miprs64vr5000el | mcore \
-               | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
-               | thumb | d10v | fr30)
-               basic_machine=$basic_machine-unknown
-               ;;
-       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65 | pj | pjl)
-               ;;
-
-       # We use `pc' rather than `unknown'
-       # because (1) that's what they normally are, and
-       # (2) the word "unknown" tends to confuse beginning users.
-       i[34567]86)
-         basic_machine=$basic_machine-pc
-         ;;
-       # Object if more than one company name word.
-       *-*-*)
-               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
-               exit 1
-               ;;
-       # Recognize the basic CPU types with company name.
-       # FIXME: clean up the formatting here.
-       vax-* | tahoe-* | i[34567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
-             | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
-             | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
-             | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
-             | xmp-* | ymp-* \
-             | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \
-             | alpha-* | alphaev[4-7]-* | alphaev56-* | alphapca5[67]-* \
-             | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
-             | clipper-* | orion-* \
-             | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
-             | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
-             | mips64el-* | mips64orion-* | mips64orionel-* \
-             | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
-             | mipstx39-* | mipstx39el-* | mcore-* \
-             | f301-* | armv*-* | t3e-* \
-             | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
-             | thumb-* | v850-* | d30v-* | tic30-* | c30-* | fr30-* )
-               ;;
-       # Recognize the various machine names and aliases which stand
-       # for a CPU type and a company and sometimes even an OS.
-       386bsd)
-               basic_machine=i386-unknown
-               os=-bsd
-               ;;
-       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
-               basic_machine=m68000-att
-               ;;
-       3b*)
-               basic_machine=we32k-att
-               ;;
-       a29khif)
-               basic_machine=a29k-amd
-               os=-udi
-               ;;
-       adobe68k)
-               basic_machine=m68010-adobe
-               os=-scout
-               ;;
-       alliant | fx80)
-               basic_machine=fx80-alliant
-               ;;
-       altos | altos3068)
-               basic_machine=m68k-altos
-               ;;
-       am29k)
-               basic_machine=a29k-none
-               os=-bsd
-               ;;
-       amdahl)
-               basic_machine=580-amdahl
-               os=-sysv
-               ;;
-       amiga | amiga-*)
-               basic_machine=m68k-cbm
-               ;;
-       amigaos | amigados)
-               basic_machine=m68k-cbm
-               os=-amigaos
-               ;;
-       amigaunix | amix)
-               basic_machine=m68k-cbm
-               os=-sysv4
-               ;;
-       apollo68)
-               basic_machine=m68k-apollo
-               os=-sysv
-               ;;
-       apollo68bsd)
-               basic_machine=m68k-apollo
-               os=-bsd
-               ;;
-       aux)
-               basic_machine=m68k-apple
-               os=-aux
-               ;;
-       balance)
-               basic_machine=ns32k-sequent
-               os=-dynix
-               ;;
-       convex-c1)
-               basic_machine=c1-convex
-               os=-bsd
-               ;;
-       convex-c2)
-               basic_machine=c2-convex
-               os=-bsd
-               ;;
-       convex-c32)
-               basic_machine=c32-convex
-               os=-bsd
-               ;;
-       convex-c34)
-               basic_machine=c34-convex
-               os=-bsd
-               ;;
-       convex-c38)
-               basic_machine=c38-convex
-               os=-bsd
-               ;;
-       cray | ymp)
-               basic_machine=ymp-cray
-               os=-unicos
-               ;;
-       cray2)
-               basic_machine=cray2-cray
-               os=-unicos
-               ;;
-       [ctj]90-cray)
-               basic_machine=c90-cray
-               os=-unicos
-               ;;
-       crds | unos)
-               basic_machine=m68k-crds
-               ;;
-       da30 | da30-*)
-               basic_machine=m68k-da30
-               ;;
-       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
-               basic_machine=mips-dec
-               ;;
-       delta | 3300 | motorola-3300 | motorola-delta \
-             | 3300-motorola | delta-motorola)
-               basic_machine=m68k-motorola
-               ;;
-       delta88)
-               basic_machine=m88k-motorola
-               os=-sysv3
-               ;;
-       dpx20 | dpx20-*)
-               basic_machine=rs6000-bull
-               os=-bosx
-               ;;
-       dpx2* | dpx2*-bull)
-               basic_machine=m68k-bull
-               os=-sysv3
-               ;;
-       ebmon29k)
-               basic_machine=a29k-amd
-               os=-ebmon
-               ;;
-       elxsi)
-               basic_machine=elxsi-elxsi
-               os=-bsd
-               ;;
-       encore | umax | mmax)
-               basic_machine=ns32k-encore
-               ;;
-       es1800 | OSE68k | ose68k | ose | OSE)
-               basic_machine=m68k-ericsson
-               os=-ose
-               ;;
-       fx2800)
-               basic_machine=i860-alliant
-               ;;
-       genix)
-               basic_machine=ns32k-ns
-               ;;
-       gmicro)
-               basic_machine=tron-gmicro
-               os=-sysv
-               ;;
-       h3050r* | hiux*)
-               basic_machine=hppa1.1-hitachi
-               os=-hiuxwe2
-               ;;
-       h8300hms)
-               basic_machine=h8300-hitachi
-               os=-hms
-               ;;
-       h8300xray)
-               basic_machine=h8300-hitachi
-               os=-xray
-               ;;
-       h8500hms)
-               basic_machine=h8500-hitachi
-               os=-hms
-               ;;
-       harris)
-               basic_machine=m88k-harris
-               os=-sysv3
-               ;;
-       hp300-*)
-               basic_machine=m68k-hp
-               ;;
-       hp300bsd)
-               basic_machine=m68k-hp
-               os=-bsd
-               ;;
-       hp300hpux)
-               basic_machine=m68k-hp
-               os=-hpux
-               ;;
-       hp3k9[0-9][0-9] | hp9[0-9][0-9])
-               basic_machine=hppa1.0-hp
-               ;;
-       hp9k2[0-9][0-9] | hp9k31[0-9])
-               basic_machine=m68000-hp
-               ;;
-       hp9k3[2-9][0-9])
-               basic_machine=m68k-hp
-               ;;
-       hp9k6[0-9][0-9] | hp6[0-9][0-9])
-               basic_machine=hppa1.0-hp
-               ;;
-       hp9k7[0-79][0-9] | hp7[0-79][0-9])
-               basic_machine=hppa1.1-hp
-               ;;
-       hp9k78[0-9] | hp78[0-9])
-               # FIXME: really hppa2.0-hp
-               basic_machine=hppa1.1-hp
-               ;;
-       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
-               # FIXME: really hppa2.0-hp
-               basic_machine=hppa1.1-hp
-               ;;
-       hp9k8[0-9][13679] | hp8[0-9][13679])
-               basic_machine=hppa1.1-hp
-               ;;
-       hp9k8[0-9][0-9] | hp8[0-9][0-9])
-               basic_machine=hppa1.0-hp
-               ;;
-       hppa-next)
-               os=-nextstep3
-               ;;
-       hppaosf)
-               basic_machine=hppa1.1-hp
-               os=-osf
-               ;;
-       hppro)
-               basic_machine=hppa1.1-hp
-               os=-proelf
-               ;;
-       i370-ibm* | ibm*)
-               basic_machine=i370-ibm
-               ;;
-# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
-       i[34567]86v32)
-               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-               os=-sysv32
-               ;;
-       i[34567]86v4*)
-               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-               os=-sysv4
-               ;;
-       i[34567]86v)
-               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-               os=-sysv
-               ;;
-       i[34567]86sol2)
-               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-               os=-solaris2
-               ;;
-       i386mach)
-               basic_machine=i386-mach
-               os=-mach
-               ;;
-       i386-vsta | vsta)
-               basic_machine=i386-unknown
-               os=-vsta
-               ;;
-       i386-go32 | go32)
-               basic_machine=i386-unknown
-               os=-go32
-               ;;
-       i386-mingw32 | mingw32)
-               basic_machine=i386-unknown
-               os=-mingw32
-               ;;
-       i386-qnx | qnx)
-               basic_machine=i386-qnx
-               ;;
-       iris | iris4d)
-               basic_machine=mips-sgi
-               case $os in
-                   -irix*)
-                       ;;
-                   *)
-                       os=-irix4
-                       ;;
-               esac
-               ;;
-       isi68 | isi)
-               basic_machine=m68k-isi
-               os=-sysv
-               ;;
-       m88k-omron*)
-               basic_machine=m88k-omron
-               ;;
-       magnum | m3230)
-               basic_machine=mips-mips
-               os=-sysv
-               ;;
-       merlin)
-               basic_machine=ns32k-utek
-               os=-sysv
-               ;;
-       miniframe)
-               basic_machine=m68000-convergent
-               ;;
-       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
-               basic_machine=m68k-atari
-               os=-mint
-               ;;
-       mipsel*-linux*)
-               basic_machine=mipsel-unknown
-               os=-linux-gnu
-               ;;
-       mips*-linux*)
-               basic_machine=mips-unknown
-               os=-linux-gnu
-               ;;
-       mips3*-*)
-               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
-               ;;
-       mips3*)
-               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
-               ;;
-       monitor)
-               basic_machine=m68k-rom68k
-               os=-coff
-               ;;
-       msdos)
-               basic_machine=i386-unknown
-               os=-msdos
-               ;;
-       mvs)
-               basic_machine=i370-ibm
-               os=-mvs
-               ;;
-       ncr3000)
-               basic_machine=i486-ncr
-               os=-sysv4
-               ;;
-       netbsd386)
-               basic_machine=i386-unknown
-               os=-netbsd
-               ;;
-       netwinder)
-               basic_machine=armv4l-rebel
-               os=-linux
-               ;;
-       news | news700 | news800 | news900)
-               basic_machine=m68k-sony
-               os=-newsos
-               ;;
-       news1000)
-               basic_machine=m68030-sony
-               os=-newsos
-               ;;
-       news-3600 | risc-news)
-               basic_machine=mips-sony
-               os=-newsos
-               ;;
-       necv70)
-               basic_machine=v70-nec
-               os=-sysv
-               ;;
-       next | m*-next )
-               basic_machine=m68k-next
-               case $os in
-                   -nextstep* )
-                       ;;
-                   -ns2*)
-                     os=-nextstep2
-                       ;;
-                   *)
-                     os=-nextstep3
-                       ;;
-               esac
-               ;;
-       nh3000)
-               basic_machine=m68k-harris
-               os=-cxux
-               ;;
-       nh[45]000)
-               basic_machine=m88k-harris
-               os=-cxux
-               ;;
-       nindy960)
-               basic_machine=i960-intel
-               os=-nindy
-               ;;
-       mon960)
-               basic_machine=i960-intel
-               os=-mon960
-               ;;
-       np1)
-               basic_machine=np1-gould
-               ;;
-       op50n-* | op60c-*)
-               basic_machine=hppa1.1-oki
-               os=-proelf
-               ;;
-       OSE68000 | ose68000)
-               basic_machine=m68000-ericsson
-               os=-ose
-               ;;
-       os68k)
-               basic_machine=m68k-none
-               os=-os68k
-               ;;
-       pa-hitachi)
-               basic_machine=hppa1.1-hitachi
-               os=-hiuxwe2
-               ;;
-       paragon)
-               basic_machine=i860-intel
-               os=-osf
-               ;;
-       pbd)
-               basic_machine=sparc-tti
-               ;;
-       pbb)
-               basic_machine=m68k-tti
-               ;;
-        pc532 | pc532-*)
-               basic_machine=ns32k-pc532
-               ;;
-       pentium | p5 | k5 | k6 | nexen)
-               basic_machine=i586-pc
-               ;;
-       pentiumpro | p6 | 6x86)
-               basic_machine=i686-pc
-               ;;
-       pentiumii | pentium2)
-               basic_machine=i786-pc
-               ;;
-       pentium-* | p5-* | k5-* | k6-* | nexen-*)
-               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       pentiumpro-* | p6-* | 6x86-*)
-               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       pentiumii-* | pentium2-*)
-               basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       pn)
-               basic_machine=pn-gould
-               ;;
-       power)  basic_machine=rs6000-ibm
-               ;;
-       ppc)    basic_machine=powerpc-unknown
-               ;;
-       ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       ppcle | powerpclittle | ppc-le | powerpc-little)
-               basic_machine=powerpcle-unknown
-               ;;
-       ppcle-* | powerpclittle-*)
-               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       ps2)
-               basic_machine=i386-ibm
-               ;;
-       rom68k)
-               basic_machine=m68k-rom68k
-               os=-coff
-               ;;
-       rm[46]00)
-               basic_machine=mips-siemens
-               ;;
-       rtpc | rtpc-*)
-               basic_machine=romp-ibm
-               ;;
-       sa29200)
-               basic_machine=a29k-amd
-               os=-udi
-               ;;
-       sequent)
-               basic_machine=i386-sequent
-               ;;
-       sh)
-               basic_machine=sh-hitachi
-               os=-hms
-               ;;
-       sparclite-wrs)
-               basic_machine=sparclite-wrs
-               os=-vxworks
-               ;;
-       sps7)
-               basic_machine=m68k-bull
-               os=-sysv2
-               ;;
-       spur)
-               basic_machine=spur-unknown
-               ;;
-       st2000)
-               basic_machine=m68k-tandem
-               ;;
-       stratus)
-               basic_machine=i860-stratus
-               os=-sysv4
-               ;;
-       sun2)
-               basic_machine=m68000-sun
-               ;;
-       sun2os3)
-               basic_machine=m68000-sun
-               os=-sunos3
-               ;;
-       sun2os4)
-               basic_machine=m68000-sun
-               os=-sunos4
-               ;;
-       sun3os3)
-               basic_machine=m68k-sun
-               os=-sunos3
-               ;;
-       sun3os4)
-               basic_machine=m68k-sun
-               os=-sunos4
-               ;;
-       sun4os3)
-               basic_machine=sparc-sun
-               os=-sunos3
-               ;;
-       sun4os4)
-               basic_machine=sparc-sun
-               os=-sunos4
-               ;;
-       sun4sol2)
-               basic_machine=sparc-sun
-               os=-solaris2
-               ;;
-       sun3 | sun3-*)
-               basic_machine=m68k-sun
-               ;;
-       sun4)
-               basic_machine=sparc-sun
-               ;;
-       sun386 | sun386i | roadrunner)
-               basic_machine=i386-sun
-               ;;
-       symmetry)
-               basic_machine=i386-sequent
-               os=-dynix
-               ;;
-       t3e)
-               basic_machine=t3e-cray
-               os=-unicos
-               ;;
-       tx39)
-               basic_machine=mipstx39-unknown
-               ;;
-       tx39el)
-               basic_machine=mipstx39el-unknown
-               ;;
-       tower | tower-32)
-               basic_machine=m68k-ncr
-               ;;
-       udi29k)
-               basic_machine=a29k-amd
-               os=-udi
-               ;;
-       ultra3)
-               basic_machine=a29k-nyu
-               os=-sym1
-               ;;
-       v810 | necv810)
-               basic_machine=v810-nec
-               os=-none
-               ;;
-       vaxv)
-               basic_machine=vax-dec
-               os=-sysv
-               ;;
-       vms)
-               basic_machine=vax-dec
-               os=-vms
-               ;;
-       vpp*|vx|vx-*)
-               basic_machine=f301-fujitsu
-               ;;
-       vxworks960)
-               basic_machine=i960-wrs
-               os=-vxworks
-               ;;
-       vxworks68)
-               basic_machine=m68k-wrs
-               os=-vxworks
-               ;;
-       vxworks29k)
-               basic_machine=a29k-wrs
-               os=-vxworks
-               ;;
-       w65*)
-               basic_machine=w65-wdc
-               os=-none
-               ;;
-       w89k-*)
-               basic_machine=hppa1.1-winbond
-               os=-proelf
-               ;;
-       xmp)
-               basic_machine=xmp-cray
-               os=-unicos
-               ;;
-        xps | xps100)
-               basic_machine=xps100-honeywell
-               ;;
-       z8k-*-coff)
-               basic_machine=z8k-unknown
-               os=-sim
-               ;;
-       none)
-               basic_machine=none-none
-               os=-none
-               ;;
-
-# Here we handle the default manufacturer of certain CPU types.  It is in
-# some cases the only manufacturer, in others, it is the most popular.
-       w89k)
-               basic_machine=hppa1.1-winbond
-               ;;
-       op50n)
-               basic_machine=hppa1.1-oki
-               ;;
-       op60c)
-               basic_machine=hppa1.1-oki
-               ;;
-       mips)
-               if [ x$os = x-linux-gnu ]; then
-                       basic_machine=mips-unknown
-               else
-                       basic_machine=mips-mips
-               fi
-               ;;
-       romp)
-               basic_machine=romp-ibm
-               ;;
-       rs6000)
-               basic_machine=rs6000-ibm
-               ;;
-       vax)
-               basic_machine=vax-dec
-               ;;
-       pdp11)
-               basic_machine=pdp11-dec
-               ;;
-       we32k)
-               basic_machine=we32k-att
-               ;;
-       sparc | sparcv9)
-               basic_machine=sparc-sun
-               ;;
-        cydra)
-               basic_machine=cydra-cydrome
-               ;;
-       orion)
-               basic_machine=orion-highlevel
-               ;;
-       orion105)
-               basic_machine=clipper-highlevel
-               ;;
-       mac | mpw | mac-mpw)
-               basic_machine=m68k-apple
-               ;;
-       pmac | pmac-mpw)
-               basic_machine=powerpc-apple
-               ;;
-       c4x*)
-               basic_machine=c4x-none
-               os=-coff
-               ;;
-       *)
-               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
-               exit 1
-               ;;
-esac
-
-# Here we canonicalize certain aliases for manufacturers.
-case $basic_machine in
-       *-digital*)
-               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
-               ;;
-       *-commodore*)
-               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
-               ;;
-       *)
-               ;;
-esac
-
-# Decode manufacturer-specific aliases for certain operating systems.
-
-if [ x"$os" != x"" ]
-then
-case $os in
-        # First match some system type aliases
-        # that might get confused with valid system types.
-       # -solaris* is a basic system type, with this one exception.
-       -solaris1 | -solaris1.*)
-               os=`echo $os | sed -e 's|solaris1|sunos4|'`
-               ;;
-       -solaris)
-               os=-solaris2
-               ;;
-       -svr4*)
-               os=-sysv4
-               ;;
-       -unixware*)
-               os=-sysv4.2uw
-               ;;
-       -gnu/linux*)
-               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
-               ;;
-       # First accept the basic system types.
-       # The portable systems comes first.
-       # Each alternative MUST END IN A *, to match a version number.
-       # -sysv* is not here because it comes later, after sysvr4.
-       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
-             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
-             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
-             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
-             | -aos* \
-             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
-             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
-             | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
-             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
-             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
-             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
-             | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
-             | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
-             | -interix* | -uwin* | -rhapsody* | -opened* | -openstep* | -oskit*)
-       # Remember, each alternative MUST END IN *, to match a version number.
-               ;;
-       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
-             | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
-             | -macos* | -mpw* | -magic* | -mon960* | -lnews*)
-               ;;
-       -mac*)
-               os=`echo $os | sed -e 's|mac|macos|'`
-               ;;
-       -linux*)
-               os=`echo $os | sed -e 's|linux|linux-gnu|'`
-               ;;
-       -sunos5*)
-               os=`echo $os | sed -e 's|sunos5|solaris2|'`
-               ;;
-       -sunos6*)
-               os=`echo $os | sed -e 's|sunos6|solaris3|'`
-               ;;
-       -opened*)
-               os=-openedition
-               ;;
-       -osfrose*)
-               os=-osfrose
-               ;;
-       -osf*)
-               os=-osf
-               ;;
-       -utek*)
-               os=-bsd
-               ;;
-       -dynix*)
-               os=-bsd
-               ;;
-       -acis*)
-               os=-aos
-               ;;
-       -386bsd)
-               os=-bsd
-               ;;
-       -ctix* | -uts*)
-               os=-sysv
-               ;;
-       -ns2 )
-               os=-nextstep2
-               ;;
-       # Preserve the version number of sinix5.
-       -sinix5.*)
-               os=`echo $os | sed -e 's|sinix|sysv|'`
-               ;;
-       -sinix*)
-               os=-sysv4
-               ;;
-       -triton*)
-               os=-sysv3
-               ;;
-       -oss*)
-               os=-sysv3
-               ;;
-        -qnx)
-               os=-qnx4
-               ;;
-       -svr4)
-               os=-sysv4
-               ;;
-       -svr3)
-               os=-sysv3
-               ;;
-       -sysvr4)
-               os=-sysv4
-               ;;
-       # This must come after -sysvr4.
-       -sysv*)
-               ;;
-       -ose*)
-               os=-ose
-               ;;
-       -es1800*)
-               os=-ose
-               ;;
-       -xenix)
-               os=-xenix
-               ;;
-        -*mint | -*MiNT)
-               os=-mint
-               ;;
-       -none)
-               ;;
-       *)
-               # Get rid of the `-' at the beginning of $os.
-               os=`echo $os | sed 's/[^-]*-//'`
-               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
-               exit 1
-               ;;
-esac
-else
-
-# Here we handle the default operating systems that come with various machines.
-# The value should be what the vendor currently ships out the door with their
-# machine or put another way, the most popular os provided with the machine.
-
-# Note that if you're going to try to match "-MANUFACTURER" here (say,
-# "-sun"), then you have to tell the case statement up towards the top
-# that MANUFACTURER isn't an operating system.  Otherwise, code above
-# will signal an error saying that MANUFACTURER isn't an operating
-# system, and we'll never get to this point.
-
-case $basic_machine in
-       *-acorn)
-               os=-riscix1.2
-               ;;
-       arm*-rebel)
-               os=-linux
-               ;;
-       arm*-semi)
-               os=-aout
-               ;;
-        pdp11-*)
-               os=-none
-               ;;
-       *-dec | vax-*)
-               os=-ultrix4.2
-               ;;
-       m68*-apollo)
-               os=-domain
-               ;;
-       i386-sun)
-               os=-sunos4.0.2
-               ;;
-       m68000-sun)
-               os=-sunos3
-               # This also exists in the configure program, but was not the
-               # default.
-               # os=-sunos4
-               ;;
-       m68*-cisco)
-               os=-aout
-               ;;
-       mips*-cisco)
-               os=-elf
-               ;;
-       mips*-*)
-               os=-elf
-               ;;
-       *-tti)  # must be before sparc entry or we get the wrong os.
-               os=-sysv3
-               ;;
-       sparc-* | *-sun)
-               os=-sunos4.1.1
-               ;;
-       *-be)
-               os=-beos
-               ;;
-       *-ibm)
-               os=-aix
-               ;;
-       *-wec)
-               os=-proelf
-               ;;
-       *-winbond)
-               os=-proelf
-               ;;
-       *-oki)
-               os=-proelf
-               ;;
-       *-hp)
-               os=-hpux
-               ;;
-       *-hitachi)
-               os=-hiux
-               ;;
-       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
-               os=-sysv
-               ;;
-       *-cbm)
-               os=-amigaos
-               ;;
-       *-dg)
-               os=-dgux
-               ;;
-       *-dolphin)
-               os=-sysv3
-               ;;
-       m68k-ccur)
-               os=-rtu
-               ;;
-       m88k-omron*)
-               os=-luna
-               ;;
-       *-next )
-               os=-nextstep
-               ;;
-       *-sequent)
-               os=-ptx
-               ;;
-       *-crds)
-               os=-unos
-               ;;
-       *-ns)
-               os=-genix
-               ;;
-       i370-*)
-               os=-mvs
-               ;;
-       *-next)
-               os=-nextstep3
-               ;;
-        *-gould)
-               os=-sysv
-               ;;
-        *-highlevel)
-               os=-bsd
-               ;;
-       *-encore)
-               os=-bsd
-               ;;
-        *-sgi)
-               os=-irix
-               ;;
-        *-siemens)
-               os=-sysv4
-               ;;
-       *-masscomp)
-               os=-rtu
-               ;;
-       f301-fujitsu)
-               os=-uxpv
-               ;;
-       *-rom68k)
-               os=-coff
-               ;;
-       *-*bug)
-               os=-coff
-               ;;
-       *-apple)
-               os=-macos
-               ;;
-       *-atari*)
-               os=-mint
-               ;;
-       *)
-               os=-none
-               ;;
-esac
-fi
-
-# Here we handle the case where we know the os, and the CPU type, but not the
-# manufacturer.  We pick the logical manufacturer.
-vendor=unknown
-case $basic_machine in
-       *-unknown)
-               case $os in
-                       -riscix*)
-                               vendor=acorn
-                               ;;
-                       -sunos*)
-                               vendor=sun
-                               ;;
-                       -aix*)
-                               vendor=ibm
-                               ;;
-                       -beos*)
-                               vendor=be
-                               ;;
-                       -hpux*)
-                               vendor=hp
-                               ;;
-                       -mpeix*)
-                               vendor=hp
-                               ;;
-                       -hiux*)
-                               vendor=hitachi
-                               ;;
-                       -unos*)
-                               vendor=crds
-                               ;;
-                       -dgux*)
-                               vendor=dg
-                               ;;
-                       -luna*)
-                               vendor=omron
-                               ;;
-                       -genix*)
-                               vendor=ns
-                               ;;
-                       -mvs* | -opened*)
-                               vendor=ibm
-                               ;;
-                       -ptx*)
-                               vendor=sequent
-                               ;;
-                       -vxsim* | -vxworks*)
-                               vendor=wrs
-                               ;;
-                       -aux*)
-                               vendor=apple
-                               ;;
-                       -hms*)
-                               vendor=hitachi
-                               ;;
-                       -mpw* | -macos*)
-                               vendor=apple
-                               ;;
-                       -*mint | -*MiNT)
-                               vendor=atari
-                               ;;
-               esac
-               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
-               ;;
-esac
-
-echo $basic_machine$os
diff --git a/configure b/configure
deleted file mode 100755 (executable)
index 7a31bfe..0000000
--- a/configure
+++ /dev/null
@@ -1,2886 +0,0 @@
-#! /bin/sh
-
-# Guess values for system-dependent variables and create Makefiles.
-# Generated automatically using autoconf version 2.13 
-# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
-#
-# This configure script is free software; the Free Software Foundation
-# gives unlimited permission to copy, distribute and modify it.
-
-# Defaults:
-ac_help=
-ac_default_prefix=/usr/local
-# Any additions from configure.in:
-ac_help="$ac_help
-  --with-pam           With PAM Support   "
-ac_help="$ac_help
-  --with-ldap          With LDAP Support   "
-ac_help="$ac_help
-  --with-db            For DB Support   "
-ac_help="$ac_help
-  --with-mysql         With MySQL Support   "
-ac_help="$ac_help
-  --with-mysql-prefix=PREFIX  Mysql prefix [default=/usr]"
-ac_help="$ac_help
-  --with-pgsql         With PgSQL Support   "
-ac_help="$ac_help
-  --with-pgsql-prefix=PREFIX  PgSQL prefix [default=/usr]"
-ac_help="$ac_help
-  --with-tacuid=ID     If you like to run tac_plus other than root user (no default value) "
-ac_help="$ac_help
-  --with-tacgid=GID    If you like to run tac_plus other than root group(no default value) "
-ac_help="$ac_help
-  --enable-maxsess     Enable maxsess feature "
-ac_help="$ac_help
-  --with-tacplus_pid=PREFIX  Tac_plus pid file location [default=/var/run] "
-ac_help="$ac_help
-  --with-libwrap[=PATH]   Compile in libwrap (tcp_wrappers) support."
-
-# Initialize some variables set by options.
-# The variables have the same names as the options, with
-# dashes changed to underlines.
-build=NONE
-cache_file=./config.cache
-exec_prefix=NONE
-host=NONE
-no_create=
-nonopt=NONE
-no_recursion=
-prefix=NONE
-program_prefix=NONE
-program_suffix=NONE
-program_transform_name=s,x,x,
-silent=
-site=
-srcdir=
-target=NONE
-verbose=
-x_includes=NONE
-x_libraries=NONE
-bindir='${exec_prefix}/bin'
-sbindir='${exec_prefix}/sbin'
-libexecdir='${exec_prefix}/libexec'
-datadir='${prefix}/share'
-sysconfdir='${prefix}/etc'
-sharedstatedir='${prefix}/com'
-localstatedir='${prefix}/var'
-libdir='${exec_prefix}/lib'
-includedir='${prefix}/include'
-oldincludedir='/usr/include'
-infodir='${prefix}/info'
-mandir='${prefix}/man'
-
-# Initialize some other variables.
-subdirs=
-MFLAGS= MAKEFLAGS=
-SHELL=${CONFIG_SHELL-/bin/sh}
-# Maximum number of lines to put in a shell here document.
-ac_max_here_lines=12
-
-ac_prev=
-for ac_option
-do
-
-  # If the previous option needs an argument, assign it.
-  if test -n "$ac_prev"; then
-    eval "$ac_prev=\$ac_option"
-    ac_prev=
-    continue
-  fi
-
-  case "$ac_option" in
-  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
-  *) ac_optarg= ;;
-  esac
-
-  # Accept the important Cygnus configure options, so we can diagnose typos.
-
-  case "$ac_option" in
-
-  -bindir | --bindir | --bindi | --bind | --bin | --bi)
-    ac_prev=bindir ;;
-  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
-    bindir="$ac_optarg" ;;
-
-  -build | --build | --buil | --bui | --bu)
-    ac_prev=build ;;
-  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
-    build="$ac_optarg" ;;
-
-  -cache-file | --cache-file | --cache-fil | --cache-fi \
-  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
-    ac_prev=cache_file ;;
-  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
-  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
-    cache_file="$ac_optarg" ;;
-
-  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
-    ac_prev=datadir ;;
-  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
-  | --da=*)
-    datadir="$ac_optarg" ;;
-
-  -disable-* | --disable-*)
-    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
-    # Reject names that are not valid shell variable names.
-    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
-      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
-    fi
-    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
-    eval "enable_${ac_feature}=no" ;;
-
-  -enable-* | --enable-*)
-    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
-    # Reject names that are not valid shell variable names.
-    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
-      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
-    fi
-    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
-    case "$ac_option" in
-      *=*) ;;
-      *) ac_optarg=yes ;;
-    esac
-    eval "enable_${ac_feature}='$ac_optarg'" ;;
-
-  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
-  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
-  | --exec | --exe | --ex)
-    ac_prev=exec_prefix ;;
-  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
-  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
-  | --exec=* | --exe=* | --ex=*)
-    exec_prefix="$ac_optarg" ;;
-
-  -gas | --gas | --ga | --g)
-    # Obsolete; use --with-gas.
-    with_gas=yes ;;
-
-  -help | --help | --hel | --he)
-    # Omit some internal or obsolete options to make the list less imposing.
-    # This message is too long to be a string in the A/UX 3.1 sh.
-    cat << EOF
-Usage: configure [options] [host]
-Options: [defaults in brackets after descriptions]
-Configuration:
-  --cache-file=FILE       cache test results in FILE
-  --help                  print this message
-  --no-create             do not create output files
-  --quiet, --silent       do not print \`checking...' messages
-  --version               print the version of autoconf that created configure
-Directory and file names:
-  --prefix=PREFIX         install architecture-independent files in PREFIX
-                          [$ac_default_prefix]
-  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
-                          [same as prefix]
-  --bindir=DIR            user executables in DIR [EPREFIX/bin]
-  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
-  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
-  --datadir=DIR           read-only architecture-independent data in DIR
-                          [PREFIX/share]
-  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
-  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
-                          [PREFIX/com]
-  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
-  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
-  --includedir=DIR        C header files in DIR [PREFIX/include]
-  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
-  --infodir=DIR           info documentation in DIR [PREFIX/info]
-  --mandir=DIR            man documentation in DIR [PREFIX/man]
-  --srcdir=DIR            find the sources in DIR [configure dir or ..]
-  --program-prefix=PREFIX prepend PREFIX to installed program names
-  --program-suffix=SUFFIX append SUFFIX to installed program names
-  --program-transform-name=PROGRAM
-                          run sed PROGRAM on installed program names
-EOF
-    cat << EOF
-Host type:
-  --build=BUILD           configure for building on BUILD [BUILD=HOST]
-  --host=HOST             configure for HOST [guessed]
-  --target=TARGET         configure for TARGET [TARGET=HOST]
-Features and packages:
-  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
-  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
-  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
-  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
-  --x-includes=DIR        X include files are in DIR
-  --x-libraries=DIR       X library files are in DIR
-EOF
-    if test -n "$ac_help"; then
-      echo "--enable and --with options recognized:$ac_help"
-    fi
-    exit 0 ;;
-
-  -host | --host | --hos | --ho)
-    ac_prev=host ;;
-  -host=* | --host=* | --hos=* | --ho=*)
-    host="$ac_optarg" ;;
-
-  -includedir | --includedir | --includedi | --included | --include \
-  | --includ | --inclu | --incl | --inc)
-    ac_prev=includedir ;;
-  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
-  | --includ=* | --inclu=* | --incl=* | --inc=*)
-    includedir="$ac_optarg" ;;
-
-  -infodir | --infodir | --infodi | --infod | --info | --inf)
-    ac_prev=infodir ;;
-  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
-    infodir="$ac_optarg" ;;
-
-  -libdir | --libdir | --libdi | --libd)
-    ac_prev=libdir ;;
-  -libdir=* | --libdir=* | --libdi=* | --libd=*)
-    libdir="$ac_optarg" ;;
-
-  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
-  | --libexe | --libex | --libe)
-    ac_prev=libexecdir ;;
-  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
-  | --libexe=* | --libex=* | --libe=*)
-    libexecdir="$ac_optarg" ;;
-
-  -localstatedir | --localstatedir | --localstatedi | --localstated \
-  | --localstate | --localstat | --localsta | --localst \
-  | --locals | --local | --loca | --loc | --lo)
-    ac_prev=localstatedir ;;
-  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
-  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
-  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
-    localstatedir="$ac_optarg" ;;
-
-  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
-    ac_prev=mandir ;;
-  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
-    mandir="$ac_optarg" ;;
-
-  -nfp | --nfp | --nf)
-    # Obsolete; use --without-fp.
-    with_fp=no ;;
-
-  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
-  | --no-cr | --no-c)
-    no_create=yes ;;
-
-  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
-  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
-    no_recursion=yes ;;
-
-  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
-  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
-  | --oldin | --oldi | --old | --ol | --o)
-    ac_prev=oldincludedir ;;
-  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
-  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
-  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
-    oldincludedir="$ac_optarg" ;;
-
-  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
-    ac_prev=prefix ;;
-  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
-    prefix="$ac_optarg" ;;
-
-  -program-prefix | --program-prefix | --program-prefi | --program-pref \
-  | --program-pre | --program-pr | --program-p)
-    ac_prev=program_prefix ;;
-  -program-prefix=* | --program-prefix=* | --program-prefi=* \
-  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
-    program_prefix="$ac_optarg" ;;
-
-  -program-suffix | --program-suffix | --program-suffi | --program-suff \
-  | --program-suf | --program-su | --program-s)
-    ac_prev=program_suffix ;;
-  -program-suffix=* | --program-suffix=* | --program-suffi=* \
-  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
-    program_suffix="$ac_optarg" ;;
-
-  -program-transform-name | --program-transform-name \
-  | --program-transform-nam | --program-transform-na \
-  | --program-transform-n | --program-transform- \
-  | --program-transform | --program-transfor \
-  | --program-transfo | --program-transf \
-  | --program-trans | --program-tran \
-  | --progr-tra | --program-tr | --program-t)
-    ac_prev=program_transform_name ;;
-  -program-transform-name=* | --program-transform-name=* \
-  | --program-transform-nam=* | --program-transform-na=* \
-  | --program-transform-n=* | --program-transform-=* \
-  | --program-transform=* | --program-transfor=* \
-  | --program-transfo=* | --program-transf=* \
-  | --program-trans=* | --program-tran=* \
-  | --progr-tra=* | --program-tr=* | --program-t=*)
-    program_transform_name="$ac_optarg" ;;
-
-  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
-  | -silent | --silent | --silen | --sile | --sil)
-    silent=yes ;;
-
-  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
-    ac_prev=sbindir ;;
-  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
-  | --sbi=* | --sb=*)
-    sbindir="$ac_optarg" ;;
-
-  -sharedstatedir | --sharedstatedir | --sharedstatedi \
-  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
-  | --sharedst | --shareds | --shared | --share | --shar \
-  | --sha | --sh)
-    ac_prev=sharedstatedir ;;
-  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
-  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
-  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
-  | --sha=* | --sh=*)
-    sharedstatedir="$ac_optarg" ;;
-
-  -site | --site | --sit)
-    ac_prev=site ;;
-  -site=* | --site=* | --sit=*)
-    site="$ac_optarg" ;;
-
-  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
-    ac_prev=srcdir ;;
-  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
-    srcdir="$ac_optarg" ;;
-
-  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
-  | --syscon | --sysco | --sysc | --sys | --sy)
-    ac_prev=sysconfdir ;;
-  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
-  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
-    sysconfdir="$ac_optarg" ;;
-
-  -target | --target | --targe | --targ | --tar | --ta | --t)
-    ac_prev=target ;;
-  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
-    target="$ac_optarg" ;;
-
-  -v | -verbose | --verbose | --verbos | --verbo | --verb)
-    verbose=yes ;;
-
-  -version | --version | --versio | --versi | --vers)
-    echo "configure generated by autoconf version 2.13"
-    exit 0 ;;
-
-  -with-* | --with-*)
-    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
-    # Reject names that are not valid shell variable names.
-    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
-      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
-    fi
-    ac_package=`echo $ac_package| sed 's/-/_/g'`
-    case "$ac_option" in
-      *=*) ;;
-      *) ac_optarg=yes ;;
-    esac
-    eval "with_${ac_package}='$ac_optarg'" ;;
-
-  -without-* | --without-*)
-    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
-    # Reject names that are not valid shell variable names.
-    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
-      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
-    fi
-    ac_package=`echo $ac_package| sed 's/-/_/g'`
-    eval "with_${ac_package}=no" ;;
-
-  --x)
-    # Obsolete; use --with-x.
-    with_x=yes ;;
-
-  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
-  | --x-incl | --x-inc | --x-in | --x-i)
-    ac_prev=x_includes ;;
-  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
-  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
-    x_includes="$ac_optarg" ;;
-
-  -x-libraries | --x-libraries | --x-librarie | --x-librari \
-  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
-    ac_prev=x_libraries ;;
-  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
-  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
-    x_libraries="$ac_optarg" ;;
-
-  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
-    ;;
-
-  *)
-    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
-      echo "configure: warning: $ac_option: invalid host type" 1>&2
-    fi
-    if test "x$nonopt" != xNONE; then
-      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
-    fi
-    nonopt="$ac_option"
-    ;;
-
-  esac
-done
-
-if test -n "$ac_prev"; then
-  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
-fi
-
-trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
-
-# File descriptor usage:
-# 0 standard input
-# 1 file creation
-# 2 errors and warnings
-# 3 some systems may open it to /dev/tty
-# 4 used on the Kubota Titan
-# 6 checking for... messages and results
-# 5 compiler messages saved in config.log
-if test "$silent" = yes; then
-  exec 6>/dev/null
-else
-  exec 6>&1
-fi
-exec 5>./config.log
-
-echo "\
-This file contains any messages produced by compilers while
-running configure, to aid debugging if configure makes a mistake.
-" 1>&5
-
-# Strip out --no-create and --no-recursion so they do not pile up.
-# Also quote any args containing shell metacharacters.
-ac_configure_args=
-for ac_arg
-do
-  case "$ac_arg" in
-  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
-  | --no-cr | --no-c) ;;
-  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
-  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
-  *" "*|*"     "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
-  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
-  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
-  esac
-done
-
-# NLS nuisances.
-# Only set these to C if already set.  These must not be set unconditionally
-# because not all systems understand e.g. LANG=C (notably SCO).
-# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
-# Non-C LC_CTYPE values break the ctype check.
-if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
-if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
-if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
-if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
-
-# confdefs.h avoids OS command line length limits that DEFS can exceed.
-rm -rf conftest* confdefs.h
-# AIX cpp loses on an empty file, so make sure it contains at least a newline.
-echo > confdefs.h
-
-# A filename unique to this package, relative to the directory that
-# configure is in, which we can look for to find out if srcdir is correct.
-ac_unique_file=
-
-# Find the source files, if location was not specified.
-if test -z "$srcdir"; then
-  ac_srcdir_defaulted=yes
-  # Try the directory containing this script, then its parent.
-  ac_prog=$0
-  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
-  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
-  srcdir=$ac_confdir
-  if test ! -r $srcdir/$ac_unique_file; then
-    srcdir=..
-  fi
-else
-  ac_srcdir_defaulted=no
-fi
-if test ! -r $srcdir/$ac_unique_file; then
-  if test "$ac_srcdir_defaulted" = yes; then
-    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
-  else
-    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
-  fi
-fi
-srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
-
-# Prefer explicitly selected file to automatically selected ones.
-if test -z "$CONFIG_SITE"; then
-  if test "x$prefix" != xNONE; then
-    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
-  else
-    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
-  fi
-fi
-for ac_site_file in $CONFIG_SITE; do
-  if test -r "$ac_site_file"; then
-    echo "loading site script $ac_site_file"
-    . "$ac_site_file"
-  fi
-done
-
-if test -r "$cache_file"; then
-  echo "loading cache $cache_file"
-  . $cache_file
-else
-  echo "creating cache $cache_file"
-  > $cache_file
-fi
-
-ac_ext=c
-# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
-cross_compiling=$ac_cv_prog_cc_cross
-
-ac_exeext=
-ac_objext=o
-if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
-  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
-  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
-    ac_n= ac_c='
-' ac_t='       '
-  else
-    ac_n=-n ac_c= ac_t=
-  fi
-else
-  ac_n= ac_c='\c' ac_t=
-fi
-
-
-
-echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
-echo "configure:551: checking whether ${MAKE-make} sets \${MAKE}" >&5
-set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftestmake <<\EOF
-all:
-       @echo 'ac_maketemp="${MAKE}"'
-EOF
-# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
-eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
-if test -n "$ac_maketemp"; then
-  eval ac_cv_prog_make_${ac_make}_set=yes
-else
-  eval ac_cv_prog_make_${ac_make}_set=no
-fi
-rm -f conftestmake
-fi
-if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-  SET_MAKE=
-else
-  echo "$ac_t""no" 1>&6
-  SET_MAKE="MAKE=${MAKE-make}"
-fi
-
-# Extract the first word of "gcc", so it can be a program name with args.
-set dummy gcc; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:580: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
-  ac_dummy="$PATH"
-  for ac_dir in $ac_dummy; do
-    test -z "$ac_dir" && ac_dir=.
-    if test -f $ac_dir/$ac_word; then
-      ac_cv_prog_CC="gcc"
-      break
-    fi
-  done
-  IFS="$ac_save_ifs"
-fi
-fi
-CC="$ac_cv_prog_CC"
-if test -n "$CC"; then
-  echo "$ac_t""$CC" 1>&6
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-if test -z "$CC"; then
-  # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:610: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
-  ac_prog_rejected=no
-  ac_dummy="$PATH"
-  for ac_dir in $ac_dummy; do
-    test -z "$ac_dir" && ac_dir=.
-    if test -f $ac_dir/$ac_word; then
-      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
-        ac_prog_rejected=yes
-       continue
-      fi
-      ac_cv_prog_CC="cc"
-      break
-    fi
-  done
-  IFS="$ac_save_ifs"
-if test $ac_prog_rejected = yes; then
-  # We found a bogon in the path, so make sure we never use it.
-  set dummy $ac_cv_prog_CC
-  shift
-  if test $# -gt 0; then
-    # We chose a different compiler from the bogus one.
-    # However, it has the same basename, so the bogon will be chosen
-    # first if we set CC to just the basename; use the full file name.
-    shift
-    set dummy "$ac_dir/$ac_word" "$@"
-    shift
-    ac_cv_prog_CC="$@"
-  fi
-fi
-fi
-fi
-CC="$ac_cv_prog_CC"
-if test -n "$CC"; then
-  echo "$ac_t""$CC" 1>&6
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-  if test -z "$CC"; then
-    case "`uname -s`" in
-    *win32* | *WIN32*)
-      # Extract the first word of "cl", so it can be a program name with args.
-set dummy cl; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:661: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
-  ac_dummy="$PATH"
-  for ac_dir in $ac_dummy; do
-    test -z "$ac_dir" && ac_dir=.
-    if test -f $ac_dir/$ac_word; then
-      ac_cv_prog_CC="cl"
-      break
-    fi
-  done
-  IFS="$ac_save_ifs"
-fi
-fi
-CC="$ac_cv_prog_CC"
-if test -n "$CC"; then
-  echo "$ac_t""$CC" 1>&6
-else
-  echo "$ac_t""no" 1>&6
-fi
- ;;
-    esac
-  fi
-  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
-fi
-
-echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
-echo "configure:693: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
-
-ac_ext=c
-# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
-cross_compiling=$ac_cv_prog_cc_cross
-
-cat > conftest.$ac_ext << EOF
-
-#line 704 "configure"
-#include "confdefs.h"
-
-main(){return(0);}
-EOF
-if { (eval echo configure:709: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  ac_cv_prog_cc_works=yes
-  # If we can't run a trivial program, we are probably using a cross compiler.
-  if (./conftest; exit) 2>/dev/null; then
-    ac_cv_prog_cc_cross=no
-  else
-    ac_cv_prog_cc_cross=yes
-  fi
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  ac_cv_prog_cc_works=no
-fi
-rm -fr conftest*
-ac_ext=c
-# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
-cross_compiling=$ac_cv_prog_cc_cross
-
-echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
-if test $ac_cv_prog_cc_works = no; then
-  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
-fi
-echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
-echo "configure:735: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
-echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
-cross_compiling=$ac_cv_prog_cc_cross
-
-echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
-echo "configure:740: checking whether we are using GNU C" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.c <<EOF
-#ifdef __GNUC__
-  yes;
-#endif
-EOF
-if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:749: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
-  ac_cv_prog_gcc=yes
-else
-  ac_cv_prog_gcc=no
-fi
-fi
-
-echo "$ac_t""$ac_cv_prog_gcc" 1>&6
-
-if test $ac_cv_prog_gcc = yes; then
-  GCC=yes
-else
-  GCC=
-fi
-
-ac_test_CFLAGS="${CFLAGS+set}"
-ac_save_CFLAGS="$CFLAGS"
-CFLAGS=
-echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
-echo "configure:768: checking whether ${CC-cc} accepts -g" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  echo 'void f(){}' > conftest.c
-if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
-  ac_cv_prog_cc_g=yes
-else
-  ac_cv_prog_cc_g=no
-fi
-rm -f conftest*
-
-fi
-
-echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
-if test "$ac_test_CFLAGS" = set; then
-  CFLAGS="$ac_save_CFLAGS"
-elif test $ac_cv_prog_cc_g = yes; then
-  if test "$GCC" = yes; then
-    CFLAGS="-g -O2"
-  else
-    CFLAGS="-g"
-  fi
-else
-  if test "$GCC" = yes; then
-    CFLAGS="-O2"
-  else
-    CFLAGS=
-  fi
-fi
-
-
-ac_aux_dir=
-for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
-  if test -f $ac_dir/install-sh; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/install-sh -c"
-    break
-  elif test -f $ac_dir/install.sh; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/install.sh -c"
-    break
-  fi
-done
-if test -z "$ac_aux_dir"; then
-  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
-fi
-ac_config_guess=$ac_aux_dir/config.guess
-ac_config_sub=$ac_aux_dir/config.sub
-ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
-
-
-# Do some error checking and defaulting for the host and target type.
-# The inputs are:
-#    configure --host=HOST --target=TARGET --build=BUILD NONOPT
-#
-# The rules are:
-# 1. You are not allowed to specify --host, --target, and nonopt at the
-#    same time.
-# 2. Host defaults to nonopt.
-# 3. If nonopt is not specified, then host defaults to the current host,
-#    as determined by config.guess.
-# 4. Target and build default to nonopt.
-# 5. If nonopt is not specified, then target and build default to host.
-
-# The aliases save the names the user supplied, while $host etc.
-# will get canonicalized.
-case $host---$target---$nonopt in
-NONE---*---* | *---NONE---* | *---*---NONE) ;;
-*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;;
-esac
-
-
-# Make sure we can run config.sub.
-if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
-else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
-fi
-
-echo $ac_n "checking host system type""... $ac_c" 1>&6
-echo "configure:847: checking host system type" >&5
-
-host_alias=$host
-case "$host_alias" in
-NONE)
-  case $nonopt in
-  NONE)
-    if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
-    else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
-    fi ;;
-  *) host_alias=$nonopt ;;
-  esac ;;
-esac
-
-host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
-host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
-host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
-host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
-echo "$ac_t""$host" 1>&6
-
-echo $ac_n "checking target system type""... $ac_c" 1>&6
-echo "configure:868: checking target system type" >&5
-
-target_alias=$target
-case "$target_alias" in
-NONE)
-  case $nonopt in
-  NONE) target_alias=$host_alias ;;
-  *) target_alias=$nonopt ;;
-  esac ;;
-esac
-
-target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias`
-target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
-target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
-target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
-echo "$ac_t""$target" 1>&6
-
-echo $ac_n "checking build system type""... $ac_c" 1>&6
-echo "configure:886: checking build system type" >&5
-
-build_alias=$build
-case "$build_alias" in
-NONE)
-  case $nonopt in
-  NONE) build_alias=$host_alias ;;
-  *) build_alias=$nonopt ;;
-  esac ;;
-esac
-
-build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias`
-build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
-build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
-build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
-echo "$ac_t""$build" 1>&6
-
-test "$host_alias" != "$target_alias" &&
-  test "$program_prefix$program_suffix$program_transform_name" = \
-    NONENONEs,x,x, &&
-  program_prefix=${target_alias}-
-
-
-case $host_os in 
-       *linux-gnu)
-       OS="-DLINUX -DGLIBC"
-       ;;
-       *solaris)
-       OS="-DSOLARIS"
-       ;;
-       *freebsd)
-       OS="-DFREEBSD"
-       ;;
-       *hpux)
-       OS="-DHPUX"
-       ;;
-       *aix)
-       OS="-DAIX"
-       ;;
-       *)
-       ;;
-esac
-       
-echo $ac_n "checking for main in -lnsl""... $ac_c" 1>&6
-echo "configure:930: checking for main in -lnsl" >&5
-ac_lib_var=`echo nsl'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-lnsl  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 938 "configure"
-#include "confdefs.h"
-
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:945: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
-
-  LIBS="-lnsl $LIBS"
-
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-echo $ac_n "checking for main in -log""... $ac_c" 1>&6
-echo "configure:973: checking for main in -log" >&5
-ac_lib_var=`echo og'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-log  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 981 "configure"
-#include "confdefs.h"
-
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:988: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo og | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
-
-  LIBS="-log $LIBS"
-
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-echo $ac_n "checking for main in -lldap""... $ac_c" 1>&6
-echo "configure:1016: checking for main in -lldap" >&5
-ac_lib_var=`echo ldap'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-lldap  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1024 "configure"
-#include "confdefs.h"
-
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:1031: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo ldap | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
-
-  LIBS="-lldap $LIBS"
-
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-echo $ac_n "checking for main in -llber""... $ac_c" 1>&6
-echo "configure:1059: checking for main in -llber" >&5
-ac_lib_var=`echo lber'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-llber  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1067 "configure"
-#include "confdefs.h"
-
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:1074: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo lber | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
-
-  LIBS="-llber $LIBS"
-
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-echo $ac_n "checking for main in -lsocket""... $ac_c" 1>&6
-echo "configure:1102: checking for main in -lsocket" >&5
-ac_lib_var=`echo socket'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-lsocket  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1110 "configure"
-#include "confdefs.h"
-
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:1117: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
-
-  LIBS="-lsocket $LIBS"
-
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6
-echo "configure:1145: checking for crypt in -lcrypt" >&5
-ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-lcrypt  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1153 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char crypt();
-
-int main() {
-crypt()
-; return 0; }
-EOF
-if { (eval echo configure:1164: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo crypt | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
-
-  LIBS="-lcrypt $LIBS"
-
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-echo $ac_n "checking for printf in -lc""... $ac_c" 1>&6
-echo "configure:1192: checking for printf in -lc" >&5
-ac_lib_var=`echo c'_'printf | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-lc  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1200 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char printf();
-
-int main() {
-printf()
-; return 0; }
-EOF
-if { (eval echo configure:1211: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo c | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
-
-  LIBS="-lc $LIBS"
-
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-
-
-
-
-echo $ac_n "checking for PAM support:""... $ac_c" 1>&6
-echo "configure:1243: checking for PAM support:" >&5
-echo
-# Check whether --with-pam or --without-pam was given.
-if test "${with_pam+set}" = set; then
-  withval="$with_pam"
-  :
-fi
-
-if test "x$with_pam" = "xyes";then
-       echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
-echo "configure:1253: checking for dlopen in -ldl" >&5
-ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-ldl  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1261 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char dlopen();
-
-int main() {
-dlopen()
-; return 0; }
-EOF
-if { (eval echo configure:1272: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo dl | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
-
-  LIBS="-ldl $LIBS"
-
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-       echo $ac_n "checking for pam_start in -lpam""... $ac_c" 1>&6
-echo "configure:1300: checking for pam_start in -lpam" >&5
-ac_lib_var=`echo pam'_'pam_start | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-lpam  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1308 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char pam_start();
-
-int main() {
-pam_start()
-; return 0; }
-EOF
-if { (eval echo configure:1319: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo pam | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
-
-  LIBS="-lpam $LIBS"
-
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-       DEFINES="-DUSE_PAM $DEFINES";
-        echo "$ac_t""Pam support... yes" 1>&6
-else
-        echo "$ac_t""Pam support... no" 1>&6
-fi
-
-echo $ac_n "checking for LDAP support""... $ac_c" 1>&6
-echo "configure:1353: checking for LDAP support" >&5
-echo
-# Check whether --with-ldap or --without-ldap was given.
-if test "${with_ldap+set}" = set; then
-  withval="$with_ldap"
-  :
-fi
-
-
-if test "x$with_ldap" = "xyes";then
-   echo $ac_n "checking for ldap_simple_bind_s in -lldap""... $ac_c" 1>&6
-echo "configure:1364: checking for ldap_simple_bind_s in -lldap" >&5
-ac_lib_var=`echo ldap'_'ldap_simple_bind_s | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-lldap  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1372 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char ldap_simple_bind_s();
-
-int main() {
-ldap_simple_bind_s()
-; return 0; }
-EOF
-if { (eval echo configure:1383: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo ldap | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
-
-  LIBS="-lldap $LIBS"
-
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-   echo $ac_n "checking for ldap_init in -lldap""... $ac_c" 1>&6
-echo "configure:1411: checking for ldap_init in -lldap" >&5
-ac_lib_var=`echo ldap'_'ldap_init | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-lldap  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1419 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char ldap_init();
-
-int main() {
-ldap_init()
-; return 0; }
-EOF
-if { (eval echo configure:1430: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo ldap | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
-
-  LIBS="-lldap $LIBS"
-
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-   DEFINES="-DUSE_LDAP $DEFINES"
-        echo "$ac_t""LDAP support... yes" 1>&6
-else
-        echo "$ac_t""LDAP support... no" 1>&6
-fi
-
-echo $ac_n "checking for DB support""... $ac_c" 1>&6
-echo "configure:1465: checking for DB support" >&5
-echo 
-# Check whether --with-db or --without-db was given.
-if test "${with_db+set}" = set; then
-  withval="$with_db"
-  :
-fi
-
-if test "x$with_db" = "xyes";then
-       DB="$DB -DDB -DDB_NULL" 
-       echo "$ac_t""DB support... yes" 1>&6
-else
-       echo "$ac_t""DB support... no" 1>&6
-fi
-
-if test "x$with_db" = "xyes";then
-
-echo "Check for MySQL support:"
-
-# Check whether --with-mysql or --without-mysql was given.
-if test "${with_mysql+set}" = set; then
-  withval="$with_mysql"
-  :
-fi
-
-
-# Check whether --with-mysql-prefix or --without-mysql-prefix was given.
-if test "${with_mysql_prefix+set}" = set; then
-  withval="$with_mysql_prefix"
-  MYSQL_PREFIX=$withval
-else
-  MYSQL_PREFIX=/usr
-
-fi
-
-
-
-if test "x$with_mysql" = "xyes";then
-       
-       LDFLAGS="-L$MYSQL_PREFIX/lib/mysql $LDFLAGS"
-        LDFLAGS="-I$MYSQL_PREFIX/include/mysql $LDFLAGS"
-        echo $ac_n "checking for mysql_init in -lmysqlclient""... $ac_c" 1>&6
-echo "configure:1507: checking for mysql_init in -lmysqlclient" >&5
-ac_lib_var=`echo mysqlclient'_'mysql_init | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-lmysqlclient -lm $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1515 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char mysql_init();
-
-int main() {
-mysql_init()
-; return 0; }
-EOF
-if { (eval echo configure:1526: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-  LIBS="-lmysqlclient -lm $LIBS"
-else
-  echo "$ac_t""no" 1>&6
-{ echo "configure: error: *** couldn't find libmysqlclient" 1>&2; exit 1; }
-fi
-
-
-       DB="$DB -DDB_MYSQL";
-        echo "$ac_t""Mysql support... yes" 1>&6
-else
-        echo "$ac_t""Mysql support... no" 1>&6
-fi
-
-fi
-
-if test "x$with_db" = "xyes";then
-
-echo "Check for PgSQL support:"
-
-# Check whether --with-pgsql or --without-pgsql was given.
-if test "${with_pgsql+set}" = set; then
-  withval="$with_pgsql"
-  :
-fi
-
-
-# Check whether --with-pgsql-prefix or --without-pgsql-prefix was given.
-if test "${with_pgsql_prefix+set}" = set; then
-  withval="$with_pgsql_prefix"
-  PGSQL_PREFIX=$withval
-else
-  PGSQL_PREFIX=/usr
-
-fi
-
-
-
-if test "x$with_pgsql" = "xyes";then
-       
-       LDFLAGS="-L$PGSQL_PREFIX/lib/pgsql $LDFLAGS"
-        LDFLAGS="-I$PGSQL_PREFIX/include/pgsql $LDFLAGS"
-        echo $ac_n "checking for PQconnectdb  in -lpq""... $ac_c" 1>&6
-echo "configure:1583: checking for PQconnectdb  in -lpq" >&5
-ac_lib_var=`echo pq'_'PQconnectdb  | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-lpq  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1591 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char PQconnectdb ();
-
-int main() {
-PQconnectdb ()
-; return 0; }
-EOF
-if { (eval echo configure:1602: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-  LIBS="-lpq $LIBS"
-else
-  echo "$ac_t""no" 1>&6
-{ echo "configure: error: *** couldn't find libpq" 1>&2; exit 1; }
-fi
-
-
-       DB="$DB -DDB_PGSQL";
-        echo "$ac_t""Pgsql support... yes" 1>&6
-else
-        echo "$ac_t""Pgsql support... no" 1>&6
-fi
-
-fi
-
-
-# Check whether --with-tacuid or --without-tacuid was given.
-if test "${with_tacuid+set}" = set; then
-  withval="$with_tacuid"
-  :
-fi
-
-# Check whether --with-tacgid or --without-tacgid was given.
-if test "${with_tacgid+set}" = set; then
-  withval="$with_tacgid"
-  :
-fi
-
-
-
-if (test "x$with_tacuid" != "x" && test "x$with_tacgid" != "x" && test "x$with_tacuid" != "xyes" && test "x$with_tacgid" != "xyes");then
-
-       DEFINES="-DTACPLUS_USERID=$with_tacuid -DTACPLUS_GROUPID=$with_tacgid $DEFINES";        
-       echo "$ac_t""tacacs+ work with given user and group id" 1>&6 
-fi
-
-echo $ac_n "checking whether to enable the maxsess feature""... $ac_c" 1>&6
-echo "configure:1654: checking whether to enable the maxsess feature" >&5
-# Check whether --enable-maxsess or --disable-maxsess was given.
-if test "${enable_maxsess+set}" = set; then
-  enableval="$enable_maxsess"
-  
-if test "$enableval" = "yes";then
-       DEFINES="-DMAXSESS $DEFINES";
-       echo "$ac_t""yes" 1>&6
-else 
-       echo "$ac_t""no" 1>&6
-fi
-
-else
-  
-       echo "$ac_t""no" 1>&6
-
-fi
-
-
-
-# Check whether --with-tacplus_pid or --without-tacplus_pid was given.
-if test "${with_tacplus_pid+set}" = set; then
-  withval="$with_tacplus_pid"
-  PIDFILE="-DTACPLUS_PIDFILE=\\\"$withval/tac_plus.pid\\\""
-else
-  PIDFILE="-DTACPLUS_PIDFILE=\\\"/var/run/tac_plus.pid\\\""
-
-fi
-
-
-echo $ac_n "checking whether to enable the libwrap feture""... $ac_c" 1>&6
-echo "configure:1685: checking whether to enable the libwrap feture" >&5
-
-# Check whether --with-libwrap or --without-libwrap was given.
-if test "${with_libwrap+set}" = set; then
-  withval="$with_libwrap"
-   case "$withval" in
-  no)
-    echo "$ac_t""no" 1>&6
-    ;;
-  yes)
-    echo "$ac_t""yes" 1>&6
-    echo $ac_n "checking for request_init in -lwrap""... $ac_c" 1>&6
-echo "configure:1697: checking for request_init in -lwrap" >&5
-ac_lib_var=`echo wrap'_'request_init | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-lwrap  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1705 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char request_init();
-
-int main() {
-request_init()
-; return 0; }
-EOF
-if { (eval echo configure:1716: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-  
-        LIBS="-lwrap $LIBS"
-        DEFINES="-DTCPWRAPPER $DEFINES"
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-    ;;
-  *)
-    echo "$ac_t""yes" 1>&6
-    if test -d "$withval"; then
-        LDFLAGS="-L$withval $LDFLAGS"
-       DEFINES="-DTCPWRAPPER $DEFINES"
-    fi
-    cat > conftest.$ac_ext <<EOF
-#line 1746 "configure"
-#include "confdefs.h"
- int allow_severity; int deny_severity; 
-int main() {
- hosts_access(); 
-; return 0; }
-EOF
-if { (eval echo configure:1753: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  :
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-   { echo "configure: error: Could not find the $withval library.  You must first install tcp_wrappers." 1>&2; exit 1; } 
-fi
-rm -f conftest*
-    ;;
-  esac 
-else
-  echo "$ac_t""no" 1>&6
-
-fi
-
-
-
-
-
-
-
-echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:1776: checking how to run the C preprocessor" >&5
-# On Suns, sometimes $CPP names a directory.
-if test -n "$CPP" && test -d "$CPP"; then
-  CPP=
-fi
-if test -z "$CPP"; then
-if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-    # This must be in double quotes, not single quotes, because CPP may get
-  # substituted into the Makefile and "${CC-cc}" will confuse make.
-  CPP="${CC-cc} -E"
-  # On the NeXT, cc -E runs the code through the compiler's parser,
-  # not just through cpp.
-  cat > conftest.$ac_ext <<EOF
-#line 1791 "configure"
-#include "confdefs.h"
-#include <assert.h>
-Syntax Error
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1797: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
-  :
-else
-  echo "$ac_err" >&5
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  CPP="${CC-cc} -E -traditional-cpp"
-  cat > conftest.$ac_ext <<EOF
-#line 1808 "configure"
-#include "confdefs.h"
-#include <assert.h>
-Syntax Error
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1814: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
-  :
-else
-  echo "$ac_err" >&5
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  CPP="${CC-cc} -nologo -E"
-  cat > conftest.$ac_ext <<EOF
-#line 1825 "configure"
-#include "confdefs.h"
-#include <assert.h>
-Syntax Error
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1831: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
-  :
-else
-  echo "$ac_err" >&5
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  CPP=/lib/cpp
-fi
-rm -f conftest*
-fi
-rm -f conftest*
-fi
-rm -f conftest*
-  ac_cv_prog_CPP="$CPP"
-fi
-  CPP="$ac_cv_prog_CPP"
-else
-  ac_cv_prog_CPP="$CPP"
-fi
-echo "$ac_t""$CPP" 1>&6
-
-echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:1856: checking for ANSI C header files" >&5
-if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 1861 "configure"
-#include "confdefs.h"
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <float.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1869: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
-  rm -rf conftest*
-  ac_cv_header_stdc=yes
-else
-  echo "$ac_err" >&5
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-if test $ac_cv_header_stdc = yes; then
-  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
-cat > conftest.$ac_ext <<EOF
-#line 1886 "configure"
-#include "confdefs.h"
-#include <string.h>
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  egrep "memchr" >/dev/null 2>&1; then
-  :
-else
-  rm -rf conftest*
-  ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
-  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
-cat > conftest.$ac_ext <<EOF
-#line 1904 "configure"
-#include "confdefs.h"
-#include <stdlib.h>
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  egrep "free" >/dev/null 2>&1; then
-  :
-else
-  rm -rf conftest*
-  ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
-  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
-if test "$cross_compiling" = yes; then
-  :
-else
-  cat > conftest.$ac_ext <<EOF
-#line 1925 "configure"
-#include "confdefs.h"
-#include <ctype.h>
-#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int main () { int i; for (i = 0; i < 256; i++)
-if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
-exit (0); }
-
-EOF
-if { (eval echo configure:1936: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
-then
-  :
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -fr conftest*
-  ac_cv_header_stdc=no
-fi
-rm -fr conftest*
-fi
-
-fi
-fi
-
-echo "$ac_t""$ac_cv_header_stdc" 1>&6
-if test $ac_cv_header_stdc = yes; then
-  cat >> confdefs.h <<\EOF
-#define STDC_HEADERS 1
-EOF
-
-fi
-
-for ac_hdr in fcntl.h malloc.h strings.h sys/file.h sys/ioctl.h sys/time.h syslog.h unistd.h
-do
-ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1963: checking for $ac_hdr" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 1968 "configure"
-#include "confdefs.h"
-#include <$ac_hdr>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1973: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
-  rm -rf conftest*
-  eval "ac_cv_header_$ac_safe=yes"
-else
-  echo "$ac_err" >&5
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_hdr 1
-EOF
-else
-  echo "$ac_t""no" 1>&6
-fi
-done
-
-for ac_hdr in shadow.h
-do
-ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:2003: checking for $ac_hdr" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2008 "configure"
-#include "confdefs.h"
-#include <$ac_hdr>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2013: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
-  rm -rf conftest*
-  eval "ac_cv_header_$ac_safe=yes"
-else
-  echo "$ac_err" >&5
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_hdr 1
-EOF
-               if test -f /etc/shadow ; then
-                 cat >> confdefs.h <<\EOF
-#define SHADOW_PASSWORDS 1
-EOF
-               
-               fi 
-               
-else
-  echo "$ac_t""no" 1>&6
-fi
-done
-
-echo $ac_n "checking for working const""... $ac_c" 1>&6
-echo "configure:2047: checking for working const" >&5
-if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2052 "configure"
-#include "confdefs.h"
-
-int main() {
-
-/* Ultrix mips cc rejects this.  */
-typedef int charset[2]; const charset x;
-/* SunOS 4.1.1 cc rejects this.  */
-char const *const *ccp;
-char **p;
-/* NEC SVR4.0.2 mips cc rejects this.  */
-struct point {int x, y;};
-static struct point const zero = {0,0};
-/* AIX XL C 1.02.0.0 rejects this.
-   It does not let you subtract one const X* pointer from another in an arm
-   of an if-expression whose if-part is not a constant expression */
-const char *g = "string";
-ccp = &g + (g ? g-g : 0);
-/* HPUX 7.0 cc rejects these. */
-++ccp;
-p = (char**) ccp;
-ccp = (char const *const *) p;
-{ /* SCO 3.2v4 cc rejects this.  */
-  char *t;
-  char const *s = 0 ? (char *) 0 : (char const *) 0;
-
-  *t++ = 0;
-}
-{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
-  int x[] = {25, 17};
-  const int *foo = &x[0];
-  ++foo;
-}
-{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
-  typedef const int *iptr;
-  iptr p = 0;
-  ++p;
-}
-{ /* AIX XL C 1.02.0.0 rejects this saying
-     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
-  struct s { int j; const int *ap[3]; };
-  struct s *b; b->j = 5;
-}
-{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
-  const int foo = 10;
-}
-
-; return 0; }
-EOF
-if { (eval echo configure:2101: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
-  rm -rf conftest*
-  ac_cv_c_const=yes
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  ac_cv_c_const=no
-fi
-rm -f conftest*
-fi
-
-echo "$ac_t""$ac_cv_c_const" 1>&6
-if test $ac_cv_c_const = no; then
-  cat >> confdefs.h <<\EOF
-#define const 
-EOF
-
-fi
-
-echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
-echo "configure:2122: checking whether time.h and sys/time.h may both be included" >&5
-if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2127 "configure"
-#include "confdefs.h"
-#include <sys/types.h>
-#include <sys/time.h>
-#include <time.h>
-int main() {
-struct tm *tp;
-; return 0; }
-EOF
-if { (eval echo configure:2136: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
-  rm -rf conftest*
-  ac_cv_header_time=yes
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  ac_cv_header_time=no
-fi
-rm -f conftest*
-fi
-
-echo "$ac_t""$ac_cv_header_time" 1>&6
-if test $ac_cv_header_time = yes; then
-  cat >> confdefs.h <<\EOF
-#define TIME_WITH_SYS_TIME 1
-EOF
-
-fi
-
-
-if test $ac_cv_prog_gcc = yes; then
-    echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
-echo "configure:2159: checking whether ${CC-cc} needs -traditional" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-    ac_pattern="Autoconf.*'x'"
-  cat > conftest.$ac_ext <<EOF
-#line 2165 "configure"
-#include "confdefs.h"
-#include <sgtty.h>
-Autoconf TIOCGETP
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  egrep "$ac_pattern" >/dev/null 2>&1; then
-  rm -rf conftest*
-  ac_cv_prog_gcc_traditional=yes
-else
-  rm -rf conftest*
-  ac_cv_prog_gcc_traditional=no
-fi
-rm -f conftest*
-
-
-  if test $ac_cv_prog_gcc_traditional = no; then
-    cat > conftest.$ac_ext <<EOF
-#line 2183 "configure"
-#include "confdefs.h"
-#include <termio.h>
-Autoconf TCGETA
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  egrep "$ac_pattern" >/dev/null 2>&1; then
-  rm -rf conftest*
-  ac_cv_prog_gcc_traditional=yes
-fi
-rm -f conftest*
-
-  fi
-fi
-
-echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
-  if test $ac_cv_prog_gcc_traditional = yes; then
-    CC="$CC -traditional"
-  fi
-fi
-
-echo $ac_n "checking whether setpgrp takes no argument""... $ac_c" 1>&6
-echo "configure:2205: checking whether setpgrp takes no argument" >&5
-if eval "test \"`echo '$''{'ac_cv_func_setpgrp_void'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  if test "$cross_compiling" = yes; then
-  { echo "configure: error: cannot check setpgrp if cross compiling" 1>&2; exit 1; }
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2213 "configure"
-#include "confdefs.h"
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-/*
- * If this system has a BSD-style setpgrp, which takes arguments, exit
- * successfully.
- */
-main()
-{
-    if (setpgrp(1,1) == -1)
-       exit(0);
-    else
-       exit(1);
-}
-
-EOF
-if { (eval echo configure:2233: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
-then
-  ac_cv_func_setpgrp_void=no
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -fr conftest*
-  ac_cv_func_setpgrp_void=yes
-fi
-rm -fr conftest*
-fi
-
-
-fi
-
-echo "$ac_t""$ac_cv_func_setpgrp_void" 1>&6
-if test $ac_cv_func_setpgrp_void = yes; then
-  cat >> confdefs.h <<\EOF
-#define SETPGRP_VOID 1
-EOF
-
-fi
-
-echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
-echo "configure:2257: checking return type of signal handlers" >&5
-if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2262 "configure"
-#include "confdefs.h"
-#include <sys/types.h>
-#include <signal.h>
-#ifdef signal
-#undef signal
-#endif
-#ifdef __cplusplus
-extern "C" void (*signal (int, void (*)(int)))(int);
-#else
-void (*signal ()) ();
-#endif
-
-int main() {
-int i;
-; return 0; }
-EOF
-if { (eval echo configure:2279: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
-  rm -rf conftest*
-  ac_cv_type_signal=void
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  ac_cv_type_signal=int
-fi
-rm -f conftest*
-fi
-
-echo "$ac_t""$ac_cv_type_signal" 1>&6
-cat >> confdefs.h <<EOF
-#define RETSIGTYPE $ac_cv_type_signal
-EOF
-
-
-echo $ac_n "checking for vprintf""... $ac_c" 1>&6
-echo "configure:2298: checking for vprintf" >&5
-if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2303 "configure"
-#include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char vprintf(); below.  */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char vprintf();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined (__stub_vprintf) || defined (__stub___vprintf)
-choke me
-#else
-vprintf();
-#endif
-
-; return 0; }
-EOF
-if { (eval echo configure:2326: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_func_vprintf=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_func_vprintf=no"
-fi
-rm -f conftest*
-fi
-
-if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-  cat >> confdefs.h <<\EOF
-#define HAVE_VPRINTF 1
-EOF
-
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-if test "$ac_cv_func_vprintf" != yes; then
-echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
-echo "configure:2350: checking for _doprnt" >&5
-if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2355 "configure"
-#include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char _doprnt(); below.  */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char _doprnt();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined (__stub__doprnt) || defined (__stub____doprnt)
-choke me
-#else
-_doprnt();
-#endif
-
-; return 0; }
-EOF
-if { (eval echo configure:2378: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_func__doprnt=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_func__doprnt=no"
-fi
-rm -f conftest*
-fi
-
-if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-  cat >> confdefs.h <<\EOF
-#define HAVE_DOPRNT 1
-EOF
-
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-fi
-
-echo $ac_n "checking for wait3 that fills in rusage""... $ac_c" 1>&6
-echo "configure:2403: checking for wait3 that fills in rusage" >&5
-if eval "test \"`echo '$''{'ac_cv_func_wait3_rusage'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  if test "$cross_compiling" = yes; then
-  ac_cv_func_wait3_rusage=no
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2411 "configure"
-#include "confdefs.h"
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <stdio.h>
-/* HP-UX has wait3 but does not fill in rusage at all.  */
-main() {
-  struct rusage r;
-  int i;
-  /* Use a field that we can force nonzero --
-     voluntary context switches.
-     For systems like NeXT and OSF/1 that don't set it,
-     also use the system CPU time.  And page faults (I/O) for Linux.  */
-  r.ru_nvcsw = 0;
-  r.ru_stime.tv_sec = 0;
-  r.ru_stime.tv_usec = 0;
-  r.ru_majflt = r.ru_minflt = 0;
-  switch (fork()) {
-  case 0: /* Child.  */
-    sleep(1); /* Give up the CPU.  */
-    _exit(0);
-  case -1: _exit(0); /* What can we do?  */
-  default: /* Parent.  */
-    wait3(&i, 0, &r);
-    sleep(2); /* Avoid "text file busy" from rm on fast HP-UX machines.  */
-    exit(r.ru_nvcsw == 0 && r.ru_majflt == 0 && r.ru_minflt == 0
-        && r.ru_stime.tv_sec == 0 && r.ru_stime.tv_usec == 0);
-  }
-}
-EOF
-if { (eval echo configure:2442: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
-then
-  ac_cv_func_wait3_rusage=yes
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -fr conftest*
-  ac_cv_func_wait3_rusage=no
-fi
-rm -fr conftest*
-fi
-
-fi
-
-echo "$ac_t""$ac_cv_func_wait3_rusage" 1>&6
-if test $ac_cv_func_wait3_rusage = yes; then
-  cat >> confdefs.h <<\EOF
-#define HAVE_WAIT3 1
-EOF
-
-fi
-
-for ac_func in regcomp select socket strcspn strdup strtol
-do
-echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2467: checking for $ac_func" >&5
-if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2472 "configure"
-#include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func(); below.  */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char $ac_func();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
-choke me
-#else
-$ac_func();
-#endif
-
-; return 0; }
-EOF
-if { (eval echo configure:2495: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_func_$ac_func=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_func_$ac_func=no"
-fi
-rm -f conftest*
-fi
-
-if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_func 1
-EOF
-else
-  echo "$ac_t""no" 1>&6
-fi
-done
-
-
-trap '' 1 2 15
-cat > confcache <<\EOF
-# This file is a shell script that caches the results of configure
-# tests run on this system so they can be shared between configure
-# scripts and configure runs.  It is not useful on other systems.
-# If it contains results you don't want to keep, you may remove or edit it.
-#
-# By default, configure uses ./config.cache as the cache file,
-# creating it if it does not exist already.  You can give configure
-# the --cache-file=FILE option to use a different cache file; that is
-# what configure does when it calls configure scripts in
-# subdirectories, so they share the cache.
-# Giving --cache-file=/dev/null disables caching, for debugging configure.
-# config.status only pays attention to the cache file if you give it the
-# --recheck option to rerun configure.
-#
-EOF
-# The following way of writing the cache mishandles newlines in values,
-# but we know of no workaround that is simple, portable, and efficient.
-# So, don't put newlines in cache variables' values.
-# Ultrix sh set writes to stderr and can't be redirected directly,
-# and sets the high bit in the cache file unless we assign to the vars.
-(set) 2>&1 |
-  case `(ac_space=' '; set | grep ac_space) 2>&1` in
-  *ac_space=\ *)
-    # `set' does not quote correctly, so add quotes (double-quote substitution
-    # turns \\\\ into \\, and sed turns \\ into \).
-    sed -n \
-      -e "s/'/'\\\\''/g" \
-      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
-    ;;
-  *)
-    # `set' quotes correctly as required by POSIX, so do not add quotes.
-    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
-    ;;
-  esac >> confcache
-if cmp -s $cache_file confcache; then
-  :
-else
-  if test -w $cache_file; then
-    echo "updating cache $cache_file"
-    cat confcache > $cache_file
-  else
-    echo "not updating unwritable cache $cache_file"
-  fi
-fi
-rm -f confcache
-
-trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
-
-test "x$prefix" = xNONE && prefix=$ac_default_prefix
-# Let make expand exec_prefix.
-test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
-
-# Any assignment to VPATH causes Sun make to only execute
-# the first set of double-colon rules, so remove it if not needed.
-# If there is a colon in the path, we need to keep it.
-if test "x$srcdir" = x.; then
-  ac_vpsub='/^[        ]*VPATH[        ]*=[^:]*$/d'
-fi
-
-trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
-
-DEFS=-DHAVE_CONFIG_H
-
-# Without the "./", some shells look in PATH for config.status.
-: ${CONFIG_STATUS=./config.status}
-
-echo creating $CONFIG_STATUS
-rm -f $CONFIG_STATUS
-cat > $CONFIG_STATUS <<EOF
-#! /bin/sh
-# Generated automatically by configure.
-# Run this file to recreate the current configuration.
-# This directory was configured as follows,
-# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
-#
-# $0 $ac_configure_args
-#
-# Compiler output produced by configure, useful for debugging
-# configure, is in ./config.log if it exists.
-
-ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
-for ac_option
-do
-  case "\$ac_option" in
-  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
-    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
-    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
-  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
-    echo "$CONFIG_STATUS generated by autoconf version 2.13"
-    exit 0 ;;
-  -help | --help | --hel | --he | --h)
-    echo "\$ac_cs_usage"; exit 0 ;;
-  *) echo "\$ac_cs_usage"; exit 1 ;;
-  esac
-done
-
-ac_given_srcdir=$srcdir
-
-trap 'rm -fr `echo "Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
-EOF
-cat >> $CONFIG_STATUS <<EOF
-
-# Protect against being on the right side of a sed subst in config.status.
-sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
- s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
-$ac_vpsub
-$extrasub
-s%@SHELL@%$SHELL%g
-s%@CFLAGS@%$CFLAGS%g
-s%@CPPFLAGS@%$CPPFLAGS%g
-s%@CXXFLAGS@%$CXXFLAGS%g
-s%@FFLAGS@%$FFLAGS%g
-s%@DEFS@%$DEFS%g
-s%@LDFLAGS@%$LDFLAGS%g
-s%@LIBS@%$LIBS%g
-s%@exec_prefix@%$exec_prefix%g
-s%@prefix@%$prefix%g
-s%@program_transform_name@%$program_transform_name%g
-s%@bindir@%$bindir%g
-s%@sbindir@%$sbindir%g
-s%@libexecdir@%$libexecdir%g
-s%@datadir@%$datadir%g
-s%@sysconfdir@%$sysconfdir%g
-s%@sharedstatedir@%$sharedstatedir%g
-s%@localstatedir@%$localstatedir%g
-s%@libdir@%$libdir%g
-s%@includedir@%$includedir%g
-s%@oldincludedir@%$oldincludedir%g
-s%@infodir@%$infodir%g
-s%@mandir@%$mandir%g
-s%@SET_MAKE@%$SET_MAKE%g
-s%@CC@%$CC%g
-s%@host@%$host%g
-s%@host_alias@%$host_alias%g
-s%@host_cpu@%$host_cpu%g
-s%@host_vendor@%$host_vendor%g
-s%@host_os@%$host_os%g
-s%@target@%$target%g
-s%@target_alias@%$target_alias%g
-s%@target_cpu@%$target_cpu%g
-s%@target_vendor@%$target_vendor%g
-s%@target_os@%$target_os%g
-s%@build@%$build%g
-s%@build_alias@%$build_alias%g
-s%@build_cpu@%$build_cpu%g
-s%@build_vendor@%$build_vendor%g
-s%@build_os@%$build_os%g
-s%@DEFINES@%$DEFINES%g
-s%@PIDFILE@%$PIDFILE%g
-s%@DB@%$DB%g
-s%@OS@%$OS%g
-s%@CPP@%$CPP%g
-
-CEOF
-EOF
-
-cat >> $CONFIG_STATUS <<\EOF
-
-# Split the substitutions into bite-sized pieces for seds with
-# small command number limits, like on Digital OSF/1 and HP-UX.
-ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
-ac_file=1 # Number of current file.
-ac_beg=1 # First line for current file.
-ac_end=$ac_max_sed_cmds # Line after last line for current file.
-ac_more_lines=:
-ac_sed_cmds=""
-while $ac_more_lines; do
-  if test $ac_beg -gt 1; then
-    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
-  else
-    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
-  fi
-  if test ! -s conftest.s$ac_file; then
-    ac_more_lines=false
-    rm -f conftest.s$ac_file
-  else
-    if test -z "$ac_sed_cmds"; then
-      ac_sed_cmds="sed -f conftest.s$ac_file"
-    else
-      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
-    fi
-    ac_file=`expr $ac_file + 1`
-    ac_beg=$ac_end
-    ac_end=`expr $ac_end + $ac_max_sed_cmds`
-  fi
-done
-if test -z "$ac_sed_cmds"; then
-  ac_sed_cmds=cat
-fi
-EOF
-
-cat >> $CONFIG_STATUS <<EOF
-
-CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
-EOF
-cat >> $CONFIG_STATUS <<\EOF
-for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
-  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
-  case "$ac_file" in
-  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
-       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
-  *) ac_file_in="${ac_file}.in" ;;
-  esac
-
-  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
-
-  # Remove last slash and all that follows it.  Not all systems have dirname.
-  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
-  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
-    # The file is in a subdirectory.
-    test ! -d "$ac_dir" && mkdir "$ac_dir"
-    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
-    # A "../" for each directory in $ac_dir_suffix.
-    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
-  else
-    ac_dir_suffix= ac_dots=
-  fi
-
-  case "$ac_given_srcdir" in
-  .)  srcdir=.
-      if test -z "$ac_dots"; then top_srcdir=.
-      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
-  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
-  *) # Relative path.
-    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
-    top_srcdir="$ac_dots$ac_given_srcdir" ;;
-  esac
-
-
-  echo creating "$ac_file"
-  rm -f "$ac_file"
-  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
-  case "$ac_file" in
-  *Makefile*) ac_comsub="1i\\
-# $configure_input" ;;
-  *) ac_comsub= ;;
-  esac
-
-  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
-  sed -e "$ac_comsub
-s%@configure_input@%$configure_input%g
-s%@srcdir@%$srcdir%g
-s%@top_srcdir@%$top_srcdir%g
-" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
-fi; done
-rm -f conftest.s*
-
-# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
-# NAME is the cpp macro being defined and VALUE is the value it is being given.
-#
-# ac_d sets the value in "#define NAME VALUE" lines.
-ac_dA='s%^\([  ]*\)#\([        ]*define[       ][      ]*\)'
-ac_dB='\([     ][      ]*\)[^  ]*%\1#\2'
-ac_dC='\3'
-ac_dD='%g'
-# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
-ac_uA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
-ac_uB='\([     ]\)%\1#\2define\3'
-ac_uC=' '
-ac_uD='\4%g'
-# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
-ac_eA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
-ac_eB='$%\1#\2define\3'
-ac_eC=' '
-ac_eD='%g'
-
-if test "${CONFIG_HEADERS+set}" != set; then
-EOF
-cat >> $CONFIG_STATUS <<EOF
-  CONFIG_HEADERS="config.h"
-EOF
-cat >> $CONFIG_STATUS <<\EOF
-fi
-for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
-  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
-  case "$ac_file" in
-  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
-       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
-  *) ac_file_in="${ac_file}.in" ;;
-  esac
-
-  echo creating $ac_file
-
-  rm -f conftest.frag conftest.in conftest.out
-  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
-  cat $ac_file_inputs > conftest.in
-
-EOF
-
-# Transform confdefs.h into a sed script conftest.vals that substitutes
-# the proper values into config.h.in to produce config.h.  And first:
-# Protect against being on the right side of a sed subst in config.status.
-# Protect against being in an unquoted here document in config.status.
-rm -f conftest.vals
-cat > conftest.hdr <<\EOF
-s/[\\&%]/\\&/g
-s%[\\$`]%\\&%g
-s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
-s%ac_d%ac_u%gp
-s%ac_u%ac_e%gp
-EOF
-sed -n -f conftest.hdr confdefs.h > conftest.vals
-rm -f conftest.hdr
-
-# This sed command replaces #undef with comments.  This is necessary, for
-# example, in the case of _POSIX_SOURCE, which is predefined and required
-# on some systems where configure will not decide to define it.
-cat >> conftest.vals <<\EOF
-s%^[   ]*#[    ]*undef[        ][      ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
-EOF
-
-# Break up conftest.vals because some shells have a limit on
-# the size of here documents, and old seds have small limits too.
-
-rm -f conftest.tail
-while :
-do
-  ac_lines=`grep -c . conftest.vals`
-  # grep -c gives empty output for an empty file on some AIX systems.
-  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
-  # Write a limited-size here document to conftest.frag.
-  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
-  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
-  echo 'CEOF
-  sed -f conftest.frag conftest.in > conftest.out
-  rm -f conftest.in
-  mv conftest.out conftest.in
-' >> $CONFIG_STATUS
-  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
-  rm -f conftest.vals
-  mv conftest.tail conftest.vals
-done
-rm -f conftest.vals
-
-cat >> $CONFIG_STATUS <<\EOF
-  rm -f conftest.frag conftest.h
-  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
-  cat conftest.in >> conftest.h
-  rm -f conftest.in
-  if cmp -s $ac_file conftest.h 2>/dev/null; then
-    echo "$ac_file is unchanged"
-    rm -f conftest.h
-  else
-    # Remove last slash and all that follows it.  Not all systems have dirname.
-      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
-      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
-      # The file is in a subdirectory.
-      test ! -d "$ac_dir" && mkdir "$ac_dir"
-    fi
-    rm -f $ac_file
-    mv conftest.h $ac_file
-  fi
-fi; done
-
-EOF
-cat >> $CONFIG_STATUS <<EOF
-
-EOF
-cat >> $CONFIG_STATUS <<\EOF
-echo timestamp > stamp-h
-exit 0
-EOF
-chmod +x $CONFIG_STATUS
-rm -fr confdefs* $ac_clean_files
-test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
-
index 6b3eb13..34a31dd 100644 (file)
 dnl This file writen by Devrim SERAL for tac_plus daemon
 
 AC_INIT()
+dnl Check for Host information
+dnl AC_CANONICAL_HOST()
+AC_CANONICAL_SYSTEM()
+AM_INIT_AUTOMAKE(tac_plus, F4.0.3.alpha.8.gts1)
 
 dnl Checks for programs.
 AC_PROG_MAKE_SET
 AC_PROG_CC
 
-dnl Check for Host information
-dnl AC_CANONICAL_HOST()
-AC_CANONICAL_SYSTEM()
-
-case $host_os in 
+case $host_os in
        *linux-gnu)
-       OS="-DLINUX -DGLIBC"
-       ;;
+               AC_DEFINE(LINUX)
+               AC_DEFINE(GLIBC)
+               ;;
        *solaris)
-       OS="-DSOLARIS"
-       ;;
+               AC_DEFINE(SOLARIS)
+               ;;
        *freebsd)
-       OS="-DFREEBSD"
-       ;;
+               AC_DEFINE(FREEBSD)
+               ;;
        *hpux)
-       OS="-DHPUX"
-       ;;
+               AC_DEFINE(HPUX)
+               ;;
        *aix)
-       OS="-DAIX"
-       ;;
+               AC_DEFINE(AIX)
+               AC_MSG_WARN([See /usr/lpp/bos/bsdport on your system for details of how to define bsdcc])
+               # CC="bsdcc"
+               ;;
+       *mips)
+               AC_DEFINE(MIPS)
+               ;;
        *)
-       ;;
+               ;;
 esac
-       
+
+dnl Devrim Added
+AM_CONFIG_HEADER(config.h)
+AM_MAINTAINER_MODE
+
+if test "x$USE_MAINTAINER_MODE" = "xyes"; then
+       AC_DEFINE(MAINTAINER_MODE)
+fi
+
+if test "x$USE_MAINTAINER_MODE" = "xyes" -a "x$GCC" = "xyes"; then
+       CFLAGS="$CFLAGS -ggdb3 -Wall -Wstrict-prototypes -pedantic -Wsign-compare"
+fi
+
+# Set these options as otherwise some autoconf tests give different results:
+final_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -D_XOPEN_SOURCE=1 -D_XOPEN_SOURCE_EXTENDED=1 -D_BSD_SOURCE=1 -D_OSF_SOURCE=1 -D__EXTENSIONS__=1"
+
+COND_USE=""
+AC_SUBST(COND_USE)
+conf_LDFLAGS=""
+AC_SUBST(conf_LDFLAGS)
+conf_LDADD=""
+AC_SUBST(conf_LDADD)
+
+
 dnl Checks for libraries.
 dnl Replace `main' with a function in -lnsl:
-AC_CHECK_LIB(nsl, main)
+AC_CHECK_LIB(nsl, main,    [ conf_LDADD="-lnsl    $conf_LDADD" ] )
 dnl Replace `main' with a function in -log:
-AC_CHECK_LIB(og, main)
-dnl Replace `main' with a function in -lldap:
-AC_CHECK_LIB(ldap, main)
-dnl Replace `main' with a function in -llber:
-AC_CHECK_LIB(lber, main)
+AC_CHECK_LIB(og, main,     [ conf_LDADD="-log     $conf_LDADD" ] )
 dnl Replace `main' with a function in -lsocket:
-AC_CHECK_LIB(socket, main)
+AC_CHECK_LIB(socket, main, [ conf_LDADD="-lsocket $conf_LDADD" ] )
 dnl Check for Crypt function
+dnl Never use CONF_LDADD here as it is used also for "generate_passwd"
 AC_CHECK_LIB(crypt, crypt)
 AC_CHECK_LIB(c,printf)
 
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h malloc.h strings.h sys/file.h sys/ioctl.h sys/time.h syslog.h sys/syslog.h unistd.h regex.h sys/param.h)
+AC_CHECK_HEADERS(shadow.h,[
+               if test -f /etc/shadow ; then
+                 AC_DEFINE(SHADOW_PASSWORDS)
+               fi
+               ],)
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_HEADER_TIME
+
+dnl Checks for library functions.
+AC_PROG_GCC_TRADITIONAL
+AC_FUNC_SETPGRP
+AC_TYPE_SIGNAL
+AC_FUNC_VPRINTF
+AC_FUNC_WAIT3
+AC_TYPE_SIZE_T
+AC_CHECK_FUNCS(select socket strcspn strdup strtol siginterrupt)
+AC_CHECK_SIZEOF(unsigned short,2)
+AC_CHECK_SIZEOF(unsigned int,4)
+AC_CHECK_SIZEOF(unsigned long,4)
 
-dnl Devrim Added 
-AC_CONFIG_HEADER(config.h)
 
 dnl For PAM support
 AC_MSG_CHECKING(for PAM support:)
@@ -55,9 +103,10 @@ echo
 AC_ARG_WITH(pam,
        [  --with-pam           With PAM Support   ],,)
 if test "x$with_pam" = "xyes";then
-       AC_CHECK_LIB(dl, dlopen)
-       AC_CHECK_LIB(pam, pam_start)
-       DEFINES="-DUSE_PAM $DEFINES";
+       AC_CHECK_LIB(dl, dlopen,     [ conf_LDADD="-ldl  $conf_LDADD" ] )
+       AC_CHECK_LIB(pam, pam_start, [ conf_LDADD="-lpam $conf_LDADD" ] )
+       AC_DEFINE(USE_PAM)
+       COND_USE="$COND_USE "'$(cond_USE_PAM)'
         AC_MSG_RESULT(Pam support... yes)
 else
         AC_MSG_RESULT(Pam support... no)
@@ -70,22 +119,30 @@ AC_ARG_WITH(ldap,
         [  --with-ldap         With LDAP Support   ],,)
 
 if test "x$with_ldap" = "xyes";then
-   AC_CHECK_LIB(ldap, ldap_simple_bind_s)
-   AC_CHECK_LIB(ldap, ldap_init)
-   DEFINES="-DUSE_LDAP $DEFINES"
-        AC_MSG_RESULT(LDAP support... yes)
+       dnl Replace `main' with a function in -llber:
+       AC_CHECK_LIB(lber, main,   [ conf_LDADD="-llber   $conf_LDADD"; liblber="-llber" ], [ liblber="" ] )
+       dnl Replace `main' with a function in -lldap:
+       AC_CHECK_LIB(ldap, ldap_simple_bind_s, [ conf_LDADD="-lldap   $conf_LDADD" ],
+               [
+       AC_CHECK_LIB(ldap, ldap_init,          [ conf_LDADD="-lldap   $conf_LDADD" ],, $liblber)
+               ], $liblber )
+       AC_DEFINE(USE_LDAP)
+       COND_USE="$COND_USE "'$(cond_USE_LDAP)'
+       AC_MSG_RESULT(LDAP support... yes)
 else
-        AC_MSG_RESULT(LDAP support... no)
+       AC_MSG_RESULT(LDAP support... no)
 fi
 
 dnl For DB Support
 AC_MSG_CHECKING(for DB support)
-echo 
+echo
 AC_ARG_WITH(db,
         [  --with-db           For DB Support   ],,)
 if test "x$with_db" = "xyes";then
-       DB="$DB -DDB -DDB_NULL" 
+       AC_DEFINE(DB)
+       AC_DEFINE(DB_NULL)
+       COND_USE="$COND_USE "'$(cond_DB)'
+       COND_USE="$COND_USE "'$(cond_DB_NULL)'
        AC_MSG_RESULT(DB support... yes)
 else
        AC_MSG_RESULT(DB support... no)
@@ -107,15 +164,16 @@ AC_ARG_WITH(mysql-prefix,
 
 
 if test "x$with_mysql" = "xyes";then
-       
-       LDFLAGS="-L$MYSQL_PREFIX/lib/mysql $LDFLAGS"
-        LDFLAGS="-I$MYSQL_PREFIX/include/mysql $LDFLAGS"
+
+       conf_LDFLAGS="-L$MYSQL_PREFIX/lib/mysql $conf_LDFLAGS"
+        CPPFLAGS="-I$MYSQL_PREFIX/include/mysql $CPPFLAGS"
         AC_CHECK_LIB(mysqlclient, mysql_init,
-                        LIBS="-lmysqlclient -lm $LIBS",
+                        conf_LDADD="-lmysqlclient -lm $conf_LDADD",
                         AC_MSG_ERROR(*** couldn't find libmysqlclient),
                         -lm)
 
-       DB="$DB -DDB_MYSQL";
+       AC_DEFINE(DB_MYSQL)
+       COND_USE="$COND_USE "'$(cond_DB_MYSQL)'
         AC_MSG_RESULT(Mysql support... yes)
 else
         AC_MSG_RESULT(Mysql support... no)
@@ -139,14 +197,15 @@ AC_ARG_WITH(pgsql-prefix,
 
 
 if test "x$with_pgsql" = "xyes";then
-       
-       LDFLAGS="-L$PGSQL_PREFIX/lib/pgsql $LDFLAGS"
-        LDFLAGS="-I$PGSQL_PREFIX/include/pgsql $LDFLAGS"
+
+       conf_LDFLAGS="-L$PGSQL_PREFIX/lib/pgsql $conf_LDFLAGS"
+        CPPFLAGS="-I$PGSQL_PREFIX/include/pgsql $CPPFLAGS"
         AC_CHECK_LIB(pq,PQconnectdb ,
-                        LIBS="-lpq $LIBS",
+                        conf_LDADD="-lpq $conf_LDADD",
                         AC_MSG_ERROR(*** couldn't find libpq))
 
-       DB="$DB -DDB_PGSQL";
+       AC_DEFINE(DB_PGSQL)
+       COND_USE="$COND_USE "'$(cond_DB_PGSQL)'
         AC_MSG_RESULT(Pgsql support... yes)
 else
         AC_MSG_RESULT(Pgsql support... no)
@@ -154,7 +213,7 @@ fi
 
 fi
 
-dnl Tacuid & tac guid 
+dnl Tacuid & tac guid
 
 AC_ARG_WITH(tacuid,
                [  --with-tacuid=ID     If you like to run tac_plus other than root user (no default value) ],,)
@@ -164,8 +223,9 @@ AC_ARG_WITH(tacgid,
 
 if (test "x$with_tacuid" != "x" && test "x$with_tacgid" != "x" && test "x$with_tacuid" != "xyes" && test "x$with_tacgid" != "xyes");then
 
-       DEFINES="-DTACPLUS_USERID=$with_tacuid -DTACPLUS_GROUPID=$with_tacgid $DEFINES";        
-       AC_MSG_RESULT(tacacs+ work with given user and group id) 
+       AC_DEFINE_UNQUOTED(TACPLUS_USERID,  $with_tacuid)
+       AC_DEFINE_UNQUOTED(TACPLUS_GROUPID, $with_tacgid)
+       AC_MSG_RESULT(tacacs+ work with given user and group id)
 fi
 
 AC_MSG_CHECKING(whether to enable the maxsess feature)
@@ -173,9 +233,10 @@ AC_ARG_ENABLE(maxsess,
               [  --enable-maxsess      Enable maxsess feature ],
 [
 if test "$enableval" = "yes";then
-       DEFINES="-DMAXSESS $DEFINES";
+       AC_DEFINE(MAXSESS)
        AC_MSG_RESULT(yes)
-else 
+       COND_USE="$COND_USE "'$(cond_MAXSESS)'
+else
        AC_MSG_RESULT(no)
 fi
 ],
@@ -183,17 +244,19 @@ fi
        AC_MSG_RESULT(no)
 ])
 
-dnl Enable tacacs.pid file directory 
-
+dnl Enable tacacs.pid file directory
 AC_ARG_WITH(tacplus_pid,
         [  --with-tacplus_pid=PREFIX  Tac_plus pid file location [default=/var/run] ],
-        PIDFILE="-DTACPLUS_PIDFILE=\\\"$withval/tac_plus.pid\\\"",
-        PIDFILE="-DTACPLUS_PIDFILE=\\\"/var/run/tac_plus.pid\\\""
+       [ pidfile="$withval" ],
+       [ pidfile="" ]
 )
+if test "x$pidfile" '!=' "x"; then
+       AC_DEFINE_UNQUOTED(TACPLUS_PIDFILE, "$pidfile/tac_plus.pid")
+fi
 
 dnl For libwrap check
-AC_MSG_CHECKING(whether to enable the libwrap feture)
-
+AC_MSG_CHECKING(whether to enable the libwrap feature)
+cond=false
 AC_ARG_WITH(libwrap,
 [  --with-libwrap[=PATH]   Compile in libwrap (tcp_wrappers) support.],
 [ case "$withval" in
@@ -203,48 +266,221 @@ AC_ARG_WITH(libwrap,
   yes)
     AC_MSG_RESULT(yes)
     AC_CHECK_LIB(wrap, request_init, [
-        LIBS="-lwrap $LIBS"
-        DEFINES="-DTCPWRAPPER $DEFINES"])
+        conf_LDADD="-lwrap $conf_LDADD"
+       cond=true
+       ])
     ;;
   *)
     AC_MSG_RESULT(yes)
     if test -d "$withval"; then
         LDFLAGS="-L$withval $LDFLAGS"
-       DEFINES="-DTCPWRAPPER $DEFINES"
     fi
     AC_TRY_LINK([ int allow_severity; int deny_severity; ],
                 [ hosts_access(); ],
                 [],
                 [ AC_MSG_ERROR(Could not find the $withval library.  You must first install tcp_wrappers.) ])
+    cond=true
     ;;
   esac ],
   AC_MSG_RESULT(no)
 )
+if $cond; then
+       AC_DEFINE(TCPWRAPPER)
+       COND_USE="$COND_USE "'$(cond_TCPWRAPPER)'
+fi
 
-dnl insert defines to Makefile 
-AC_SUBST(DEFINES)
-AC_SUBST(PIDFILE)
-AC_SUBST(DB)
-AC_SUBST(OS)
+dnl For SKEY check
+AC_MSG_CHECKING(whether to use SKEY security feature)
+cond=false
+AC_ARG_WITH(skey,
+[  --with-skey[=LIBPATH]   Compile with SKEY support (also use -I in CPPFLAGS var).],
+[ case "$withval" in
+  no)
+    AC_MSG_RESULT(no)
+    ;;
+  yes)
+    AC_MSG_RESULT(yes)
+    cond=true
+    ;;
+  *)
+    AC_MSG_RESULT(yes)
+    if test '!' -f "$withval";then
+       AC_MSG_ERROR([Cannot find $withval library file, you may wish to use LIBS variable instead.])
+    fi
+    conf_LDADD="$withval $conf_LDADD"
+    cond=true
+    ;;
+  esac ],
+  AC_MSG_RESULT(no)
+)
+if $cond; then
+       AC_DEFINE(SKEY)
+       COND_USE="$COND_USE "'$(cond_SKEY)'
+fi
 
-dnl Checks for header files.
-AC_HEADER_STDC
-AC_CHECK_HEADERS(fcntl.h malloc.h strings.h sys/file.h sys/ioctl.h sys/time.h syslog.h unistd.h)
-AC_CHECK_HEADERS(shadow.h,[
-               if test -f /etc/shadow ; then
-                 AC_DEFINE(SHADOW_PASSWORDS)           
-               fi 
-               ],)
-dnl Checks for typedefs, structures, and compiler characteristics.
-AC_C_CONST
-AC_HEADER_TIME
+dnl For MSCHAP and also MSCHAP_DES
+AC_MSG_CHECKING(whether to compile with Microsoft CHAP)
+cond=false
+AC_ARG_WITH(mschap,
+[  --with-mschap[=des]     Compile with Microsoft CHAP (optionally including MSCHAP_DES).],
+[ case "$withval" in
+  no)
+    AC_MSG_RESULT(no)
+    ;;
+  yes)
+    AC_MSG_RESULT([yes, without DES])
+    cond=true
+    ;;
+  des)
+    AC_MSG_RESULT([yes, including DES])
+    AC_DEFINE(MSCHAP_DES)
+    cond=true
+    ;;
+  *)
+    AC_MSG_ERROR(Unknown --with-mschap argument $withval, use: no, yes or des)
+    ;;
+  esac ],
+  AC_MSG_RESULT(no)
+)
+if $cond; then
+       AC_DEFINE(MSCHAP)
+       COND_USE="$COND_USE "'$(cond_MSCHAP)'
+fi
 
-dnl Checks for library functions.
-AC_PROG_GCC_TRADITIONAL
-AC_FUNC_SETPGRP
-AC_TYPE_SIGNAL
-AC_FUNC_VPRINTF
-AC_FUNC_WAIT3
-AC_CHECK_FUNCS(regcomp select socket strcspn strdup strtol)
+dnl For SunOS encryption compatibility
+dnl Never use CONF_LDADD here as it is used also for "generate_passwd"
+AC_MSG_CHECKING(whether to use SunOS encryption compatibility)
+cond=false
+AC_ARG_WITH(descrypt,
+[  --with-descrypt         Be password encryption compatible with SunOS.],
+[ case "$withval" in
+  no)
+    AC_MSG_RESULT(no)
+    ;;
+  yes)
+    AC_MSG_RESULT(yes)
+    LIBS="-ldescrypt $LIBS"
+    ;;
+  *)
+    AC_MSG_RESULT(yes - $withval)
+    LIBS="$withval $LIBS"
+    ;;
+  esac ],
+  AC_MSG_RESULT(no)
+)
+
+AC_ARG_WITH(efence,
+[  --with-efence           compile with efence support (for debugging)],,[
+       if test "x$USE_MAINTAINER_MODE" = "xyes"; then
+               with_efence=auto
+       else
+               with_efence=no
+       fi
+])
+if test "$with_efence" != no; then
+       AC_CHECK_LIB(efence,malloc,,[
+               if test "$with_efence" = yes; then
+                       AC_MSG_ERROR(Unable to find efence library.)
+               fi
+               ])
+fi
+
+dnl Check for type in sys/socket.h
+AC_MSG_CHECKING([for parameter type of 3rd accept() arg])
+AC_CACHE_VAL(tac_plus_cv_accept_type, [
+       check_ok=false
+       for type in socklen_t size_t int; do
+               AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+],[
+                       return 0;}
+                       int accept(int s, struct sockaddr *addr, ]$type[ *addrlen)
+                       { return 0; }
+                       int discarded_main() {
+],
+                       [check_ok=true;break],continue)
+       done
+       if $check_ok
+       then
+               tac_plus_cv_accept_type=$type
+       else
+               tac_plus_cv_accept_type=no
+       fi
+       ])
+if test "x$tac_plus_cv_accept_type" = "xno"
+then
+       AC_DEFINE(socklen_t,int)
+       AC_MSG_RESULT([failed to detect, will try int])
+else
+       AC_MSG_RESULT($tac_plus_cv_accept_type)
+       if test "x$tac_plus_cv_accept_type" != "xsocklen_t"
+       then
+               AC_DEFINE_UNQUOTED(socklen_t,$tac_plus_cv_accept_type)
+       fi
+fi
+
+dnl Check for system regex (stolen from "mutt" package)
+AC_ARG_WITH(included-regex, [  --with-included-regex   Use the included regex library ],
+       [tac_plus_cv_included_regex=yes],
+       [AC_CHECK_FUNCS(regcomp, tac_plus_cv_included_regex=no, tac_plus_cv_included_regex=yes)])
+
+if test $tac_plus_cv_included_regex = no ; then
+AC_CACHE_CHECK([whether your system's regexp library is completely broken],
+       [tac_plus_cv_included_regex_broken],
+       AC_TRY_RUN([
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_REGEX_H
+#include <regex.h>
+#endif
+main() { regex_t blah ; regmatch_t p; p.rm_eo = p.rm_eo; return regcomp(&blah, "foo.*bar", REG_NOSUB) || regexec (&blah, "foobar", 0, NULL, 0); }],
+       tac_plus_cv_included_regex_broken=no, tac_plus_cv_included_regex_broken=yes, tac_plus_cv_included_regex_broken=yes))
+       if test $tac_plus_cv_included_regex_broken = yes ; then
+               echo "Using the included regex instead." >&AC_FD_MSG
+               tac_plus_cv_included_regex=yes
+       fi
+fi
+if test $tac_plus_cv_included_regex = yes; then
+       AC_DEFINE(WITH_INCLUDED_REGEX)
+       COND_USE="$COND_USE "'$(cond_WITH_INCLUDED_REGEX)'
+fi
+
+dnl Check for "struct passwd.pw_{age,comment}"
+dnl Stolen from Julianne Frances Haugh's login replacement.
+AC_CACHE_CHECK(for pw_age in struct passwd,
+tac_plus_cv_struct_passwd_pw_age, AC_TRY_COMPILE([#include <pwd.h>],
+[ struct passwd pw;  pw.pw_age = "" ],
+tac_plus_cv_struct_passwd_pw_age=yes, tac_plus_cv_struct_passwd_pw_age=no))
+
+if test "$tac_plus_cv_struct_passwd_pw_age" = "yes"; then
+       AC_DEFINE(HAVE_PASSWD_PW_AGE)
+fi
+AC_CACHE_CHECK(for pw_comment in struct passwd,
+tac_plus_cv_struct_passwd_pw_comment, AC_TRY_COMPILE([#include <pwd.h>],
+[ struct passwd pw;  pw.pw_comment = "" ],
+tac_plus_cv_struct_passwd_pw_comment=yes, tac_plus_cv_struct_passwd_pw_comment=no))
+
+if test "$tac_plus_cv_struct_passwd_pw_comment" = "yes"; then
+       AC_DEFINE(HAVE_PASSWD_PW_COMMENT)
+fi
+AC_CACHE_CHECK(for ut_host in struct utmp,
+tac_plus_cv_struct_utmp_ut_host, AC_TRY_COMPILE([#include <utmp.h>],
+[ struct utmp ut;  ut.ut_host = "" ],
+tac_plus_cv_struct_utmp_ut_host=yes, tac_plus_cv_struct_utmp_ut_host=no))
+
+if test "$tac_plus_cv_struct_utmp_ut_host" = "yes"; then
+       AC_DEFINE(HAVE_UTMP_UT_HOST)
+fi
+
+CFLAGS="$final_CFLAGS"
 
-AC_OUTPUT(Makefile,echo timestamp > stamp-h)
+AC_OUTPUT([
+       Makefile
+       tac_plus.spec
+       ])
index eb0b5c2..83cbdcc 100755 (executable)
@@ -6,7 +6,7 @@
 # Please NOTE:  None of the TACACS code available here comes with any
 # warranty or support.
 # Copyright (c) 1995-1998 by Cisco systems, 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 of the software and
 # in advertising or publicity pertaining to distribution of the
 # program without specific prior permission, and notice be given
 # in supporting documentation that modification, copying and distribution is by
-# permission of Cisco Systems, Inc.   
-# 
+# permission of Cisco Systems, Inc.
+#
 # Cisco Systems, Inc. makes no representations about the suitability of this
 # software for any purpose.  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. 
+# FOR A PARTICULAR PURPOSE.
 
-die 'Usage: convert.pl <password file> [-g] [ <supplementary file> ]' 
+die 'Usage: convert.pl <password file> [-g] [ <supplementary file> ]'
     if $#ARGV < 0;
 
 $pwfile = '';
@@ -141,6 +141,3 @@ exit 0 if ($acl_valid);
 foreach $group (keys %groups) {
     print "group = $group { }\n";
 }
-
-
-
diff --git a/db.c b/db.c
index 9cbbbe1..b5c156c 100644 (file)
--- a/db.c
+++ b/db.c
@@ -1,7 +1,7 @@
 /*
      Verify that this user/password is valid per a database.
      Return 1 if verified, 0 otherwise.
-     
+
      Format of connection string (look like internet URL):
 
        db://user:password@hostname/table?name&passwd
@@ -22,7 +22,7 @@
                  'default authentication = db <string>'
      28-nov-1998 Added code for NULL database %)
      14-dec-1999 Add code for MySQL and also more check
-     
+
      FUTURE:
      Make *_db_verify() the functions is reenterable
      More security for connection to database
      Separate debug logging
      Perfomance testing on 10000 records in Oracle database
      (in guide sayd about 3 auth/sec on Ultra 2 - hmm)
-     
+
      -------------------------------------------------------
      fil@artelecom.ru                   http://twister.pp.ru
+
  ****************************************************************************
                                    PART II
 
    I am added some extra extension. Like MySQL and PostgreSQL database support
-   And change most of lines for use dynamic memory allocation. db_accounting 
+   And change most of lines for use dynamic memory allocation. db_accounting
    added by me.
-  
+
    devrim(devrim@gazi.edu.tr)
 */
 
-#if defined(DB)
-#include <stdio.h>
+
 #include "tac_plus.h"
+
+#ifdef DB
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db.h"
+#include "report.h"
+#include "do_acct.h"
+#include "main.h"
+#include "do_author.h"                 /* for "struct identity" */
+#include "utils.h"
+
+
+#ifdef DB_MYSQL
+#include "db_mysql.h"
+#endif
+#ifdef DB_NULL
+#include "db_null.h"
+#endif
+#ifdef DB_PGSQL
+#include "db_pgsql.h"
+#endif
+
+
+static int check_db_type TAC_ARGS((char *db_type));
+
+
 /* The databases  recognized by this function */
 #define DEFINED_DB {"null","mysql","pgsql"}
 
-char *find_attr_value(); 
+int db_verify TAC_ARGS((const char *user, const char *users_passwd, const char *str_conn));
 
 int
 db_verify(user, users_passwd, str_conn)
-char *user, *users_passwd;      /* Username and gived password   */
-char *str_conn;                 /* String connection to database */
+const char *user;                      /* username ... */
+const char *users_passwd;              /* ... and given password */
+const char *str_conn;                  /* string connection to database */
 {
     char *buffer;
     char *db_pref, *db_user, *db_password;
@@ -65,11 +94,7 @@ char *str_conn;                 /* String connection to database */
     if (debug & DEBUG_PASSWD_FLAG)
        report(LOG_DEBUG, "verify %s by database at %s", user, str_conn);
 
-    buffer = db_pref = (char *)malloc( strlen(str_conn) + 1 );
-    if( buffer == NULL ){
-       report(LOG_DEBUG, "Error allocation memory");
-        return(0);
-    }
+    buffer = db_pref = (char *) tac_malloc( strlen(str_conn) + 1 );
 
     strcpy( buffer, str_conn );
 
@@ -80,10 +105,10 @@ char *str_conn;                 /* String connection to database */
            free(buffer);
            return(0);
     }
-    *db_user = '\0'; 
+    *db_user = '\0';
 
        /* For recognize db authentication database */
-    
+
     if (check_db_type(db_pref)) {
        report(LOG_DEBUG, "%s DB authentication scheme didn't recognize by tac_plus",db_pref);
        free(buffer);
@@ -101,7 +126,7 @@ char *str_conn;                 /* String connection to database */
     }
     *db_password = '\0';
     db_password++;
-    
+
     db_hostname = (char *)strstr( db_password, "@" );
     if( db_hostname == NULL ){
        if (debug & DEBUG_PASSWD_FLAG)
@@ -111,27 +136,27 @@ char *str_conn;                 /* String connection to database */
     }
     *db_hostname = '\0';
     db_hostname++;
-    
+
     db_name = (char *)strstr( db_hostname, "/" );
     if( db_name == NULL ){
         if (debug & DEBUG_PASSWD_FLAG)
            report(LOG_DEBUG, "Error parse db_name");
        free(buffer);
         return(0);
-    } 
+    }
     *db_name = '\0';
     db_name++;
-    
+
     db_table = (char *)strstr( db_name, "/" );
     if( db_table == NULL ){
         if (debug & DEBUG_PASSWD_FLAG)
            report(LOG_DEBUG, "Error parse db_table");
        free(buffer);
         return(0);
-    } 
+    }
     *db_table = '\0';
     db_table++;
-    
+
     dbfield_name = (char *)strstr( db_table, "?" );
     if( dbfield_name == NULL){
        if (debug & DEBUG_PASSWD_FLAG)
@@ -152,7 +177,7 @@ char *str_conn;                 /* String connection to database */
     }
     *dbfield_passwd = '\0';
     dbfield_passwd++;
-    
+
 
     /* Parse database connection string */
        if (debug & DEBUG_PASSWD_FLAG)
@@ -216,6 +241,8 @@ char *str_conn;                 /* String connection to database */
 }
 
 
+int db_acct TAC_ARGS((struct acct_rec *rec));
+
 /* Db accounting routine */
 int
 db_acct(rec)
@@ -227,12 +254,7 @@ struct acct_rec *rec;
     char *a_username,*s_name,*c_name,*elapsed_time,*bytes_in,*bytes_out;
     int ret;
 
-    buffer = db_pref = (char *)malloc( strlen(session.db_acct) + 1 );
-       
-    if( buffer == NULL ){
-       report(LOG_DEBUG, "Error allocation memory");
-        return(0);
-    }
+    buffer = db_pref = (char *) tac_malloc( strlen(session.db_acct) + 1 );
 
     strcpy( buffer, session.db_acct);
 
@@ -243,10 +265,10 @@ struct acct_rec *rec;
         free(buffer);
        return(0);
     }
-    *db_user = '\0'; 
+    *db_user = '\0';
 
        /* For recognize db accouting database */
-    
+
     if( check_db_type(db_pref) ) {
        report(LOG_DEBUG, "%s DB accounting scheme didn't recognize by tac_plus",db_pref);
         free(buffer);
@@ -264,7 +286,7 @@ struct acct_rec *rec;
     }
     *db_password = '\0';
     db_password++;
-    
+
     db_hostname = (char *)strstr( db_password, "@" );
     if( db_hostname == NULL ){
        if (debug & DEBUG_PASSWD_FLAG)
@@ -274,52 +296,52 @@ struct acct_rec *rec;
     }
     *db_hostname = '\0';
     db_hostname++;
-    
+
     db_name = (char *)strstr( db_hostname, "/" );
     if( db_name == NULL ){
         if (debug & DEBUG_PASSWD_FLAG)
            report(LOG_DEBUG, "Error parse db_name");
         free(buffer);
         return(0);
-    } 
+    }
     *db_name = '\0';
     db_name++;
-    
+
     db_table = (char *)strstr( db_name, "/" );
     if( db_table == NULL ){
         if (debug & DEBUG_PASSWD_FLAG)
            report(LOG_DEBUG, "Error parse db_table");
         free(buffer);
         return(0);
-    } 
+    }
     *db_table = '\0';
     db_table++;
 
 /* Find some attributes  for accounting */
     a_username=rec->identity->username;
        if (a_username==NULL ) {
-               if (debug & DEBUG_PASSWD_FLAG) 
+               if (debug & DEBUG_PASSWD_FLAG)
                        report(LOG_DEBUG,"db_acct: Can't find username!");
                        free(buffer);
                        return(0);
        }
     s_name=rec->identity->NAS_name;
        if (s_name==NULL) {
-               if (debug & DEBUG_PASSWD_FLAG) 
+               if (debug & DEBUG_PASSWD_FLAG)
                        report(LOG_DEBUG,"db_acct: Can't find NAS name!");
                        free(buffer);
                        return(0);
        }
     c_name=find_attr_value("addr", rec->args, rec->num_args);
        if (c_name==NULL) {
-               if (debug & DEBUG_PASSWD_FLAG) 
+               if (debug & DEBUG_PASSWD_FLAG)
                        report(LOG_DEBUG,"db_acct: Can't find client adress!");
-       /* Can't find client adress so give NAC_address attribute value */ 
+       /* Can't find client adress so give NAC_address attribute value */
                c_name=rec->identity->NAC_address;
        }
     elapsed_time=find_attr_value("elapsed_time", rec->args, rec->num_args);
        if (elapsed_time==NULL) {
-               if (debug & DEBUG_PASSWD_FLAG) 
+               if (debug & DEBUG_PASSWD_FLAG)
                        report(LOG_DEBUG,"db_acct: Can't get elapsed time!");
                        free(buffer);
                        return(0);
@@ -384,8 +406,10 @@ struct acct_rec *rec;
 
 }
 
+static int check_db_type TAC_ARGS((char *db_type));
+
 /* For checking DB type */
-int 
+static int
 check_db_type(db_type)
 char *db_type;
 {
@@ -400,4 +424,9 @@ for (i=0; dbp[i] ; i++ ) {
 }
 return ret;
 }
+
+#else /* DB */
+
+TAC_SOURCEFILE_EMPTY
+
 #endif /* DB */
diff --git a/db.h b/db.h
new file mode 100644 (file)
index 0000000..dfc0c23
--- /dev/null
+++ b/db.h
@@ -0,0 +1,17 @@
+#ifndef DB_H
+#define DB_H 1
+
+#include "tac_plus.h"
+
+#ifdef DB
+
+
+struct acct_rec;
+
+extern int db_verify TAC_ARGS((const char *user, const char *users_passwd, const char *str_conn));
+extern int db_acct TAC_ARGS((struct acct_rec *rec));
+
+
+#endif /* DB */
+
+#endif /* DB_H */
index 8aef6d4..4c09f48 100644 (file)
-#if defined(DB_MYSQL) && defined(DB)
-
 /*
-Writen by Devrim SERAL(devrim@tef.gazi.edu.tr)
-*/
+ * Writen by Devrim SERAL(devrim@tef.gazi.edu.tr)
+ */
+
 
 #include "tac_plus.h"
+
+#if defined(DB_MYSQL) && defined(DB)
+
 #include <stdio.h>
-#include "mysql.h"
+#include <stdlib.h>
+#include <mysql.h>
+
+#include "db_mysql.h"
+#include "report.h"
+#include "pwlib.h"
+#include "main.h"
+#include "utils.h"
+
+
 #define SQLCMDL 1024
 #define AUTHSQL "SELECT %s FROM %s WHERE %s=\"%s\""
-#define ACCTSQL "INSERT INTO %s (usern,s_name,c_name,elapsed_time,bytes_in,bytes_out,fin_t) VALUES (\"%s\",\"%s\",\"%s\",%s,%s,%s,NOW())"  
+#define ACCTSQL "INSERT INTO %s (usern,s_name,c_name,elapsed_time,bytes_in,bytes_out,fin_t) VALUES (\"%s\",\"%s\",\"%s\",%s,%s,%s,NOW())"
 
-MYSQL mysqldb;
-MYSQL_RES *res;
-MYSQL_ROW row;
-MYSQL_FIELD *table_field;
-
-int mysql_db_verify(user, users_passwd, db_user, db_password,
-       db_hostname,db_name, db_table, dbfield_name, dbfield_passwd)
+static MYSQL mysqldb;
+static MYSQL_RES *res;
+static MYSQL_ROW row;
 
 
-char *user, *users_passwd;      /* Username and gived password   */
-char *db_user;                  /* db's parameters               */
-char *db_password;
-char *db_hostname;
-char *db_name;
-char *db_table;
-char *dbfield_name;
-char *dbfield_passwd;
+int mysql_db_verify TAC_ARGS((const char *user, const char *users_passwd, const char *db_user, const char *db_password, const char *db_hostname, const char *db_name, const char *db_table, const char *dbfield_name, const char *dbfield_passwd));
 
+int mysql_db_verify(user, users_passwd, db_user, db_password,
+       db_hostname, db_name, db_table, dbfield_name, dbfield_passwd)
+const char *user;                      /* username ... */
+const char *users_passwd;              /* ... and given password */
+const char *db_user;                   /* db's parameters */
+const char *db_password;
+const char *db_hostname;
+const char *db_name;
+const char *db_table;
+const char *dbfield_name;
+const char *dbfield_passwd;
 {
+    char *real_passwd;
+    char *mysqlcmd;
+    int sql_len;
 
-char *real_passwd;
-char *mysqlcmd;
-int sql_len;
-
-   if (debug & DEBUG_AUTHEN_FLAG)
+    if (debug & DEBUG_AUTHEN_FLAG)
        report(LOG_DEBUG, "MySQL: verify %s", user);
-       
-/* Connect database server */
-
-   if ( !( mysql_connect(&mysqldb,db_hostname,db_user,db_password) ) )
-       {
-               if (debug & DEBUG_AUTHEN_FLAG)
-                   report(LOG_DEBUG, "MySQL: cannot connect as %s", db_user);
-               return(0);
-       }
 
-/*Select tacacs db */
+    /* Connect database server */
 
-    if ( mysql_select_db(&mysqldb,db_name) )
-       {
-               if (debug & DEBUG_AUTHEN_FLAG)
-                  report(LOG_DEBUG, "MySQL: cannot find database named %s",db_name);
-               return(0);
-       }
-
-/* Check select string length */
+    if ( !( mysql_connect(&mysqldb,db_hostname,db_user,db_password) ) ) {
+       if (debug & DEBUG_AUTHEN_FLAG)
+           report(LOG_DEBUG, "MySQL: cannot connect as %s", db_user);
+       return(0);
+    }
 
-sql_len=strlen(dbfield_passwd)+strlen(dbfield_name)+strlen(db_table)+strlen(user)+strlen(AUTHSQL);
+    /* Select tacacs db */
 
-  if ( sql_len> SQLCMDL )
-        {
-               if (debug & DEBUG_AUTHEN_FLAG)
-                    report(LOG_DEBUG, "MySQL: Sql cmd exceed alowed limits");
-               return(0);
-        }
+    if ( mysql_select_db(&mysqldb,db_name) ) {
+       if (debug & DEBUG_AUTHEN_FLAG)
+           report(LOG_DEBUG, "MySQL: cannot find database named %s",db_name);
+       return(0);
+    }
 
-/* Prepare select string */
+    /* Check select string length */
 
-mysqlcmd=(char *) malloc(sql_len);
+    sql_len = strlen(dbfield_passwd)+strlen(dbfield_name)+strlen(db_table)+strlen(user)+strlen(AUTHSQL);
 
-if(mysqlcmd==NULL) { 
+    if ( sql_len> SQLCMDL ) {
        if (debug & DEBUG_AUTHEN_FLAG)
-               report(LOG_ERR, "mysql_db_verify: mysqlcmd malloc error");
+            report(LOG_DEBUG, "MySQL: Sql cmd exceed alowed limits");
        return(0);
-}
+    }
+
+    /* Prepare select string */
+
+    mysqlcmd = (char *) tac_malloc(sql_len);
 
-sprintf(mysqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
+    sprintf(mysqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
 
-/*  Query database */
+    /*  Query database */
 
-    if (mysql_query(&mysqldb,mysqlcmd))
-       {
+    if (mysql_query(&mysqldb,mysqlcmd)) {
        if (debug & DEBUG_AUTHEN_FLAG)
                report(LOG_DEBUG, "MySQL: cannot query database ");
        free(mysqlcmd);
         return(0);
-       }
+    }
 
     free(mysqlcmd);
-    
-    if (!(res = mysql_store_result(&mysqldb)))
-       {
+
+    if (!(res = mysql_store_result(&mysqldb))) {
        if (debug & DEBUG_AUTHEN_FLAG)
                report(LOG_DEBUG, "MySQL: cannot store result");
         return(0);
-       }  
-   
-   if(!(row = mysql_fetch_row(res)))
-       {
+    }
+
+   if (!(row = mysql_fetch_row(res))) {
        if (debug & DEBUG_AUTHEN_FLAG)
                report(LOG_DEBUG, "MySQL: cannot fetch row");
         return(0);
-        }  
-  
-   if (strlen(row[0]) <=0 )
-        {
+    }
+
+   if (strlen(row[0]) <=0 ) {
        if (debug & DEBUG_AUTHEN_FLAG)
                report(LOG_DEBUG, "MySQL: DB passwd entry is NULL");
         return(0);
-        }
-  /* Allocate memory for real_passwd */
-       real_passwd=(char *) malloc(strlen(row[0])+1);
-       strcpy(real_passwd,row[0]);
-   if (!mysql_eof(res))
-       {
+    }
+
+    /* Allocate memory for real_passwd */
+    real_passwd=(char *) tac_malloc(strlen(row[0])+1);
+    strcpy(real_passwd,row[0]);
+
+    if (!mysql_eof(res)) {
        if (debug & DEBUG_AUTHEN_FLAG)
-               report(LOG_DEBUG, "MySQL:  Result not end!!");
+           report(LOG_DEBUG, "MySQL:  Result not end!!");
         return(0);
-        }
+    }
 
     mysql_free_result(res);
     mysql_close(&mysqldb);
-  
-if (debug & DEBUG_AUTHEN_FLAG)   
-     report(LOG_DEBUG, "MySQL: verify password '%s' to DES encrypted string '%s'", users_passwd, real_passwd);
+
+    if (debug & DEBUG_AUTHEN_FLAG)
+        report(LOG_DEBUG, "MySQL: verify password '%s' to DES encrypted string '%s'", users_passwd, real_passwd);
 
     /* Try to verify the password */
     if (!des_verify(users_passwd, real_passwd)) {
         free(real_passwd);
        return (0);
     }
+
     free(real_passwd);
     return (1); /* Return 1 if verified, 0 otherwise. */
 }
 
-int 
-mysql_db_acct(db_user,db_password,db_hostname,db_name,db_table,s_name,c_name,a_username,elapsed_time,bytes_in,bytes_out)
 
-char *db_user;                 /* db's parameters              */
-char *db_password;
-char *db_hostname;
-char *db_name;
-char *db_table;
-char *s_name, *c_name,*a_username,*elapsed_time,*bytes_in,*bytes_out;
+int mysql_db_acct TAC_ARGS((const char *db_user, const char *db_password, const char *db_hostname, const char *db_name, const char *db_table, const char *s_name, const char *c_name, const char *a_username, const char *elapsed_time, const char *bytes_in, const char *bytes_out));
 
+int
+mysql_db_acct(db_user,db_password,db_hostname,db_name,db_table,s_name,c_name,a_username,elapsed_time,bytes_in,bytes_out)
+const char *db_user;                   /* db's parameters              */
+const char *db_password;
+const char *db_hostname;
+const char *db_name;
+const char *db_table;
+const char *s_name;
+const char *c_name;
+const char *a_username;
+const char *elapsed_time;
+const char *bytes_in;
+const char *bytes_out;
 {
+    char *mysqlcmd;
+    int sql_len;
 
-char *mysqlcmd;
-int sql_len;
-       
-/* Connect database server */
+    /* Connect database server */
 
-   if (!(mysql_connect(&mysqldb,db_hostname,db_user,db_password)))
-       {
+    if (!(mysql_connect(&mysqldb,db_hostname,db_user,db_password))) {
        if (debug & DEBUG_ACCT_FLAG)
-               report(LOG_DEBUG, "MySQL: cannot connect as %s", db_user);
-               return(0);
-       }
+           report(LOG_DEBUG, "MySQL: cannot connect as %s", db_user);
+           return(0);
+    }
 
-/*Select tacacs db */
+    /*Select tacacs db */
 
-    if (mysql_select_db(&mysqldb,db_name))
-       {
+    if (mysql_select_db(&mysqldb,db_name)) {
        if (debug & DEBUG_ACCT_FLAG)
-               report(LOG_DEBUG, "MySQL: cannot find database named %s",db_name);
-               return(0);
-       }
+           report(LOG_DEBUG, "MySQL: cannot find database named %s",db_name);
+       return(0);
+    }
 
-/* Check buffer overflow for select string */
-sql_len=strlen(db_table)+strlen(a_username)+strlen(s_name)+strlen(c_name)+strlen(elapsed_time)+strlen(bytes_in)+strlen(bytes_out)+strlen(ACCTSQL);  
+    /* Check buffer overflow for select string */
+    sql_len = strlen(db_table)+strlen(a_username)+strlen(s_name)+strlen(c_name)+strlen(elapsed_time)+strlen(bytes_in)+strlen(bytes_out)+strlen(ACCTSQL);
 
-if ( sql_len >SQLCMDL)
-        {
+    if ( sql_len >SQLCMDL) {
         if (debug & DEBUG_ACCT_FLAG)
                report(LOG_DEBUG, "MySQL: Sql cmd exceed alowed limits");
-               return(0);
-        }
+       return(0);
+    }
 
-/* Prepare select string */
-mysqlcmd=(char *) malloc(sql_len);
 
-if(mysqlcmd==NULL) { 
-       if (debug & DEBUG_ACCT_FLAG)
-               report(LOG_ERR, "mysql_db_acct: mysqlcmd malloc error");
-       return(0);
-}
+    /* Prepare select string */
+    mysqlcmd=(char *) tac_malloc(sql_len);
 
-sprintf(mysqlcmd,ACCTSQL,db_table,a_username,s_name,c_name,elapsed_time,bytes_in,bytes_out);
+    sprintf(mysqlcmd,ACCTSQL,db_table,a_username,s_name,c_name,elapsed_time,bytes_in,bytes_out);
 
-/*  Query database */
+    /*  Query database */
 
-    if (mysql_query(&mysqldb,mysqlcmd))
-       {
+    if (mysql_query(&mysqldb,mysqlcmd)) {
        if (debug & DEBUG_ACCT_FLAG)
-               report(LOG_DEBUG, "MySQL: cannot query database");
+           report(LOG_DEBUG, "MySQL: cannot query database");
        free(mysqlcmd);
        return(0);
-        }
+    }
 
-       free(mysqlcmd);
+    free(mysqlcmd);
 
-/* Check if accounting is sucess */
-    if ( mysql_affected_rows( &mysqldb ) < 0 )
-       {
+    /* Check if accounting is sucess */
+    if ( mysql_affected_rows( &mysqldb ) < 0 ) {
        if (debug & DEBUG_ACCT_FLAG)
-               report(LOG_DEBUG, "MySQL: Insert isn't sucess");
+           report(LOG_DEBUG, "MySQL: Insert isn't sucess");
         return(0);
-        }
-       return (1); /* Return 1 if verified, 0 otherwise. */
+    }
+
+    return (1); /* Return 1 if verified, 0 otherwise. */
 }
-#endif
+
+#else /* defined(DB_MYSQL) && defined(DB) */
+
+TAC_SOURCEFILE_EMPTY
+
+#endif /* defined(DB_MYSQL) && defined(DB) */
diff --git a/db_mysql.h b/db_mysql.h
new file mode 100644 (file)
index 0000000..7e806b6
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef DB_MYSQL_H
+#define DB_MYSQL_H 1
+
+#include "tac_plus.h"
+
+#if defined(DB_MYSQL) && defined(DB)
+
+
+extern int mysql_db_verify TAC_ARGS((const char *user, const char *users_passwd, const char *db_user, const char *db_password, const char *db_hostname, const char *db_name, const char *db_table, const char *dbfield_name, const char *dbfield_passwd));
+extern int mysql_db_acct TAC_ARGS((const char *db_user, const char *db_password, const char *db_hostname, const char *db_name, const char *db_table, const char *s_name, const char *c_name, const char *a_username, const char *elapsed_time, const char *bytes_in, const char *bytes_out));
+
+
+#endif /* defined(DB_MYSQL) && defined(DB) */
+
+#endif /* DB_MYSQL_H */
index 40252d8..9892ef0 100644 (file)
--- a/db_null.c
+++ b/db_null.c
@@ -6,22 +6,30 @@
 **  DO_NOT_USE_THIS_FOR_WORK!
 */
 
-#if defined(DB_NULL) && defined(DB)
+
 #include "tac_plus.h"
 
+#if defined(DB_NULL) && defined(DB)
+
+#include "db_null.h"
+#include "report.h"
+#include "main.h"
+
+
+int null_db_verify TAC_ARGS((const char *user, const char *users_passwd, const char *db_user, const char *db_password, const char *db_hostname, const char *db_table, const char *dbfield_name, const char *dbfield_passwd));
+
 int null_db_verify(user, users_passwd, db_user, db_password, db_hostname,
            db_table, dbfield_name, dbfield_passwd)
-           
-char *user, *users_passwd;      /* Username and gived password   */
-char *db_user;                 /* db's parametr's               */
-char *db_password;
-char *db_hostname;
-char *db_table;
-char *dbfield_name;
-char *dbfield_passwd;
-
+const char *user;                      /* username ... */
+const char *users_passwd;              /* ... and given password */
+const char *db_user;                   /* db's parametr's */
+const char *db_password;
+const char *db_hostname;
+const char *db_table;
+const char *dbfield_name;
+const char *dbfield_passwd;
 {
-//report(LOG_DEBUG, "DB_NULL(%u) - ok", __LINE__);
+/*    report(LOG_DEBUG, "DB_NULL(%u) - ok", __LINE__); */
 
     /* Try to verify the password
        Successful if username and password equal */
@@ -36,22 +44,30 @@ char *dbfield_passwd;
 
 /*     Null Database Accounting        */
 
-int 
+int null_db_acct TAC_ARGS((const char *db_user, const char *db_password, const char *db_hostname, const char *db_name, const char *db_table, const char *s_name, const char *c_name, const char *a_username, const char *elapsed_time, const char *bytes_in, const char *bytes_out));
+
+int
 null_db_acct(db_user, db_password, db_hostname,db_name,db_table,s_name,c_name,a_username,elapsed_time,bytes_in,bytes_out)
-char *db_user;                 /* db's parametr's               */
-char *db_password;
-char *db_hostname;
-char *db_name;
-char *db_table;
-char *s_name;
-char *c_name;
-char *a_username;
-char *elapsed_time;char *bytes_in;char *bytes_out;
+const char *db_user;                   /* db's parametr's               */
+const char *db_password;
+const char *db_hostname;
+const char *db_name;
+const char *db_table;
+const char *s_name;
+const char *c_name;
+const char *a_username;
+const char *elapsed_time;
+const char *bytes_in;
+const char *bytes_out;
 {
-report(LOG_INFO,"Db accounting user=%s pass=%s host=%s 
-db_name=%s table=%s servern=%s clientn=%s username=%s et=%s bi=%s bo=%s",db_user,db_password,db_hostname,
-db_name,db_table,s_name,c_name,a_username,elapsed_time,bytes_in,bytes_out);
-return (1);
+    report(LOG_INFO,"Db accounting user=%s pass=%s host=%s \
+    db_name=%s table=%s servern=%s clientn=%s username=%s et=%s bi=%s bo=%s",db_user,db_password,db_hostname,
+    db_name,db_table,s_name,c_name,a_username,elapsed_time,bytes_in,bytes_out);
+    return (1);
 }
-#endif
 
+#else /* defined(DB_NULL) && defined(DB) */
+
+TAC_SOURCEFILE_EMPTY
+
+#endif /* defined(DB_NULL) && defined(DB) */
diff --git a/db_null.h b/db_null.h
new file mode 100644 (file)
index 0000000..4e82047
--- /dev/null
+++ b/db_null.h
@@ -0,0 +1,15 @@
+#ifndef DB_NULL_H
+#define DB_NULL_H 1
+
+#include "tac_plus.h"
+
+#if defined(DB_NULL) && defined(DB)
+
+
+extern int null_db_verify TAC_ARGS((const char *user, const char *users_passwd, const char *db_user, const char *db_password, const char *db_hostname, const char *db_table, const char *dbfield_name, const char *dbfield_passwd));
+extern int null_db_acct TAC_ARGS((const char *db_user, const char *db_password, const char *db_hostname, const char *db_name, const char *db_table, const char *s_name, const char *c_name, const char *a_username, const char *elapsed_time, const char *bytes_in, const char *bytes_out));
+
+
+#endif /* defined(DB_NULL) && defined(DB) */
+
+#endif /* DB_NULL_H */
index 22725fe..321133c 100644 (file)
-#if defined(DB_PGSQL) && defined(DB)
-
 /*
 Writen by Devrim SERAL(devrim@tef.gazi.edu.tr)
 For PostgreSQL Authentication And Accounting
                28-01-2001
-This program protected with GPL License. 
+This program protected with GPL License.
 */
 
+
 #include "tac_plus.h"
+
+#if defined(DB_PGSQL) && defined(DB)
+
 #include <stdio.h>
-#include "libpq-fe.h" 
+#include <stdlib.h>
+#include <libpq-fe.h>
+#include <string.h>
+
+#include "db_pgsql.h"
+#include "main.h"
+#include "report.h"
+#include "utils.h"
+#include "pwlib.h"
+
+
+static void exit_nicely TAC_ARGS((PGconn *cn, PGresult *r));
+
+
 #define SQLCMDL 1024
 #define PWLEN  13
 #define AUTHSQL "SELECT %s FROM %s WHERE %s='%s'"
-#define ACCTSQL "INSERT INTO %s (usern,s_name,c_name,elapsed_time,bytes_in,bytes_out,fin_t) VALUES ('%s','%s','%s',%s,%s,%s,NOW())"  
+#define ACCTSQL "INSERT INTO %s (usern,s_name,c_name,elapsed_time,bytes_in,bytes_out,fin_t) VALUES ('%s','%s','%s',%s,%s,%s,NOW())"
 
-PGconn     *conn;
-PGresult   *res;
-
-int pgsql_db_verify(user, users_passwd, db_user, db_password,
-       db_hostname,db_name, db_table, dbfield_name, dbfield_passwd)
+static PGconn     *conn;
+static PGresult   *res;
 
 
-char *user, *users_passwd;      /* Username and gived password   */
-char *db_user;                  /* db's parameters               */
-char *db_password;
-char *db_hostname;
-char *db_name;
-char *db_table;
-char *dbfield_name;
-char *dbfield_passwd;
+int pgsql_db_verify TAC_ARGS((const char *user, const char *users_passwd, const char *db_user, const char *db_password, const char *db_hostname, const char *db_name, const char *db_table, const char *dbfield_name, const char *dbfield_passwd));
 
+int pgsql_db_verify(user, users_passwd, db_user, db_password,
+       db_hostname, db_name, db_table, dbfield_name, dbfield_passwd)
+const char *user;                      /* username ... */
+const char *users_passwd;              /* ... and given password */
+const char *db_user;                   /* db's parameters */
+const char *db_password;
+const char *db_hostname;
+const char *db_name;
+const char *db_table;
+const char *dbfield_name;
+const char *dbfield_passwd;
 {
+    char *real_passwd;
+    char *pgsqlcmd;
+    int sql_len;
+    int nrow;
 
-char *real_passwd;
-char *pgsqlcmd;
-int sql_len;
-int nrow;
+    if (debug & DEBUG_AUTHEN_FLAG)
+       report(LOG_DEBUG, "PGSQL: verify %s", user);
 
-if (debug & DEBUG_AUTHEN_FLAG)
-        report(LOG_DEBUG, "PGSQL: verify %s", user);
-       
-/* Connect database server */
+    /* Connect database server */
 
-conn=PQsetdbLogin(db_hostname,NULL,NULL,NULL,db_name,db_user,db_password);
+    conn=PQsetdbLogin(db_hostname,NULL,NULL,NULL,db_name,db_user,db_password);
 
-if ( PQstatus(conn) == CONNECTION_BAD ) 
-{
-    if (debug & DEBUG_AUTHEN_FLAG)
-       report(LOG_DEBUG, "PGSQL: Connection to database %s failed", db_name);
+    if ( PQstatus(conn) == CONNECTION_BAD ) {
+       if (debug & DEBUG_AUTHEN_FLAG)
+           report(LOG_DEBUG, "PGSQL: Connection to database %s failed", db_name);
        return(0);
-}
+    }
 
-/* Check select string length */
+    /* Check select string length */
 
-sql_len=strlen(dbfield_passwd)+strlen(dbfield_name)+strlen(db_table)+strlen(user)+strlen(AUTHSQL);
+    sql_len=strlen(dbfield_passwd)+strlen(dbfield_name)+strlen(db_table)+strlen(user)+strlen(AUTHSQL);
 
-if ( sql_len> SQLCMDL )
-{
-    if (debug & DEBUG_AUTHEN_FLAG)
-               report(LOG_DEBUG, "PGSQL: Sql cmd exceed alowed limits");
-               return(0);
-}
+    if ( sql_len> SQLCMDL ) {
+       if (debug & DEBUG_AUTHEN_FLAG)
+           report(LOG_DEBUG, "PGSQL: Sql cmd exceed alowed limits");
+       return(0);
+    }
 
-/* Prepare select string */
+    /* Prepare select string */
 
-pgsqlcmd=(char *) malloc(sql_len);
+    pgsqlcmd=(char *) tac_malloc(sql_len);
 
-if(pgsqlcmd==NULL) 
-{ 
-    if (debug & DEBUG_AUTHEN_FLAG)
-       report(LOG_ERR, "pgsql_db_verify: pgsqlcmd malloc error");
+    sprintf(pgsqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
+
+    /*  Query database */
+    res=PQexec(conn,pgsqlcmd);
+
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) {
+       if (debug & DEBUG_AUTHEN_FLAG) {
+           report(LOG_DEBUG, "PGSQL: cannot query database ");
+           report(LOG_DEBUG, "PGSQL: Error message->%s", PQerrorMessage(conn) );
+       }
+       free(pgsqlcmd);
+       exit_nicely(conn,res);
        return(0);
-}
+    }
 
-sprintf(pgsqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
+    free(pgsqlcmd);
 
-/*  Query database */
-res=PQexec(conn,pgsqlcmd);
+    if ( (nrow=PQntuples(res)) !=1 ) {
+       if (debug & DEBUG_AUTHEN_FLAG)
+           report(LOG_DEBUG, "PGSQL: Have we got more than one password!!");
+       exit_nicely(conn,res);
+       return(0);
+    }
 
-if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
-{
-   if (debug & DEBUG_AUTHEN_FLAG) {
-       report(LOG_DEBUG, "PGSQL: cannot query database ");
-       report(LOG_DEBUG, "PGSQL: Error message->%s", PQerrorMessage(conn) );
-   }
-       free(pgsqlcmd);
-        exit_nicely(conn,res);
+    if ( PQgetisnull(res,0,PQfnumber(res,dbfield_passwd)) ) {
+       if (debug & DEBUG_AUTHEN_FLAG)
+           report(LOG_DEBUG, "PGSQL: DB passwd entry is NULL");
+       exit_nicely(conn,res);
        return(0);
-}
+    }
 
-free(pgsqlcmd);
+    /* Allocate memory for real_passwd */
+    real_passwd=(char *) tac_malloc(PWLEN+1);
+    strncpy(real_passwd,PQgetvalue(res,0,PQfnumber(res,dbfield_passwd)),PWLEN);
+    real_passwd[PWLEN]='\0';
+
+    exit_nicely(conn,res);
 
-if( nrow=PQntuples(res)!=1) 
-{  
-    if (debug & DEBUG_AUTHEN_FLAG)
-        report(LOG_DEBUG, "PGSQL: Have we got more than one password!!");
-        exit_nicely(conn,res);
-       return(0);
-}  
-  
-if ( PQgetisnull(res,0,PQfnumber(res,dbfield_passwd)) ) 
-{
     if (debug & DEBUG_AUTHEN_FLAG)
-        report(LOG_DEBUG, "PGSQL: DB passwd entry is NULL");
-        exit_nicely(conn,res);
-       return(0);
-}
+       report(LOG_DEBUG, "PGSQL: verify password '%s' to DES encrypted string '%s'", users_passwd, real_passwd);
 
-  /* Allocate memory for real_passwd */
-       real_passwd=(char *) malloc(PWLEN+1);
-       strncpy(real_passwd,PQgetvalue(res,0,PQfnumber(res,dbfield_passwd)),PWLEN);
-        real_passwd[PWLEN]='\0';
-exit_nicely(conn,res);
-  
-if (debug & DEBUG_AUTHEN_FLAG)
-        report(LOG_DEBUG, "PGSQL: verify password '%s' to DES encrypted string '%s'", users_passwd, real_passwd);
-       /* Try to verify the password */
-       if (!des_verify(users_passwd, real_passwd)) 
-       {
-        return (0);
-       }
+    /* Try to verify the password */
+    if (!des_verify(users_passwd, real_passwd))
+       return (0);
 
     return (1); /* Return 1 if verified, 0 otherwise. */
 }
 
-/*     PGSQL ACCOUNTING function       */ 
-
-int pgsql_db_acct(db_user,db_password,db_hostname,db_name,db_table,s_name,c_name,a_username,elapsed_time,bytes_in,bytes_out)
+/*     PGSQL ACCOUNTING function       */
 
-char *db_user;                  /* db's parameters              */
-char *db_password;
-char *db_hostname;
-char *db_name;
-char *db_table;
-char *s_name, *c_name,*a_username,*elapsed_time,*bytes_in,*bytes_out;
+int pgsql_db_acct TAC_ARGS((const char *db_user, const char *db_password, const char *db_hostname, const char *db_name, const char *db_table, const char *s_name, const char *c_name, const char *a_username, const char *elapsed_time, const char *bytes_in, const char *bytes_out));
 
+int pgsql_db_acct(db_user,db_password,db_hostname,db_name,db_table,s_name,c_name,a_username,elapsed_time,bytes_in,bytes_out)
+const char *db_user;                  /* db's parameters              */
+const char *db_password;
+const char *db_hostname;
+const char *db_name;
+const char *db_table;
+const char *s_name;
+const char *c_name;
+const char *a_username;
+const char *elapsed_time;
+const char *bytes_in;
+const char *bytes_out;
 {
+    char *pgsqlcmd;
+    int sql_len;
 
-char *pgsqlcmd;
-int sql_len;
-
-  if (debug & DEBUG_ACCT_FLAG)
+    if (debug & DEBUG_ACCT_FLAG)
        report(LOG_DEBUG, "PGSQL: Accounting for %s begin", a_username);
-       
-/* Connect database server */
 
-conn=PQsetdbLogin(db_hostname,NULL,NULL,NULL,db_name,db_user,db_password);
+    /* Connect database server */
 
-if ( PQstatus(conn) == CONNECTION_BAD ) 
-{
-   if (debug & DEBUG_ACCT_FLAG) {
-       report(LOG_DEBUG, "PGSQL: Connection to database %s failed", db_name);
-       report(LOG_DEBUG, "PGSQL: Error message->%s", PQerrorMessage(conn) );
-   }
+    conn=PQsetdbLogin(db_hostname,NULL,NULL,NULL,db_name,db_user,db_password);
+
+    if ( PQstatus(conn) == CONNECTION_BAD ) {
+       if (debug & DEBUG_ACCT_FLAG) {
+           report(LOG_DEBUG, "PGSQL: Connection to database %s failed", db_name);
+           report(LOG_DEBUG, "PGSQL: Error message->%s", PQerrorMessage(conn) );
+       }
        return(0);
-}
+    }
 
-/* Check select string length */
+    /* Check select string length */
 
-sql_len=strlen(db_table)+strlen(a_username)+strlen(s_name)+strlen(c_name)+strlen(elapsed_time)+strlen(bytes_in)+strlen(bytes_out)+strlen(ACCTSQL); 
+    sql_len=strlen(db_table)+strlen(a_username)+strlen(s_name)+strlen(c_name)+strlen(elapsed_time)+strlen(bytes_in)+strlen(bytes_out)+strlen(ACCTSQL);
 
-if ( sql_len> SQLCMDL )
-{
-   if (debug & DEBUG_ACCT_FLAG) 
-               report(LOG_DEBUG, "PGSQL: Sql cmd exceed alowed limits");
-               return(0);
-}
+    if ( sql_len> SQLCMDL ) {
+       if (debug & DEBUG_ACCT_FLAG)
+           report(LOG_DEBUG, "PGSQL: Sql cmd exceed alowed limits");
+       return(0);
+    }
 
-/* Prepare select string */
+    /* Prepare select string */
 
-pgsqlcmd=(char *) malloc(sql_len);
+    pgsqlcmd=(char *) tac_malloc(sql_len);
 
-if(pgsqlcmd==NULL) 
-{
-if (debug & DEBUG_ACCT_FLAG) 
-       report(LOG_ERR, "pgsql_db_verify: pgsqlcmd malloc error");
-       return(0);
-}
+    sprintf(pgsqlcmd,ACCTSQL,db_table,a_username,s_name,c_name,elapsed_time,bytes_in,bytes_out);
 
-sprintf(pgsqlcmd,ACCTSQL,db_table,a_username,s_name,c_name,elapsed_time,bytes_in,bytes_out);
-/*  Query database */
-res=PQexec(conn,pgsqlcmd);
+    /*  Query database */
+    res=PQexec(conn,pgsqlcmd);
 
-if (!res || PQresultStatus(res) != PGRES_COMMAND_OK )
-{
- if (debug & DEBUG_ACCT_FLAG) { 
-       report(LOG_DEBUG, "PGSQL: cannot establish database query");
-       report(LOG_DEBUG, "PGSQL: Error message->%s", PQerrorMessage(conn) );
-}
+    if (!res || PQresultStatus(res) != PGRES_COMMAND_OK ) {
+       if (debug & DEBUG_ACCT_FLAG) {
+           report(LOG_DEBUG, "PGSQL: cannot establish database query");
+           report(LOG_DEBUG, "PGSQL: Error message->%s", PQerrorMessage(conn) );
+       }
        free(pgsqlcmd);
         exit_nicely(conn,res);
        return(0);
-}
+    }
 
-free(pgsqlcmd);
-    
-/* Flush all result and close connection */
-exit_nicely(conn,res);
+    free(pgsqlcmd);
+
+    /* Flush all result and close connection */
+    exit_nicely(conn,res);
 
     if (debug & DEBUG_ACCT_FLAG)
        report(LOG_DEBUG, "PGSQL: Accounting for %s finished", a_username);
-  
+
     return (1); /* Return 1 if verified, 0 otherwise. */
 }
 
-int
-exit_nicely(PGconn *cn,PGresult *r)
+
+static void exit_nicely TAC_ARGS((PGconn *cn, PGresult *r));
+
+static void
+exit_nicely(cn, r)
+PGconn *cn;
+PGresult *r;
 {
     PQclear(r);
     PQfinish(cn);
 }
 
-#endif
+#else /* defined(DB_PGSQL) && defined(DB) */
+
+TAC_SOURCEFILE_EMPTY
+
+#endif /* defined(DB_PGSQL) && defined(DB) */
diff --git a/db_pgsql.h b/db_pgsql.h
new file mode 100644 (file)
index 0000000..b966bfc
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef DB_PGSQL_H
+#define DB_PGSQL_H 1
+
+#include "tac_plus.h"
+
+#if defined(DB_PGSQL) && defined(DB)
+
+
+extern int pgsql_db_verify TAC_ARGS((const char *user, const char *users_passwd, const char *db_user, const char *db_password, const char *db_hostname, const char *db_name, const char *db_table, const char *dbfield_name, const char *dbfield_passwd));
+extern int pgsql_db_acct TAC_ARGS((const char *db_user, const char *db_password, const char *db_hostname, const char *db_name, const char *db_table, const char *s_name, const char *c_name, const char *a_username, const char *elapsed_time, const char *bytes_in, const char *bytes_out));
+
+
+#endif /* defined(DB_PGSQL) && defined(DB) */
+
+#endif /* DB_PGSQL_H */
index f97e9e2..d6196cf 100644 (file)
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "default_fn.h"
 #include "expire.h"
 #include "md5.h"
+#include "report.h"
+#include "utils.h"
+#include "cfgfile.h"
+#include "pwlib.h"
+#include "choose_authen.h"             /* for "struct authen_data" */
+#include "do_author.h"                 /* for "struct identity" */
+#include "packet.h"
+#include "main.h"
 
 #ifdef MSCHAP
 #include "md4.h"
 #include "mschap.h"
-
 #ifdef MSCHAP_DES
 #include "arap_des.h"
-#endif
+#endif /* MSCHAP_DES */
 #endif /* MSCHAP */
 
 #ifdef ARAP_DES
 #include "arap_des.h"
 #endif
 
+
+struct private_data;
+
+static void chap_verify TAC_ARGS((struct authen_data *data));
+static void arap_verify TAC_ARGS((struct authen_data *data));
+static void pap_verify TAC_ARGS((struct authen_data *data));
+static void tac_login TAC_ARGS((struct authen_data *data, struct private_data *p));
+
+#ifdef MSCHAP
+static void mschap_verify TAC_ARGS((struct authen_data *data));
+#endif
+
+
 /* internal state variables */
 #define STATE_AUTHEN_START   0 /* no requests issued */
 #define STATE_AUTHEN_GETUSER 1 /* username has been requested */
@@ -44,13 +71,6 @@ struct private_data {
     int state;
 };
 
-static void chap_verify();
-#ifdef MSCHAP
-static void mschap_verify();
-#endif /* MSCHAP */
-static void arap_verify();
-static void pap_verify();
-static void tac_login();
 
 /*
  * Default tacacs login authentication function. Wants a username
@@ -67,6 +87,8 @@ static void tac_login();
  * Return 0 if data->status is valid, otherwise 1
  */
 
+int default_fn TAC_ARGS((struct authen_data *data));
+
 int
 default_fn(data)
 struct authen_data *data;
@@ -210,6 +232,8 @@ struct authen_data *data;
  *
  */
 
+static void tac_login TAC_ARGS((struct authen_data *data, struct private_data *p));
+
 static void
 tac_login(data, p)
 struct authen_data *data;
@@ -278,6 +302,8 @@ struct private_data *p;
  * the START packet.
  */
 
+static void pap_verify TAC_ARGS((struct authen_data *data));
+
 static void
 pap_verify(data)
 struct authen_data *data;
@@ -305,6 +331,8 @@ struct authen_data *data;
 }
 
 
+static void chap_verify TAC_ARGS((struct authen_data *data));
+
 /* Verify the challenge and id against the response by looking up the
  * chap secret in the config file. Set data->status appropriately.
  */
@@ -312,8 +340,9 @@ static void
 chap_verify(data)
 struct authen_data *data;
 {
-    char *name, *secret, *chal, digest[MD5_LEN];
-    char *exp_date, *p;
+    char *name, *chal, digest[MD5_LEN];
+    const char *secret;
+    const char *exp_date, *p;
     u_char *mdp;
     char id;
     int chal_len, inlen;
@@ -398,13 +427,15 @@ struct authen_data *data;
 }
 
 
+static void pw_bitshift TAC_ARGS((char *pw));
+
 /*
  * Force the "parity" bit to zero on a password before passing it to
  * des. This is not documented anywhere. (I believe forcing the parity
  * to zero reduces the integrity of the encrypted keys but this is
  * what Apple chose to do).
  */
-void 
+static void
 pw_bitshift(pw)
 char *pw;
 {
@@ -423,12 +454,14 @@ char *pw;
 }
 
 
+static void arap_verify TAC_ARGS((struct authen_data *data));
+
 static void
 arap_verify(data)
 struct authen_data *data;
 {
     char nas_chal[8], r_chal[8], r_resp[8], secret[8];
-    char *name, *cfg_secret, *exp_date, *p;
+    const char *name, *cfg_secret, *exp_date, *p;
 
     if (!(char) data->NAS_id->username[0]) {
        report(LOG_ERR, "%s %s: no username for arap_verify",
@@ -511,9 +544,12 @@ struct authen_data *data;
 #ifdef MSCHAP
 
 /* Following code is added for ms-chap */
+
+static void mschap_desencrypt TAC_ARGS((const char *clear, unsigned char *str, unsigned char *cypher));
+
 static void
 mschap_desencrypt(clear, str, cypher)
-char *clear;
+const char *clear;
 unsigned char *str;
 unsigned char *cypher;
 {
@@ -576,19 +612,23 @@ unsigned char *cypher;
 }
 
 
+static void mschap_deshash TAC_ARGS((unsigned char *clear, unsigned char *cypher));
+
 static void
 mschap_deshash(clear, cypher)
-char *clear;
-char *cypher;
+unsigned char *clear;
+unsigned char *cypher;
 {
     mschap_desencrypt(MSCHAP_KEY, clear, cypher);
 }
 
 
+static void mschap_lmpasswordhash TAC_ARGS((const char *password, unsigned char *passwordhash));
+
 static void
 mschap_lmpasswordhash(password, passwordhash)
-char *password;
-char *passwordhash;
+const char *password;
+unsigned char *passwordhash;
 {
     unsigned char upassword[15];
     int i = 0;
@@ -604,13 +644,15 @@ char *passwordhash;
 }
 
 
+static void mschap_challengeresponse TAC_ARGS((const char *challenge, unsigned char *passwordhash, unsigned char *response));
+
 static void
 mschap_challengeresponse(challenge, passwordhash, response)
-char *challenge;
-char *passwordhash;
-char *response;
+const char *challenge;
+unsigned char *passwordhash;
+unsigned char *response;
 {
-    char zpasswordhash[21];
+    unsigned char zpasswordhash[21];
 
     memset(zpasswordhash, 0, 21);
     memcpy(zpasswordhash, passwordhash, 16);
@@ -621,22 +663,26 @@ char *response;
 }
 
 
+void mschap_lmchallengeresponse TAC_ARGS((const char *challenge, const char *password, unsigned char *response));
+
 void
 mschap_lmchallengeresponse(challenge, password, response)
-char *challenge;
-char *password;
-char *response;
+const char *challenge;
+const char *password;
+unsigned char *response;
 {
-    char passwordhash[16];
+    unsigned char passwordhash[16];
 
     mschap_lmpasswordhash(password, passwordhash);
     mschap_challengeresponse(challenge, passwordhash, response);
 }
 
 
+static int mschap_unicode_len TAC_ARGS((unsigned char *password));
+
 static int
 mschap_unicode_len(password)
-char *password;
+unsigned char *password;
 {
     int i;
 
@@ -649,14 +695,16 @@ char *password;
 }
 
 
+static void mschap_ntpasswordhash TAC_ARGS((const char *password, unsigned char *passwordhash));
+
 static void
 mschap_ntpasswordhash(password, passwordhash)
-char *password;
-char *passwordhash;
+const char *password;
+unsigned char *passwordhash;
 {
     MD4_CTX context;
     int i;
-    char *cp;
+    const char *cp;
     unsigned char unicode_password[512];
 
     memset(unicode_password, 0, 512);
@@ -676,15 +724,15 @@ char *passwordhash;
 }
 
 
+void mschap_ntchallengeresponse TAC_ARGS((const char *challenge, const char *password, unsigned char *response));
+
 void
-mschap_ntchallengeresponse(challenge,
-                          password,
-                          response)
-char *challenge;
-char *password;
-char *response;
+mschap_ntchallengeresponse(challenge, password, response)
+const char *challenge;
+const char *password;
+unsigned char *response;
 {
-    char passwordhash[16];
+    unsigned char passwordhash[16];
 
     mschap_ntpasswordhash(password, passwordhash);
     mschap_challengeresponse(challenge, passwordhash, response);
@@ -694,16 +742,19 @@ char *response;
 /* Verify the challenge and id against the response by looking up the
  * ms-chap secret in the config file. Set data->status appropriately.
  */
+
+static void mschap_verify TAC_ARGS((struct authen_data *data));
+
 static void
 mschap_verify(data)
 struct authen_data *data;
 {
-    char *name, *secret, *chal, *resp;
-    char *exp_date, *p;
+    const char *name, *secret, *chal, *resp;
+    const char *exp_date, *p;
     char id;
     int chal_len;
-    char lmresponse[24];
-    char ntresponse[24];
+    unsigned char lmresponse[24];
+    unsigned char ntresponse[24];
     int bcmp_status;
 
     if (!(char) data->NAS_id->username[0]) {
diff --git a/default_fn.h b/default_fn.h
new file mode 100644 (file)
index 0000000..20e0e0f
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef DEFAULT_FN_H
+#define DEFAULT_FN_H 1
+
+#include "tac_plus.h"
+
+
+struct authen_data;
+
+extern int default_fn TAC_ARGS((struct authen_data *data));
+#ifdef MSCHAP
+extern void mschap_lmchallengeresponse TAC_ARGS((const char *challenge, const char *password, unsigned char *response));
+extern void mschap_ntchallengeresponse TAC_ARGS((const char *challenge, const char *password, unsigned char *response));
+#endif
+
+
+#endif /* DEFAULT_FN_H */
index 96e0c1d..7c4c9cb 100644 (file)
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "default_v0_fn.h"
 #include "expire.h"
+#include "utils.h"
+#include "report.h"
+#include "pwlib.h"
+#include "choose_authen.h"             /* for "struct authen_data" */
+#include "do_author.h"                 /* for "struct identity" */
+#include "packet.h"
+#include "main.h"
+#include "cfgfile.h"
+
 
 /* internal state variables */
 #define STATE_AUTHEN_START   0 /* no requests issued */
@@ -45,6 +60,8 @@ struct private_data {
  * Return 0 if data->status is valid, otherwise 1
  */
 
+int default_v0_fn TAC_ARGS((struct authen_data *data));
+
 int
 default_v0_fn(data)
 struct authen_data *data;
@@ -97,7 +114,7 @@ struct authen_data *data;
 
        default:
            /* something awful has happened. Give up and die */
-           report(LOG_ERR, "%s: default_fn bad state %d", 
+           report(LOG_ERR, "%s: default_fn bad state %d",
                   session.peer, p->state);
            return (1);
        }
@@ -136,7 +153,7 @@ struct authen_data *data;
        /* Never authenticate this user. It's for authorization only */
        data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
        if (debug) {
-           report(LOG_DEBUG, 
+           report(LOG_DEBUG,
                   "authentication query for '%s' %s from %s rejected",
                   name && name[0] ? name : "unknown",
                   session.port, session.peer);
@@ -164,7 +181,7 @@ struct authen_data *data;
 
     default:
        data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
-       report(LOG_ERR, "%s: Bogus service value %d from packet", 
+       report(LOG_ERR, "%s: Bogus service value %d from packet",
               session.peer, data->service);
        break;
     }
@@ -185,4 +202,3 @@ struct authen_data *data;
        return (1);
     }
 }
-
diff --git a/default_v0_fn.h b/default_v0_fn.h
new file mode 100644 (file)
index 0000000..1165ee4
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef DEFAULT_V0_FN_H
+#define DEFAULT_V0_FN_H 1
+
+#include "tac_plus.h"
+
+
+struct authen_data;
+
+extern int default_v0_fn TAC_ARGS((struct authen_data *data));
+
+
+#endif /* DEFAULT_V0_FN_H */
index dee8eaa..287b0dc 100644 (file)
--- a/do_acct.c
+++ b/do_acct.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
 
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <string.h>
+#include <utmp.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "do_acct.h"
+#include "report.h"
+#include "utils.h"
+#include "main.h"
+#include "do_author.h"                 /* for "struct identity" */
+
+
+char *wtmpfile = NULL; /* for wtmp file logging */
+
+
+static int wtmpfd = 0;
 static int acctfd = 0;
 
-/* Make a acct entry into the accounting file for accounting. 
+/* Make a acct entry into the accounting file for accounting.
    Return 1 on error  */
 
+static int acct_write TAC_ARGS((char *string));
+
 static int
 acct_write(string)
-    char *string;
+char *string;
 {
-    if (write(acctfd, string, strlen(string)) != strlen(string)) {
+    if ((unsigned long)write(acctfd, string, strlen(string)) != strlen(string)) {
        report(LOG_ERR, "%s: couldn't write acct file %s %s",
               session.peer,
               session.acctfile, sys_errlist[errno]);
        return(1);
     }
-    
+
     if (debug & DEBUG_ACCT_FLAG)
        report(LOG_DEBUG, "'%s'", string);
 
     return(0);
 }
 
+static int acct_write_field TAC_ARGS((char *string));
+
 /* Write a string or "unknown" into the accounting file.
    Return 1 on error  */
 static int
 acct_write_field(string)
-    char *string;
+char *string;
 {
     if (string && string[0]) {
        if (acct_write(string))
@@ -57,6 +87,8 @@ acct_write_field(string)
     return(0);
 }
 
+int do_acct TAC_ARGS((struct acct_rec *rec));
+
 int
 do_acct(rec)
 struct acct_rec *rec;
@@ -75,10 +107,10 @@ struct acct_rec *rec;
            return(1);
        }
     }
+
    if (!tac_lockfd(session.acctfile, acctfd)) {
        rec->admin_msg = tac_strdup("Cannot lock log file");
-       report(LOG_ERR, "%s: Cannot lock %s", 
+       report(LOG_ERR, "%s: Cannot lock %s",
               session.peer, session.acctfile);
        return(1);
     }
@@ -117,7 +149,7 @@ struct acct_rec *rec;
 
     for (i=0; i < rec->num_args; i++) {
        errors += acct_write(rec->args[i]);
-       if (i < (rec->num_args-1)) 
+       if (i < (rec->num_args-1))
            errors += acct_write("\t");
     }
     errors += acct_write("\n");
@@ -131,10 +163,12 @@ struct acct_rec *rec;
     return (0);
 }
 
-int
+static int wtmp_entry TAC_ARGS((char *line, char *name, char *host, time_t utime));
+
+static int
 wtmp_entry (line, name, host, utime)
-    char *line, *name, *host;
-    time_t utime;
+char *line, *name, *host;
+time_t utime;
 {
     struct utmp entry;
 
@@ -152,14 +186,14 @@ wtmp_entry (line, name, host, utime)
        strcpy(entry.ut_name, name);
     else bcopy(name, entry.ut_name, sizeof entry.ut_name);
 
-#ifndef SOLARIS
+#ifdef HAVE_UTMP_UT_HOST
     if (strlen(host) < sizeof entry.ut_host)
        strcpy(entry.ut_host, host);
     else bcopy(host, entry.ut_host, sizeof entry.ut_host);
 #endif
     entry.ut_time = utime;
 
-    wtmpfd = open(wtmpfile, O_CREAT | O_WRONLY | O_APPEND | O_SYNC, 0644);     
+    wtmpfd = open(wtmpfile, O_CREAT | O_WRONLY | O_APPEND | O_SYNC, 0644);
     if (wtmpfd < 0) {
        report(LOG_ERR, "Can't open wtmp file %s -- %s",
               wtmpfile, sys_errlist[errno]);
@@ -175,21 +209,23 @@ wtmp_entry (line, name, host, utime)
        report(LOG_ERR, "%s: couldn't write wtmp file %s %s",
               session.peer, wtmpfile, sys_errlist[errno]);
        return(1);
-    } 
+    }
 
     close(wtmpfd);
 
     if (debug & DEBUG_ACCT_FLAG) {
-       report(LOG_DEBUG, "wtmp: %s, %s %s %d", line, name, host, utime);
+       report(LOG_DEBUG, "wtmp: %s, %s %s %ld", line, name, host, (long)utime);
     }
-    
+
     return(0);
 }
 
+char *find_attr_value TAC_ARGS((char *attr, char **args, int cnt));
+
 char *
 find_attr_value (attr, args, cnt)
-    char *attr, **args;
-    int cnt;
+char *attr, **args;
+int cnt;
 {
     int i;
 
@@ -208,15 +244,17 @@ find_attr_value (attr, args, cnt)
     return(NULL);
 }
 
+int do_wtmp TAC_ARGS((struct acct_rec *rec));
+
 int
 do_wtmp(rec)
-    struct acct_rec *rec;
+struct acct_rec *rec;
 {
     time_t now = time(NULL);
     char *service;
     char *elapsed_time, *start_time;
     time_t start_utime = 0, stop_utime = 0, elapsed_utime = 0;
-    
+
 
     switch(rec->acct_type) {
     case ACCT_TYPE_START:
@@ -242,17 +280,17 @@ do_wtmp(rec)
        }
        return(0);
     }
-       
+
     if (rec->acct_type != ACCT_TYPE_STOP) {
        return(0);
     }
 
-    /* 
+    /*
      * Since xtacacs logged start records containing the peer address
      * for a connection, we have to generate them from T+ stop records.
      * Might as well do this for exec records too.
      */
-    
+
     elapsed_time = find_attr_value("elapsed_time", rec->args, rec->num_args);
 
     if (elapsed_time) {
@@ -261,7 +299,7 @@ do_wtmp(rec)
 
     start_time = find_attr_value("start_time", rec->args, rec->num_args);
 
-    /* 
+    /*
      * Use the start_time if there is one. If not (e.g. the NAS may
      * not know the time), assume the stop time is now, and calculate
      * the rest
@@ -273,7 +311,7 @@ do_wtmp(rec)
     } else {
        start_utime = now - elapsed_utime;
        stop_utime  = now;
-    }  
+    }
 
     if (STREQ(service, "slip") || STREQ(service, "ppp")) {
        char *dest_addr = find_attr_value("addr", rec->args, rec->num_args);
diff --git a/do_acct.h b/do_acct.h
new file mode 100644 (file)
index 0000000..5e6e025
--- /dev/null
+++ b/do_acct.h
@@ -0,0 +1,33 @@
+#ifndef DO_ACCT_H
+#define DO_ACCT_H 1
+
+#include "tac_plus.h"
+
+
+/* An API accounting record structure */
+struct acct_rec {
+    int acct_type;             /* start, stop, update */
+
+#define ACCT_TYPE_START      1
+#define ACCT_TYPE_STOP       2
+#define ACCT_TYPE_UPDATE     3
+
+    struct identity *identity;
+    int authen_method;
+    int authen_type;
+    int authen_service;
+    char *msg;       /* output field */
+    char *admin_msg; /* output field */
+    int num_args;
+    char **args;
+};
+
+extern char *wtmpfile;         /* for wtmp file logging */
+
+
+extern int do_acct TAC_ARGS((struct acct_rec *rec));
+extern char *find_attr_value TAC_ARGS((char *attr, char **args, int cnt));
+extern int do_wtmp TAC_ARGS((struct acct_rec *rec));
+
+
+#endif /* DO_ACCT_H */
index 574736f..3f23602 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
-#include "regexp.h"
 
-static int get_nas_svc();
-static int authorize_cmd();
-static int authorize_exec();
-static int authorize_svc();
-static void post_authorization();
-static int pre_authorization();
+#include <stdlib.h>
+#include <string.h>
+
+#include "do_author.h"
+#include "tac_regexp.h"
+#include "cfgfile.h"
+#include "report.h"
+#include "utils.h"
+#include "programs.h"
+#include "main.h"
+#include "parse.h"
+#include "cfgeval.h"
+
+#ifdef MAXSESS
+#include "maxsess.h"
+#endif
+#ifdef USE_PAM
+#include "tac_pam.h"
+#endif
+
+
+static int pre_authorization TAC_ARGS((const char *username, struct author_data *data));
+static int get_nas_svc TAC_ARGS((struct author_data *data, char **cmdname, char **protocol, char **svcname));
+static int authorize_cmd TAC_ARGS((const char *user, const char *cmd, struct author_data *data));
+static int authorize_exec TAC_ARGS((const char *user, struct author_data *data));
+static int authorize_svc TAC_ARGS((const char *user, int svc, const char *protocol, const char *svcname, struct author_data *data));
+static void post_authorization TAC_ARGS((const char *username, struct author_data *data));
+
+
+int do_author TAC_ARGS((struct author_data *data));
 
 /* Return 0 is data->status is valid */
 int
@@ -37,7 +61,7 @@ struct author_data *data;
     int svc;
     char *cmd, *protocol, *svcname;
 #ifdef USE_PAM
-    char *pam_service= NULL;
+    const char *pam_service= NULL;
 #endif
     protocol = NULL;
 
@@ -48,46 +72,48 @@ struct author_data *data;
 
     /* If this user doesn't exist in our configs, do the default */
 
-    if (!cfg_user_exists(username) && !cfg_user_exists(DEFAULT_USERNAME)) {
-       
-       if (cfg_no_user_permitted()) {
+    if (!cfg_user_exists(username)) {
+       if (!cfg_user_exists(DEFAULT_USERNAME)) {
+
+           if (cfg_no_user_permitted()) {
+               if (debug & DEBUG_AUTHOR_FLAG)
+                   report(LOG_DEBUG,
+                          "user '%s' or '%s' not found, permitted by default",
+                          username, DEFAULT_USERNAME);
+
+               data->status = AUTHOR_STATUS_PASS_ADD;
+               data->output_args = NULL;
+               data->num_out_args = 0;
+               return (0);
+           }
+
            if (debug & DEBUG_AUTHOR_FLAG)
-               report(LOG_DEBUG, 
-                      "user '%s' or '%s' not found, permitted by default", 
+               report(LOG_DEBUG,
+                      "user '%s' or '%s' not found, denied by default",
                       username, DEFAULT_USERNAME);
-
-           data->status = AUTHOR_STATUS_PASS_ADD;
-           data->output_args = NULL;
-           data->num_out_args = 0;
+           data->status = AUTHOR_STATUS_FAIL;
            return (0);
        }
 
-       if (debug & DEBUG_AUTHOR_FLAG)
-           report(LOG_DEBUG, 
-                  "user '%s' or '%s' not found, denied by default", 
-                  username, DEFAULT_USERNAME);
-       data->status = AUTHOR_STATUS_FAIL;
-       return (0);
-    }
+       /* assumed (cfg_user_exists(DEFAULT_USERNAME)): */
 
-    if (!cfg_user_exists(username) && cfg_user_exists(DEFAULT_USERNAME)) {
        if (debug & DEBUG_AUTHOR_FLAG) {
-           report(LOG_DEBUG, "Authorizing user '%s' instead of '%s'", 
+           report(LOG_DEBUG, "Authorizing user '%s' instead of '%s'",
                   DEFAULT_USERNAME, username);
        }
        username = DEFAULT_USERNAME;
     }
 
     /* See if there's a program defined which will do authorization for us */
-    if (pre_authorization(username, data)) 
+    if (pre_authorization(username, data))
        return(0);
-    
-    /* 
+
+    /*
      * Decide what kind of authorization request this is. Currently
      * one of: exec, cmd, slip, arap, ppp or <string>
-     * 
+     *
      * If it's a command typed to the exec, return its text in cmd.
-     * 
+     *
      * If it's a ppp request, return the protocol name in protocol.
      */
 
@@ -125,25 +151,26 @@ struct author_data *data;
 #endif /* MAXSESS */
 
 #ifdef USE_PAM
-       /* Check  PAM Authorization */
-     switch (svc) {
+    /* Check  PAM Authorization */
+    switch (svc) {
+
     case N_svc_ppp:
     case N_svc_exec:
-if (pam_service=cfg_get_pam_service(data->id->username,TAC_PLUS_RECURSE) ) {
+       if ((pam_service = cfg_get_pam_service(data->id->username, TAC_PLUS_RECURSE) )) {
 
-       if (debug & DEBUG_AUTHOR_FLAG)
+           if (debug & DEBUG_AUTHOR_FLAG)
                report(LOG_DEBUG, "PAM Authorization begin for user %s",data->id->username);
-       if(tac_pam_authorization(data->id->username,data,pam_service))
-       {
-               if (debug & DEBUG_AUTHOR_FLAG)
-                       report(LOG_DEBUG, "PAM Authorization Fail");
+           if (tac_pam_authorization(data->id->username, data, pam_service)) {
+               if (debug & DEBUG_AUTHOR_FLAG)
+                   report(LOG_DEBUG, "PAM Authorization Fail");
                return(0);
-       }
-} /* Pam_service */
+           }
+       } /* Pam_service */
+
     default:
        break;
     }
-#endif 
+#endif
 
     switch(svc) {
     default:
@@ -155,9 +182,9 @@ if (pam_service=cfg_get_pam_service(data->id->username,TAC_PLUS_RECURSE) ) {
        /* A command authorisation request */
        status = authorize_cmd(username, cmd, data);
        break;
+
     case N_svc_exec:
-       if (authorize_exec(username, data)) 
+       if (authorize_exec(username, data))
            return(0);
        /* FALLTHRU */
 
@@ -173,23 +200,25 @@ if (pam_service=cfg_get_pam_service(data->id->username,TAC_PLUS_RECURSE) ) {
     }
 
     post_authorization(username, data);
-    return(status);    
+    return(status);
 }
 
-/* If an before-authorization program has been specified, call it. 
+/* If an before-authorization program has been specified, call it.
 
    A return value of 1 means no further authorization is required
 */
 
+static int pre_authorization TAC_ARGS((const char *username, struct author_data *data));
+
 static int
-pre_authorization(username, data) 
-char *username;
+pre_authorization(username, data)
+const char *username;
 struct author_data *data;
 {
     int status;
     char **out_args;
     int out_cnt, i;
-    char *cmd;
+    const char *cmd;
     char error_str[255];
     int error_len = 255;
 
@@ -199,9 +228,9 @@ struct author_data *data;
     /* If a before-authorization program exists, call it to see how to
        proceed */
 
-    cmd = cfg_get_pvalue(username, TAC_IS_USER, 
+    cmd = cfg_get_pvalue(S_user, username,
                         S_before, TAC_PLUS_RECURSE);
-    if (!cmd) 
+    if (!cmd)
        return(0);
 
     if (debug & DEBUG_AUTHOR_FLAG)
@@ -213,11 +242,11 @@ struct author_data *data;
     switch (status) {
     default:
        if (debug & DEBUG_AUTHOR_FLAG)
-           report(LOG_DEBUG, "cmd %s returns %d (unrecognised value)", 
+           report(LOG_DEBUG, "cmd %s returns %d (unrecognised value)",
                   cmd, status);
 
        data->status = AUTHOR_STATUS_ERROR;
-       data->admin_msg = 
+       data->admin_msg =
            tac_strdup("Illegal return status from pre-authorization command");
        data->msg = tac_strdup(error_str);
        data->num_out_args = 0;
@@ -247,10 +276,10 @@ struct author_data *data;
            free(out_args);
        }
        return(1);
-           
+
     case 1: /* Deny */
        if (debug & DEBUG_AUTHOR_FLAG)
-           report(LOG_DEBUG, "cmd %s returns %d (unconditional deny)", 
+           report(LOG_DEBUG, "cmd %s returns %d (unconditional deny)",
                   cmd, status);
 
        data->status = AUTHOR_STATUS_FAIL;
@@ -269,10 +298,10 @@ struct author_data *data;
 
     case 2: /* Use replacement AV pairs from program as final result */
        if (debug & DEBUG_AUTHOR_FLAG) {
-           report(LOG_DEBUG, "cmd %s returns %d (permitted, args replaced)", 
+           report(LOG_DEBUG, "cmd %s returns %d (permitted, args replaced)",
                   cmd, status);
            for(i=0; i < out_cnt; i++)
-               report(LOG_DEBUG, "%s", out_args[i]); 
+               report(LOG_DEBUG, "%s", out_args[i]);
        }
 
        /* and install the new set of AV pairs as output */
@@ -283,10 +312,10 @@ struct author_data *data;
 
     case 3: /* deny, but return attributes and server-msg to NAS */
        if (debug & DEBUG_AUTHOR_FLAG) {
-           report(LOG_DEBUG, "cmd %s returns %d (deny, args replaced)", 
+           report(LOG_DEBUG, "cmd %s returns %d (deny, args replaced)",
                   cmd, status);
            for(i=0; i < out_cnt; i++)
-               report(LOG_DEBUG, "%s", out_args[i]); 
+               report(LOG_DEBUG, "%s", out_args[i]);
        }
 
        /* and install the new set of AV pairs as output */
@@ -303,17 +332,18 @@ struct author_data *data;
    change the authorization status by calling an external program.
 */
 
+static void post_authorization TAC_ARGS((const char *username, struct author_data *data));
+
 static void
-post_authorization(username, data) 
-    char *username;
-    struct author_data *data;
+post_authorization(username, data)
+const char *username;
+struct author_data *data;
 {
     char **out_args;
     int out_cnt, i;
     int status;
-    char *after = cfg_get_pvalue(username, TAC_IS_USER, 
-                               S_after, TAC_PLUS_RECURSE);
-    if (!after) 
+    const char *after = cfg_get_pvalue(S_user, username, S_after, TAC_PLUS_RECURSE);
+    if (!after)
        return;
 
     if (debug & DEBUG_AUTHOR_FLAG)
@@ -332,7 +362,7 @@ post_authorization(username, data)
     switch (status) {
     default:
        if (debug & DEBUG_AUTHOR_FLAG)
-           report(LOG_DEBUG, 
+           report(LOG_DEBUG,
                   "cmd %s returns %d (Error)", after, status);
 
        data->status = AUTHOR_STATUS_ERROR;
@@ -342,10 +372,10 @@ post_authorization(username, data)
        if (debug & DEBUG_AUTHOR_FLAG)
            report(LOG_DEBUG, "cmd %s returns 0 (no change)", after);
        return;
-           
+
     case 1:                            /* Deny */
        if (debug & DEBUG_AUTHOR_FLAG)
-           report(LOG_DEBUG, "cmd %s returns %d (unconditional deny)", 
+           report(LOG_DEBUG, "cmd %s returns %d (unconditional deny)",
                   after, status);
 
        data->status = AUTHOR_STATUS_FAIL;
@@ -354,7 +384,7 @@ post_authorization(username, data)
     case 2:
        /* Use replacement AV pairs from program */
        if (debug & DEBUG_AUTHOR_FLAG)
-           report(LOG_DEBUG, "cmd %s returns 2 (replace & continue)", 
+           report(LOG_DEBUG, "cmd %s returns 2 (replace & continue)",
                   after);
 
        /* Free any existing AV output pairs */
@@ -378,6 +408,8 @@ post_authorization(username, data)
 }
 
 
+static char *value TAC_ARGS((char *s));
+
 /* Return a pointer to the value part of an attr=value string */
 static char *
 value(s)
@@ -393,6 +425,8 @@ char *s;
 /* Reassemble the command arguments as typed by the user, out of the
    array of args we received. Return "" if there are no arguments */
 
+static char *assemble_args TAC_ARGS((struct author_data *data));
+
 static char *
 assemble_args(data)
 struct author_data *data;
@@ -445,31 +479,28 @@ struct author_data *data;
    Otherwise, we return 1, indicating no further processing is
    required for this request. */
 
+static int authorize_exec TAC_ARGS((const char *user, struct author_data *data));
+
 static int
 authorize_exec(user, data)
-char *user;
+const char *user;
 struct author_data *data;
 {
-    NODE *svc;
-
-    if (debug & DEBUG_AUTHOR_FLAG) 
+    if (debug & DEBUG_AUTHOR_FLAG)
        report(LOG_DEBUG, "exec authorization request for %s", user);
 
     /* Is an exec explicitly configured? If so, return 0 so we know to
        process its attributes */
 
-    svc = cfg_get_svc_node(user, N_svc_exec, NULL, NULL, TAC_PLUS_RECURSE);
-    if (svc) {
-       if (debug & DEBUG_AUTHOR_FLAG) 
-           report(LOG_DEBUG, "exec is explicitly permitted by line %d",
-                  svc->line);
+    if (cfg_get_svc_node(user, N_svc_exec, NULL, NULL, TAC_PLUS_RECURSE, NULL /* nodep */)) {
+       if (debug & DEBUG_AUTHOR_FLAG)
+           report(LOG_DEBUG, "exec is explicitly permitted");
        return (0);
     }
 
     /* No exec is configured. Are any commands configured? */
-    svc = cfg_get_svc_node(user, N_svc_cmd, NULL, NULL, TAC_PLUS_RECURSE);
-    if (svc) {
-       if (debug & DEBUG_AUTHOR_FLAG) 
+    if (cfg_get_svc_node(user, N_svc_cmd, NULL, NULL, TAC_PLUS_RECURSE, NULL /* nodep */)) {
+       if (debug & DEBUG_AUTHOR_FLAG)
            report(LOG_DEBUG, "exec permitted because commands are configured");
 
        data->status = AUTHOR_STATUS_PASS_ADD;
@@ -478,19 +509,7 @@ struct author_data *data;
        return (1);
     }
 
-    /* No exec or commands configured. What's the default? */
-    if (cfg_user_svc_default_is_permit(user)) {
-
-       if (debug & DEBUG_AUTHOR_FLAG) 
-           report(LOG_DEBUG, "exec permitted by default");
-
-       data->status = AUTHOR_STATUS_PASS_ADD;
-       data->output_args = NULL;
-       data->num_out_args = 0;
-       return (1);
-    }
-
-    if (debug & DEBUG_AUTHOR_FLAG) 
+    if (debug & DEBUG_AUTHOR_FLAG)
        report(LOG_DEBUG, "exec denied by default");
 
     data->status = AUTHOR_STATUS_FAIL;
@@ -498,19 +517,18 @@ struct author_data *data;
     return(1);
 }
 
-/* Is an exec command authorized per our database(s)?  
+/* Is an exec command authorized per our database(s)?
    Return 0 if status is valid */
 
+static int authorize_cmd TAC_ARGS((const char *user, const char *cmd, struct author_data *data));
+
 static int
 authorize_cmd(user, cmd, data)
-char *user, *cmd;
+const char *user;
+const char *cmd;
 struct author_data *data;
 {
-    NODE *node;
     char *args;
-    int match;
-
-    args = assemble_args(data);
 
     if (!cmd) {
        data->status = AUTHOR_STATUS_ERROR;
@@ -520,93 +538,41 @@ struct author_data *data;
        return (0);
     }
 
-    node = cfg_get_cmd_node(user, cmd, TAC_PLUS_RECURSE);
-
-    /* The command does not exist. Do the default */
-    if (!node) {
-
-       if (cfg_user_svc_default_is_permit(user)) {
-
-           if (debug & DEBUG_AUTHOR_FLAG) 
-               report(LOG_DEBUG, "cmd %s does not exist, permitted by default",
-                      cmd);
-           
-           data->status = AUTHOR_STATUS_PASS_ADD;
-           data->num_out_args = 0;
-           if (args)
-               free(args);
-           return(0);
-       }
+    args = assemble_args(data);
+    switch (cfg_authorize_cmd(user, cmd, args)) {
 
-       if (debug & DEBUG_AUTHOR_FLAG) 
-           report(LOG_DEBUG, "cmd %s does not exist, denied by default",
-                  cmd);
+    case ER_TRUE:
+       data->status = AUTHOR_STATUS_PASS_ADD;
+       data->num_out_args = 0;
+       break;
 
+    case ER_FALSE:
        data->status = AUTHOR_STATUS_FAIL;
        data->num_out_args = 0;
-       if (args)
-           free(args);
-       return(0);
-    }
-
-    /* The command exists. The default if nothing matches is DENY */
-    data->status = AUTHOR_STATUS_FAIL;
-    data->num_out_args = 0;
-
-    for (node=node->value1; node && args; node = node->next) {
-       match = regexec((regexp *) node->value1, args);
-
-       if (debug & DEBUG_AUTHOR_FLAG) {
-           report(LOG_INFO, "line %d compare %s %s '%s' & '%s' %smatch",
-                  node->line, cmd,
-                  node->type == N_permit ? "permit" : "deny",
-                  node->value, args, (match ? "" : "no "));
-       }
-
-       if (!match)
-           continue;
+       break;
 
-       switch (node->type) {
-       case N_permit:
-           if (debug & DEBUG_AUTHOR_FLAG) {
-               report(LOG_DEBUG, "%s %s permitted by line %d", 
-                      cmd, args, node->line);
-           }
-           data->status = AUTHOR_STATUS_PASS_ADD;
-           data->num_out_args = 0;
-           break;
-       case N_deny:
-           if (debug & DEBUG_AUTHOR_FLAG) {
-               report(LOG_DEBUG, "%s %s denied by line %d", 
-                      cmd, args, node->line);
-           }
-           data->status = AUTHOR_STATUS_FAIL;
-           data->num_out_args = 0;
-           break;
-       default:
-           data->status = AUTHOR_STATUS_ERROR;
-           data->admin_msg = tac_strdup("Server error illegal configuration node");
-           report(LOG_ERR, "%s: %s %s %s", 
-                  session.peer, cmd, args, data->admin_msg);
-           break;
-       }
-       if (args)
-           free(args);
-       args = NULL;
-       return (0);
+    case ER_UNKNOWN:
+       data->status = AUTHOR_STATUS_ERROR;
+       data->admin_msg = tac_strdup("Server error illegal configuration");
+       break;
     }
+
     if (args)
        free(args);
-    return (0);
+    return(0);
 }
 
+static int is_separator TAC_ARGS((int ch));
+
 static int
 is_separator(ch)
-char ch;
+int ch;                                /* promoted "char" type */
 {
     return (ch == '=' || ch == '*');
 }
 
+static int arg_ok TAC_ARGS((char *arg));
+
 /* check an attr=value pair for well-formedness */
 static int
 arg_ok(arg)
@@ -630,6 +596,8 @@ char *arg;
 }
 
 
+static int match_attrs TAC_ARGS((char *nas_arg, char *server_arg));
+
 /* return 1 if attrs match, 0 otherwise */
 static int
 match_attrs(nas_arg, server_arg)
@@ -647,12 +615,14 @@ char *nas_arg, *server_arg;
     return (0);
 }
 
+static int match_values TAC_ARGS((char *nas_arg, char *server_arg));
+
 /* return 1 if values match, 0 otherwise */
 static int
 match_values(nas_arg, server_arg)
 char *nas_arg, *server_arg;
 {
-    while (*nas_arg && 
+    while (*nas_arg &&
           *server_arg &&
           !is_separator(*nas_arg)) {
        nas_arg++;
@@ -666,11 +636,13 @@ char *nas_arg, *server_arg;
     nas_arg++;
     if (*server_arg)
        server_arg++;
-    
+
     /* compare values */
     return(STREQ(nas_arg, server_arg));
 }
 
+static int mandatory TAC_ARGS((char *arg));
+
 /* Return 1 if arg is mandatory, 0 otherwise */
 static int
 mandatory(arg)
@@ -683,13 +655,15 @@ char *arg;
 
     /* if we're not at the end, this must be the separator */
     if (*p && !is_separator(*p)) {
-       report(LOG_ERR, "%s: Error on arg %s cannot find separator", 
+       report(LOG_ERR, "%s: Error on arg %s cannot find separator",
               session.peer, arg);
        return (0);
     }
     return (*p == '=');
 }
 
+static int optional TAC_ARGS((char *arg));
+
 static int
 optional(arg)
 char *arg;
@@ -699,29 +673,24 @@ char *arg;
 
 /* PPP-LCP requests are a special case. If they are not explicitly
    configured, but there are other ppp services explicitly configured,
-   we admit (return 0) any PPP-LCP request */
+   we admit (return 1) any PPP-LCP request */
 
-static int 
-ppp_lcp_allowed(svc, protocol, user)
-    int svc;
-    char *user, *protocol;
-{
-    /* This is not a ppp/lcp request. Just Say No */
-    if (!(svc == N_svc_ppp &&
-         protocol &&
-         STREQ(protocol, "lcp")))
-       return(0);
+static int ppp_lcp_allowed TAC_ARGS((const char *user));
 
-    /* It is an LCP request. Are there PPP services configured */
-    if (cfg_ppp_is_configured(user, TAC_PLUS_RECURSE)) {
+static int
+ppp_lcp_allowed(user)
+const char *user;
+{
+    /* It is an LCP request. Are there PPP services configured? */
+    if (cfg_get_svc_node(user, N_svc_ppp, NULL /* protocol */, NULL /* svcname */, TAC_PLUS_RECURSE, NULL /* nodep */)) {
        if (debug & DEBUG_AUTHOR_FLAG) {
-           report(LOG_DEBUG, 
+           report(LOG_DEBUG,
                   "ppp/lcp request permitted (ppp is configured for %s)",
                   user);
        }
        return(1);
     }
-    
+
     /* It is an LCP request but no PPP services are configured */
     if (debug & DEBUG_AUTHOR_FLAG) {
        report(LOG_DEBUG, "ppp/lcp request denied (ppp not configured for %s)",
@@ -730,14 +699,16 @@ ppp_lcp_allowed(svc, protocol, user)
     return(0);
 }
 
+static int authorize_svc TAC_ARGS((const char *user, int svc, const char *protocol, const char *svcname, struct author_data *data));
+
 /* Return 0 means data->status is valid */
 static int
 authorize_svc(user, svc, protocol, svcname, data)
-    char *user;
-    int svc;
-    char *svcname;
-    struct author_data *data;
-    char *protocol; /* valid only if svc == ppp */
+const char *user;
+int svc;
+const char *svcname;
+struct author_data *data;
+const char *protocol;          /* valid only if svc == ppp */
 {
     int max_args;
     char **out_args, **outp;
@@ -747,35 +718,44 @@ authorize_svc(user, svc, protocol, svcname, data)
     char **cfg_argp;
     int deny_by_default;
     NODE *node;
+    int service_permit;
 
     int replaced = 0;
     int added = 0;
     int cfg_cnt;
 
     /* Does this service exist? */
-    node = cfg_get_svc_node(user, svc, protocol, svcname, TAC_PLUS_RECURSE);
+    service_permit = cfg_get_svc_node(user, svc, protocol, svcname, TAC_PLUS_RECURSE, &node);
 
-    if (!node) {
-       /* Service not found. If the default is permit, or this is an
-          PPP/LCP request and other ppp services are configured,
-          we'll allow it. */
+    /* Now we may have three cases:
+     * service_permit == 1 && node != NULL
+     * service_permit == 1 && node == NULL
+     * service_permit == 0    (BTW node == NULL)
+     */
 
-       if (cfg_user_svc_default_is_permit(user)) {
+    if (service_permit && !node) {
+       /* Service not found and the default is permit, we'll allow it. */
 
-           if (debug & DEBUG_AUTHOR_FLAG)
-               report(LOG_DEBUG, 
-              "svc=%s protocol=%s svcname=%s not found, permitted by default", 
-                      cfg_nodestring(svc), 
-                      protocol ? protocol : "",
-                      svcname ? svcname : "");
+       if (debug & DEBUG_AUTHOR_FLAG)
+           report(LOG_DEBUG,
+          "svc=%s protocol=%s svcname=%s not found, permitted by default",
+                  cfg_nodestring(svc),
+                  protocol ? protocol : "",
+                  svcname ? svcname : "");
 
-           data->status = AUTHOR_STATUS_PASS_ADD;
-           data->num_out_args = 0;
-           data->output_args = NULL;
-           return(0);
+       data->status = AUTHOR_STATUS_PASS_ADD;
+       data->num_out_args = 0;
+       data->output_args = NULL;
+       return(0);
        }
 
-       if (ppp_lcp_allowed(svc, protocol, user)) {
+    if (!service_permit) {
+       /* Service not found, if this is an
+          PPP/LCP request and other ppp services are configured,
+          we'll allow it. */
+
+       if (svc == N_svc_ppp && protocol && STREQ(protocol, "lcp")
+        && ppp_lcp_allowed(user)) {
            data->status = AUTHOR_STATUS_PASS_ADD;
            data->num_out_args = 0;
            data->output_args = NULL;
@@ -791,7 +771,7 @@ authorize_svc(user, svc, protocol, svcname, data)
        data->output_args = NULL;
        return(0);
     }
-    
+
     /* Get server args configured in the config file. */
     cfg_args = cfg_get_svc_attrs(node, &deny_by_default);
 
@@ -896,10 +876,10 @@ authorize_svc(user, svc, protocol, svcname, data)
                        free(out_args[i]);
                    free(out_args);
                }
-               
+
                data->num_out_args = 0;
                data->output_args = NULL;
-               
+
                /* free the server arguments */
                for(cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
                    free(*cfg_argp);
@@ -911,7 +891,7 @@ authorize_svc(user, svc, protocol, svcname, data)
               the output */
 
            if (debug & DEBUG_AUTHOR_FLAG) {
-               report(LOG_DEBUG, 
+               report(LOG_DEBUG,
                       "nas:%s, svr:absent, default=permit -> add %s (d)",
                       nas_arg, nas_arg);
            }
@@ -948,7 +928,7 @@ authorize_svc(user, svc, protocol, svcname, data)
            /* f). If not found, look for the first attribute match in
               the mandatory list. If found, add DAEMONS's AV pair to
               output */
-           
+
            for (j = 0; j < cfg_cnt; j++) {
                cfg_arg = cfg_args[j];
                if (optional(cfg_arg))
@@ -976,8 +956,8 @@ authorize_svc(user, svc, protocol, svcname, data)
                cfg_arg = cfg_args[j];
                if (!optional(cfg_arg))
                    continue;
-               
-               if (match_attrs(nas_arg, cfg_arg) && 
+
+               if (match_attrs(nas_arg, cfg_arg) &&
                    match_values(nas_arg, cfg_arg)) {
                    if (debug & DEBUG_AUTHOR_FLAG) {
                        report(LOG_DEBUG, "nas:%s svr:%s -> replace with %s (g)",
@@ -999,7 +979,7 @@ authorize_svc(user, svc, protocol, svcname, data)
                cfg_arg = cfg_args[j];
                if (!optional(cfg_arg))
                    continue;
-               
+
                if (match_attrs(nas_arg, cfg_arg)) {
                    if (debug & DEBUG_AUTHOR_FLAG) {
                        report(LOG_DEBUG, "nas:%s svr:%s -> replace with %s (h)",
@@ -1039,7 +1019,7 @@ authorize_svc(user, svc, protocol, svcname, data)
 
     }
 
-    
+
     /* k). After all AV pairs have been processed, for each mandatory
        DAEMON AV pair, if there is no attribute match already in the
        output list, add the AV pair (add only one AV pair for each
@@ -1049,7 +1029,7 @@ authorize_svc(user, svc, protocol, svcname, data)
        cfg_arg = cfg_args[i];
 
        if (!mandatory(cfg_arg))
-           continue;   
+           continue;
 
        for (j = 0; j < data->num_out_args; j++) {
            char *output_arg = out_args[j];
@@ -1071,9 +1051,9 @@ authorize_svc(user, svc, protocol, svcname, data)
        data->num_out_args++;
 
     next_cfg_arg:;
-       
+
     }
-       
+
     /* If we replaced or deleted some pairs we must return the entire
        list we've constructed */
 
@@ -1098,13 +1078,13 @@ authorize_svc(user, svc, protocol, svcname, data)
 
     if (added) {
 
-       if (debug & DEBUG_AUTHOR_FLAG) 
+       if (debug & DEBUG_AUTHOR_FLAG)
            report(LOG_DEBUG, "added %d args", added);
 
        /* throw away output args which are just copies of the input args */
        for (i = 0; i < data->num_in_args; i++) {
            if (debug & DEBUG_AUTHOR_FLAG) {
-               report(LOG_DEBUG, "out_args[%d] = %s input copy discarded", 
+               report(LOG_DEBUG, "out_args[%d] = %s input copy discarded",
                       i, out_args[i]);
            }
            free(out_args[i]);
@@ -1117,14 +1097,14 @@ authorize_svc(user, svc, protocol, svcname, data)
        j = 0;
        for (i = data->num_in_args; i < data->num_out_args; i++) {
            if (out_args[j]) /* we goofed */
-               report(LOG_ERR, "%s: out_args[%d] should be NULL", 
+               report(LOG_ERR, "%s: out_args[%d] should be NULL",
                       session.peer, j);
            if (!out_args[i]) /* we goofed */
                report(LOG_ERR, "%s: out_args[%d] should not be NULL",
                       session.peer, i);
 
            if (debug & DEBUG_AUTHOR_FLAG) {
-               report(LOG_DEBUG, "out_args[%d] = %s compacted to out_args[%d]", 
+               report(LOG_DEBUG, "out_args[%d] = %s compacted to out_args[%d]",
                       i, out_args[i], j);
            }
            out_args[j++] = out_args[i];
@@ -1187,11 +1167,11 @@ authorize_svc(user, svc, protocol, svcname, data)
 }
 
 /* Return an integer indicating which kind of service is being
-   requested. 
+   requested.
 
    Conveniently this integer is one of our node types. If the service
    is a command authorisation request, also return the command name in
-   cmdname. 
+   cmdname.
 
    If this service is a ppp request, return the protocol name in
    protocol.
@@ -1200,6 +1180,8 @@ authorize_svc(user, svc, protocol, svcname, data)
    name in svcname.
 */
 
+static int get_nas_svc TAC_ARGS((struct author_data *data, char **cmdname, char **protocol, char **svcname));
+
 static int
 get_nas_svc(data, cmdname, protocol, svcname)
 struct author_data *data;
@@ -1207,7 +1189,7 @@ char **cmdname, **protocol, **svcname;
 {
     int i;
     char *nas_arg;
-    
+
     *cmdname = NULL;
     *protocol = NULL;
     *svcname = NULL;
diff --git a/do_author.h b/do_author.h
new file mode 100644 (file)
index 0000000..08bea16
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef DO_AUTHOR_H
+#define DO_AUTHOR_H 1
+
+#include "tac_plus.h"
+
+
+/*
+ * This structure describes a principal that is to be authenticated.
+ *   username        is the principals name (ASCII, null terminated)
+ *   NAS_name        is the name of the NAS where the user is
+ *   NAS_port        is the port on the NAS where the user is
+ *   NAC_address     is the remote user location.  This may be
+ *                   a remote IP address or a caller-ID or ...
+ *   priv_lvl        user's requested privilege level.
+ */
+
+struct identity {
+    char *username;
+    char *NAS_name;
+    char *NAS_port;
+    char *NAC_address;
+    int priv_lvl;
+};
+
+
+/*
+ * This structure is the data structure for passing information to
+ * and from the authorization function (do_author()).
+ */
+struct author_data {
+    struct identity *id;       /* user id */
+    int authen_method;         /* authentication method */
+
+#define AUTHEN_METH_NONE             0x01
+#define AUTHEN_METH_KRB5             0x02
+#define AUTHEN_METH_LINE             0x03
+#define AUTHEN_METH_ENABLE           0x04
+#define AUTHEN_METH_LOCAL            0x05
+#define AUTHEN_METH_TACACSPLUS       0x06
+#define AUTHEN_METH_RCMD             0x20
+
+    int authen_type;           /* authentication type see authen_type */
+    int service;               /* calling service */
+    char *msg;                 /* optional NULL-terminated return message */
+    char *admin_msg;           /* optional NULL-terminated admin message */
+    int status;                        /* return status */
+
+#define AUTHOR_STATUS_PASS_ADD       0x01
+#define AUTHOR_STATUS_PASS_REPL      0x02
+#define AUTHOR_STATUS_FAIL           0x10
+#define AUTHOR_STATUS_ERROR          0x11
+
+    int num_in_args;           /* input arg count */
+    char **input_args;         /* input arguments */
+    int num_out_args;          /* output arg cnt */
+    char **output_args;                /* output arguments */
+
+};
+
+
+extern int do_author TAC_ARGS((struct author_data *data));
+
+
+#endif /* DO_AUTHOR_H */
diff --git a/dump.c b/dump.c
index ae58e5e..511085b 100644 (file)
--- a/dump.c
+++ b/dump.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
 
+#include <netinet/in.h>                /* for ntohl() */
+
+#include "dump.h"
+#include "report.h"
+#include "utils.h"
+#include "packet.h"
+#include "do_author.h"
+#include "main.h"
+
+
+char *summarise_outgoing_packet_type TAC_ARGS((u_char *pak));
+
 /* Routines for dumping packets to stderr */
 char *
 summarise_outgoing_packet_type(pak)
@@ -90,7 +103,9 @@ u_char *pak;
     return (p);
 }
 
-void
+static void dump_header TAC_ARGS((u_char *pak));
+
+static void
 dump_header(pak)
 u_char *pak;
 {
@@ -101,7 +116,7 @@ u_char *pak;
 
     report(LOG_DEBUG, "PACKET: key=%s", session.key ? session.key : "<NULL>");
     report(LOG_DEBUG, "version %d (0x%x), type %d, seq no %d, encryption %d",
-          hdr->version, hdr->version, 
+          hdr->version, hdr->version,
           hdr->type, hdr->seq_no, hdr->encryption);
     report(LOG_DEBUG, "session_id %u (0x%x), Data length %d (0x%x)",
           ntohl(hdr->session_id), ntohl(hdr->session_id),
@@ -117,7 +132,10 @@ u_char *pak;
 }
 
 
+void dump_nas_pak TAC_ARGS((u_char *pak));
+
 /* Dump packets originated by a NAS */
+void
 dump_nas_pak(pak)
 u_char *pak;
 {
@@ -188,7 +206,7 @@ u_char *pak;
            }
 
            switch(start->service) {
-               
+
            case TAC_PLUS_AUTHEN_SVC_LOGIN:
                report(LOG_DEBUG, "service=login");
                break;
@@ -218,7 +236,7 @@ u_char *pak;
                break;
            }
 
-           report(LOG_DEBUG, 
+           report(LOG_DEBUG,
                   "user_len=%d port_len=%d (0x%x), rem_addr_len=%d (0x%x)",
                   start->user_len, start->port_len, start->port_len,
                   start->rem_addr_len, start->rem_addr_len);
@@ -273,38 +291,38 @@ u_char *pak;
        author = (struct author *) (pak + TAC_PLUS_HDR_SIZE);
 
        report(LOG_DEBUG, "type=AUTHOR, priv_lvl=%d, authen=%d",
-              author->priv_lvl, 
+              author->priv_lvl,
               author->authen_type);
 
        switch(author->authen_method) {
        case AUTHEN_METH_NONE:
                report(LOG_DEBUG, "method=none");
-               break;      
+               break;
        case AUTHEN_METH_KRB5:
                report(LOG_DEBUG, "method=krb5");
-               break;      
+               break;
        case AUTHEN_METH_LINE:
                report(LOG_DEBUG, "method=line");
-               break;      
+               break;
        case AUTHEN_METH_ENABLE:
                report(LOG_DEBUG, "method=enable");
-               break;      
+               break;
        case AUTHEN_METH_LOCAL:
                report(LOG_DEBUG, "method=local");
-               break;      
+               break;
        case AUTHEN_METH_TACACSPLUS:
                report(LOG_DEBUG, "method=tacacs+");
-               break;      
+               break;
        case AUTHEN_METH_RCMD:
                report(LOG_DEBUG, "method=rcmd");
-               break;      
+               break;
        default:
                report(LOG_DEBUG, "method=unknown %d", author->authen_method);
-               break;      
+               break;
        }
 
        report(LOG_DEBUG, "svc=%d user_len=%d port_len=%d rem_addr_len=%d",
-              author->service, author->user_len, 
+              author->service, author->user_len,
               author->port_len, author->rem_addr_len);
 
        report(LOG_DEBUG, "arg_cnt=%d", author->arg_cnt);
@@ -376,6 +394,9 @@ u_char *pak;
 
 /* Dump packets originated by Tacacsd  */
 
+void dump_tacacs_pak TAC_ARGS((u_char *pak));
+
+void
 dump_tacacs_pak(pak)
 u_char *pak;
 {
@@ -393,7 +414,7 @@ u_char *pak;
     seq = hdr->seq_no;
 
     if (seq % 2 != 0) {
-       report(LOG_ERR, "%s: Bad sequence number %d should be even", 
+       report(LOG_ERR, "%s: Bad sequence number %d should be even",
               session.peer, seq);
        tac_exit(1);
     }
@@ -466,7 +487,7 @@ u_char *pak;
        p = pak + TAC_PLUS_HDR_SIZE + TAC_ACCT_REPLY_FIXED_FIELDS_SIZE;
 
        report(LOG_DEBUG, "msg: ");
-       
+
        report_string(LOG_DEBUG, p, acct->msg_len);
        p += acct->msg_len;
 
@@ -482,6 +503,8 @@ u_char *pak;
     report(LOG_DEBUG, "End packet");
 }
 
+char *summarise_incoming_packet_type TAC_ARGS((u_char *pak));
+
 /* summarise packet types for logging routines. */
 char *
 summarise_incoming_packet_type(pak)
diff --git a/dump.h b/dump.h
new file mode 100644 (file)
index 0000000..bddce30
--- /dev/null
+++ b/dump.h
@@ -0,0 +1,15 @@
+#ifndef DUMP_H
+#define DUMP_H 1
+
+#include "tac_plus.h"
+
+#include <sys/types.h>         /* for u_* */
+
+
+extern char *summarise_outgoing_packet_type TAC_ARGS((u_char *pak));
+extern void dump_nas_pak TAC_ARGS((u_char *pak));
+extern void dump_tacacs_pak TAC_ARGS((u_char *pak));
+extern char *summarise_incoming_packet_type TAC_ARGS((u_char *pak));
+
+
+#endif /* DUMP_H */
index 63a17eb..3e56c92 100644 (file)
--- a/enable.c
+++ b/enable.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "enable.h"
 #include "expire.h"
+#include "utils.h"
+#include "report.h"
+#include "pwlib.h"
+#include "choose_authen.h"             /* for "struct authen_data" */
+#include "do_author.h"                 /* for "struct identity" */
+#include "packet.h"
+#include "main.h"
+#include "cfgfile.h"
+
 
 /* internal state variables */
 #define STATE_AUTHEN_START   0 /* no requests issued */
@@ -30,6 +45,8 @@ struct private_data {
     int state;
 };
 
+static void enable TAC_ARGS((char *passwd, struct authen_data *data));
+
 static void
 enable(passwd, data)
 char *passwd;
@@ -84,6 +101,8 @@ struct authen_data *data;
  * Return 0 if data->status is valid, otherwise 1
  */
 
+int enable_fn TAC_ARGS((struct authen_data *data));
+
 int
 enable_fn(data)
 struct authen_data *data;
@@ -157,14 +176,14 @@ struct authen_data *data;
                   name && name[0] ? name : "unknown",
                   data->NAS_id->NAS_port && data->NAS_id->NAS_port[0] ?
                       data->NAS_id->NAS_port : "unknown",
-                  session.peer, 
+                  session.peer,
                   (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ?
                   "accepted" : "rejected");
        }
        break;
     default:
        data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
-       report(LOG_ERR, "%s: Bogus service value %d from packet", 
+       report(LOG_ERR, "%s: Bogus service value %d from packet",
               session.peer, data->service);
        break;
     }
diff --git a/enable.h b/enable.h
new file mode 100644 (file)
index 0000000..10a4e8a
--- /dev/null
+++ b/enable.h
@@ -0,0 +1,12 @@
+#ifndef ENABLE_H
+#define ENABLE_H 1
+
+#include "tac_plus.h"
+
+
+struct authen_data;
+
+extern int enable_fn TAC_ARGS((struct authen_data *data));
+
+
+#endif /* ENABLE_H */
index 60ba5e9..2840916 100644 (file)
--- a/encrypt.c
+++ b/encrypt.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
+
+#include <stdlib.h>
+#include <netinet/in.h>                /* for ntohl() */
+
+#include "encrypt.h"
 #include "md5.h"
+#include "utils.h"
+#include "report.h"
+#include "packet.h"
+#include "main.h"
+
 
 /*
  * create_md5_hash(): create an md5 hash of the "session_id", "the user's
  *
  */
 
-void
+static void create_md5_hash TAC_ARGS((int session_id, const char *key, unsigned version, unsigned seq_no, u_char *prev_hash, u_char *hash));
+
+static void
 create_md5_hash(session_id, key, version, seq_no, prev_hash, hash)
 int session_id;
-char *key;
-u_char version;
-u_char seq_no;
+const char *key;
+unsigned version;                      /* promoted "u_char" type */
+unsigned seq_no;                       /* promoted "u_char" type */
 u_char *prev_hash;
 u_char *hash;
 {
     u_char *md_stream, *mdp;
     int md_len;
     MD5_CTX mdcontext;
+    u_char version_uchar = version;
+    u_char seq_no_uchar = seq_no;
 
-    md_len = sizeof(session_id) + strlen(key) + sizeof(version) +
-       sizeof(seq_no);
+    md_len = sizeof(session_id) + strlen(key) + sizeof(version_uchar) +
+       sizeof(seq_no_uchar);
 
     if (prev_hash) {
        md_len += MD5_LEN;
@@ -62,11 +77,11 @@ u_char *hash;
     bcopy(key, mdp, strlen(key));
     mdp += strlen(key);
 
-    bcopy(&version, mdp, sizeof(version));
-    mdp += sizeof(version);
+    bcopy(&version_uchar, mdp, sizeof(version_uchar));
+    mdp += sizeof(version_uchar);
 
-    bcopy(&seq_no, mdp, sizeof(seq_no));
-    mdp += sizeof(seq_no);
+    bcopy(&seq_no_uchar, mdp, sizeof(seq_no_uchar));
+    mdp += sizeof(seq_no_uchar);
 
     if (prev_hash) {
        bcopy(prev_hash, mdp, MD5_LEN);
@@ -90,10 +105,13 @@ u_char *hash;
  * Return 0 on success, -1 on failure.
  */
 
+int md5_xor TAC_ARGS((HDR *hdr, u_char *data, const char *key));
+
+int
 md5_xor(hdr, data, key)
 HDR *hdr;
 u_char *data;
-char *key;
+const char *key;
 {
     int i, j;
     u_char hash[MD5_LEN];      /* the md5 hash */
@@ -120,7 +138,7 @@ char *key;
        if (debug & DEBUG_MD5_HASH_FLAG) {
            int k;
 
-           report(LOG_DEBUG, 
+           report(LOG_DEBUG,
                   "hash: session_id=%u, key=%s, version=%d, seq_no=%d",
                   session_id, key, version, seq_no);
            if (prev_hashp) {
@@ -141,7 +159,7 @@ char *key;
        for (j = 0; j < 16; j++) {
 
            if ((i + j) >= data_len) {
-               hdr->encryption = (hdr->encryption == TAC_PLUS_CLEAR) 
+               hdr->encryption = (hdr->encryption == TAC_PLUS_CLEAR)
                    ? TAC_PLUS_ENCRYPTED : TAC_PLUS_CLEAR;
                return (0);
            }
@@ -157,7 +175,7 @@ char *key;
            data[i + j] ^= hash[j];
        }
     }
-    hdr->encryption = (hdr->encryption == TAC_PLUS_CLEAR) 
+    hdr->encryption = (hdr->encryption == TAC_PLUS_CLEAR)
        ? TAC_PLUS_ENCRYPTED : TAC_PLUS_CLEAR;
     return (0);
 }
diff --git a/encrypt.h b/encrypt.h
new file mode 100644 (file)
index 0000000..9c7ae53
--- /dev/null
+++ b/encrypt.h
@@ -0,0 +1,14 @@
+#ifndef ENCRYPT_H
+#define ENCRYPT_H 1
+
+#include "tac_plus.h"
+
+#include <sys/types.h>         /* for u_* */
+
+#include "packet.h"            /* for "HDR" */
+
+
+extern int md5_xor TAC_ARGS((HDR *hdr, u_char *data, const char *key));
+
+
+#endif /* ENCRYPT_H */
index 1ef745c..3aed354 100644 (file)
--- a/expire.c
+++ b/expire.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
+
+#include <ctype.h>
+#include <time.h>
+#include <string.h>
+#include <stdio.h>
+
 #include "expire.h"
 
+
 /*
  * check a date for expiry. If the field specifies
  * a shell return PW_OK
@@ -37,9 +45,11 @@ static char *monthname[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
 static long days_ere_month[] = {0, 31, 59, 90, 120, 151,
 181, 212, 243, 273, 304, 334};
 
+int check_expiration TAC_ARGS((const char *date));
+
 int
 check_expiration(date)
-char *date;
+const char *date;
 {
     long day, month, year, leaps, now, expiration, warning;
     char monthstr[10];
@@ -52,11 +62,11 @@ char *date;
        return (PW_OK);
 
     /* Parse date string.  Fail it upon error. */
-    if (sscanf(date, "%s %d %d", monthstr, &day, &year) != 3)
+    if (sscanf(date, "%s %ld %ld", monthstr, &day, &year) != 3)
        return (PW_EXPIRED);
 
     for(i=0; i < 3; i++) {
-       monthstr[i] = toupper(monthstr[i]);
+       monthstr[i] = toupper((int) monthstr[i]);
     }
 
     /* Compute the expiration date in days. */
index c7df48d..6e7fc5e 100644 (file)
--- a/expire.h
+++ b/expire.h
@@ -1,4 +1,9 @@
-/* 
+#ifndef EXPIRE_H
+#define EXPIRE_H 1
+
+#include "tac_plus.h"
+
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #define PW_OK       0          /* pw not expired and not due to expire soon */
 #define PW_EXPIRED  1          /* pw has expired */
 #define PW_EXPIRING 2          /* pw will expire soon */
 
 #define MAX_PASSWD_LEN 256
 
-extern int check_expiration();
+
+extern int check_expiration TAC_ARGS((const char *date));
+
+
+#endif /* EXPIRE_H */
index 509e48a..a21098d 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
-/* Program to des encrypt a password like Unix 
-   It prompts for the password to encrypt. 
+/* Program to des encrypt a password like Unix
+   It prompts for the password to encrypt.
    You can optionally supply a salt to verify a password.
    Usage: a.out [salt]
 */
 
-#define NULL 0
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+/* Stolen from pbmplus.h of netpbm: */
+
+#if __STDC__
+#define TAC_ARGS(alist) alist
+#else /*__STDC__*/
+#define TAC_ARGS(alist) ()
+#endif /*__STDC__*/
+
+
+int main TAC_ARGS((int argc, char **argv));
+
+int
 main(argc, argv)
+int argc;
 char **argv;
 {
-    char *crypt();
     char pass[25], *salt, buf[24];
     char *result;
     int n;
@@ -42,10 +71,10 @@ char **argv;
 
     write(1, prompt, strlen(prompt));
     n = read(0, pass, sizeof(pass));
-    pass[n-1] = NULL;
+    pass[n-1] = 0;
 
     if (!salt) {
-       int i, r, r1, r2;
+       int i, r, r1 = 0 /* GCC paranoia */, r2 = 0 /* GCC paranoia */;
 
        srand(time(0));
 
@@ -61,7 +90,7 @@ char **argv;
            if (r > 57 && r < 65)
                r += 7;
 
-           if (r > 90 && r < 97) 
+           if (r > 90 && r < 97)
                r += 6;
 
            if (r > 122)
@@ -82,9 +111,6 @@ char **argv;
 
     write(1, result, strlen(result));
     write(1, "\n", 1);
-}
-
-
-
-
 
+    return (EXIT_SUCCESS);
+}
diff --git a/hash.c b/hash.c
index 443d42b..2db807b 100644 (file)
--- a/hash.c
+++ b/hash.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
 
+#include "hash.h"
+#include "utils.h"
+
+
 struct entry {
     char *name;
     void *hash;
 };
 
-typedef struct entry ENTRY;
+static int calculate_hash TAC_ARGS((const char *name));
 
 /* Calculate hash value from a string */
 static int
 calculate_hash(name)
-char *name;
+const char *name;
 {
     int i;
     int len = strlen(name);
@@ -43,12 +48,14 @@ char *name;
     return (hashval);
 }
 
+void *hash_lookup TAC_ARGS((void **hashtab, const char *name));
+
 /* Lookup a name in a hash table.  Return its node if it exists, NULL
    otherwise */
 void *
 hash_lookup(hashtab, name)
 void **hashtab;
-char *name;
+const char *name;
 {
     ENTRY *entry;
     int hashval = calculate_hash(name);
@@ -64,6 +71,8 @@ char *name;
     return (NULL);
 }
 
+void *hash_add_entry TAC_ARGS((void **hashtab, ENTRY *newentry));
+
 /* Add a node to a hash table.  Return node if it exists, NULL
    otherwise */
 void *
@@ -86,6 +95,8 @@ ENTRY *newentry;
 }
 
 
+void **hash_get_entries TAC_ARGS((void **hashtab));
+
 /* Return an array of pointers to all the entries in a hash table */
 void **
 hash_get_entries(hashtab)
diff --git a/hash.h b/hash.h
new file mode 100644 (file)
index 0000000..a808f05
--- /dev/null
+++ b/hash.h
@@ -0,0 +1,17 @@
+#ifndef HASH_H
+#define HASH_H 1
+
+#include "tac_plus.h"
+
+
+#define HASH_TAB_SIZE 157        /* user and group hash table sizes */
+
+typedef struct entry ENTRY;
+
+
+extern void *hash_lookup TAC_ARGS((void **hashtab, const char *name));
+extern void *hash_add_entry TAC_ARGS((void **hashtab, ENTRY *newentry));
+extern void **hash_get_entries TAC_ARGS((void **hashtab));
+
+
+#endif /* HASH_H */
diff --git a/install-sh b/install-sh
deleted file mode 100644 (file)
index 1a24852..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#!/bin/sh
diff --git a/ldap.c b/ldap.c
deleted file mode 100644 (file)
index ca1a8ef..0000000
--- a/ldap.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
-     Verify that this user/password is valid per a database LDAP server
-     Return 1 if verified, 0 otherwise.
-     
-     Format of connection string (look like internet URL):
-
-       ldap://LDAP-hostname
-     
-     -------------------------------------------------------
-     patrick.harpes@tudor.lu            http://www.santel.lu
-                                        http://www.tudor.lu
-     
-
-
-     Dependencies: You need to get the OpenLDAP libraries
-                   from http://www.openldap.org
-      License: tac_ldap is free software; you can redistribute it
-               and/or modify it under the terms of the GNU General Public License
-               as published by the Free Software Foundation; either version 2,
-               or (at your option) any later version.
---------------------------------------------------------------------------
-                               Changes:
- Ok i am back again..:)
- I changed lot of thing.. First off all i add port feature to ldap string.
- And also add more check for buffer overflows.
-
-Connect format would be:
-       ldap://LDAP-hostname:100
-
-Port name isn't required.. I would like to change format with : 
-       ldap://LDAP-hostname:100/dn_for_user&dn_for_passwd
-
- devrim seral <devrim@gazi.edu.tr> 
-
-*/ 
-
-
-#if defined(USE_LDAP)
-#include <stdio.h>
-#include <string.h>
-#include <lber.h>
-#include <ldap.h>
-#include <ldap_cdefs.h>
-
-#include "tac_plus.h"
-#include "ldap.h"
-
-
-int
-ldap_verify(user, users_passwd, str_conn)
-char *user, *users_passwd;      /* Username and gived password   */
-char *str_conn;                 /* String connection to database */
-{
-  char *buf;
-  char *ldapServer;
-  char *ldap_port;
-  LDAP *ld;
-  int port;
-  int err;
-
-/* Don't allow null username and passwd */ 
-  if ( *user == '0' || *users_passwd == '0' ) return (1);
-
-  buf=(char *)malloc(strlen(str_conn)+1);
-  if (buf == NULL ){ 
-       report(LOG_DEBUG, "Error can't allocate memory");
-        return(1);
-  }
-  
-  strcpy(buf,str_conn);
-  ldapServer=strstr(buf, "://");
-  
-  if(ldapServer == NULL && strlen(ldapServer) <4 ) {
-       if (debug) {
-               report(LOG_DEBUG, "Error parse ldap server");
-               return(1);
-       }
-  } 
-  
- ldapServer=ldapServer+3;
-
- ldap_port=(char *)strstr(ldapServer, ":");
-
- if (ldap_port != NULL ) {
-               *ldap_port='\0';
-               port=atoi(++ldap_port);
- } else {
-       port = LDAP_PORT;
- }
- if ( debug & DEBUG_AUTHEN_FLAG ) 
-  report(LOG_DEBUG, "In verify_ldap : Before ldap_init : ldapserver = %s port= %d", ldapServer, port);
-
-
-  if( (ld = ldap_init(ldapServer, port)) == NULL)
-    {
-      report(LOG_DEBUG, "Unable to connect to LDAP server:%s port:%d",ldapServer, port);
-      return 1;
-    }
-  
-  err=ldap_simple_bind_s(ld, user, users_passwd);
-  
-  if(err != LDAP_SUCCESS)
-    {
-      if ( debug & DEBUG_AUTHEN_FLAG ) 
-       report(LOG_DEBUG,"Error while bind : %d %s",err, ldap_err2string(err) );
-      return 1;
-    }         
-  else
-    {
-      /* Success */
-     if ( debug & DEBUG_AUTHEN_FLAG ) 
-               report(LOG_DEBUG, "LDAP authentication Sucess ");
-     ldap_unbind_s(ld); 
-     return 0;
-    }
-}
-#endif /* LDAP */
diff --git a/ldap.h b/ldap.h
deleted file mode 100644 (file)
index 6479426..0000000
--- a/ldap.h
+++ /dev/null
@@ -1 +0,0 @@
-int ldap_verify();
index ca1a8ef..c788e82 100644 (file)
@@ -1,20 +1,20 @@
 /*
      Verify that this user/password is valid per a database LDAP server
      Return 1 if verified, 0 otherwise.
-     
+
      Format of connection string (look like internet URL):
 
        ldap://LDAP-hostname
-     
+
      -------------------------------------------------------
      patrick.harpes@tudor.lu            http://www.santel.lu
                                         http://www.tudor.lu
-     
+
 
 
      Dependencies: You need to get the OpenLDAP libraries
                    from http://www.openldap.org
+
       License: tac_ldap is free software; you can redistribute it
                and/or modify it under the terms of the GNU General Public License
                as published by the Free Software Foundation; either version 2,
 Connect format would be:
        ldap://LDAP-hostname:100
 
-Port name isn't required.. I would like to change format with : 
+Port name isn't required.. I would like to change format with :
        ldap://LDAP-hostname:100/dn_for_user&dn_for_passwd
 
- devrim seral <devrim@gazi.edu.tr> 
+ devrim seral <devrim@gazi.edu.tr>
+
+*/
 
-*/ 
 
+#include "tac_plus.h"
+
+#ifdef USE_LDAP
 
-#if defined(USE_LDAP)
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 #include <lber.h>
 #include <ldap.h>
 #include <ldap_cdefs.h>
 
-#include "tac_plus.h"
-#include "ldap.h"
+#include "ldap_author.h"
+#include "main.h"
+#include "utils.h"
+#include "report.h"
+
 
+int ldap_verify TAC_ARGS((const char *user, const char *users_passwd, const char *str_conn));
 
 int
 ldap_verify(user, users_passwd, str_conn)
-char *user, *users_passwd;      /* Username and gived password   */
-char *str_conn;                 /* String connection to database */
+const char *user;              /* username ... */
+const char *users_passwd;      /* ... and given password */
+const char *str_conn;                  /* string connection to database */
 {
   char *buf;
   char *ldapServer;
@@ -59,25 +68,21 @@ char *str_conn;                 /* String connection to database */
   int port;
   int err;
 
-/* Don't allow null username and passwd */ 
+/* Don't allow null username and passwd */
   if ( *user == '0' || *users_passwd == '0' ) return (1);
 
-  buf=(char *)malloc(strlen(str_conn)+1);
-  if (buf == NULL ){ 
-       report(LOG_DEBUG, "Error can't allocate memory");
-        return(1);
-  }
-  
+  buf = (char *) tac_malloc(strlen(str_conn)+1);
+
   strcpy(buf,str_conn);
   ldapServer=strstr(buf, "://");
-  
+
   if(ldapServer == NULL && strlen(ldapServer) <4 ) {
        if (debug) {
                report(LOG_DEBUG, "Error parse ldap server");
                return(1);
        }
-  } 
-  
+  }
+
  ldapServer=ldapServer+3;
 
  ldap_port=(char *)strstr(ldapServer, ":");
@@ -88,8 +93,8 @@ char *str_conn;                 /* String connection to database */
  } else {
        port = LDAP_PORT;
  }
- if ( debug & DEBUG_AUTHEN_FLAG ) 
+
+ if ( debug & DEBUG_AUTHEN_FLAG )
   report(LOG_DEBUG, "In verify_ldap : Before ldap_init : ldapserver = %s port= %d", ldapServer, port);
 
 
@@ -98,22 +103,27 @@ char *str_conn;                 /* String connection to database */
       report(LOG_DEBUG, "Unable to connect to LDAP server:%s port:%d",ldapServer, port);
       return 1;
     }
-  
-  err=ldap_simple_bind_s(ld, user, users_passwd);
-  
+
+  err=ldap_simple_bind_s(ld, (/* de-const */ char *) user, (/* de-const */ char *) users_passwd);
+
   if(err != LDAP_SUCCESS)
     {
-      if ( debug & DEBUG_AUTHEN_FLAG ) 
+      if ( debug & DEBUG_AUTHEN_FLAG )
        report(LOG_DEBUG,"Error while bind : %d %s",err, ldap_err2string(err) );
       return 1;
-    }         
+    }
   else
     {
       /* Success */
-     if ( debug & DEBUG_AUTHEN_FLAG ) 
+     if ( debug & DEBUG_AUTHEN_FLAG )
                report(LOG_DEBUG, "LDAP authentication Sucess ");
-     ldap_unbind_s(ld); 
+     ldap_unbind_s(ld);
      return 0;
     }
 }
-#endif /* LDAP */
+
+#else /* USE_LDAP */
+
+TAC_SOURCEFILE_EMPTY
+
+#endif /* USE_LDAP */
index 6479426..ecd71dd 100644 (file)
@@ -1 +1,14 @@
-int ldap_verify();
+#ifndef LDAP_AUTHOR_H
+#define LDAP_AUTHOR_H 1
+
+#include "tac_plus.h"
+
+#ifdef USE_LDAP
+
+
+extern int ldap_verify TAC_ARGS((const char *user, const char *users_passwd, const char *str_conn));
+
+
+#endif /* USE_LDAP */
+
+#endif /* LDAP_AUTHOR_H */
diff --git a/main.c b/main.c
index cf0ffd8..3878c01 100644 (file)
--- a/main.c
+++ b/main.c
@@ -14,7 +14,7 @@
  * distribution of the program without specific prior permission, and
  * notice be given in supporting documentation that modification,
  * copying and distribution is by permission of Cisco Systems, Inc.
-
+ *
  * Cisco Systems, Inc. makes no representations about the suitability
  * of this software for any purpose.  THIS SOFTWARE IS PROVIDED ``AS
  * IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
  * FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
-#include "sys/wait.h"
-#include "signal.h"
+
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netdb.h>
+#include <errno.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+#ifdef HAVE_SYS_SYSLOG_H
+#include <sys/syslog.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#include "main.h"
+#include "report.h"
+#include "utils.h"
+#include "cfgfile.h"
+#include "packet.h"
+#include "dump.h"
+#include "author.h"
+#include "acct.h"
+#include "authen.h"
+#include "do_acct.h"
+#include "parse.h"
+
+#ifdef MAXSESS
+#include "maxsess.h"
+#endif
+
+
+static void version TAC_ARGS((void));
+static void start_session TAC_ARGS((void));
+
+
+/* Configurable:
+ */
+
+#ifndef TAC_PLUS_PORT
+#define        TAC_PLUS_PORT                   49
+#endif
+
 
 static int standalone  = 1; /* running standalone (1) or under inetd (0) */
 static int initialised = 0; /* data structures have been allocated */
 int sendauth_only      = 0; /* don't respond to sendpass requests */
 int debug              = 0; /* debugging flags */
-int port               = 0; /* port we're listening on */
+static int port        = 0; /* port we're listening on */
 int console            = 0; /* write all syslog messages to console */
 int parse_only         = 0; /* exit after verbose parsing */
 int single             = 0; /* single thread (for debugging) */
-int wtmpfd            = 0; /* for wtmp file logging */
-char *wtmpfile         = NULL;
-
-struct timeval started_at;
 
 struct session session;     /* session data */
 
 static char pidfilebuf[75]; /* holds current name of the pidfile */
 
-void start_session();
 
 #ifndef REAPCHILD
-static
-#ifdef VOIDSIG
-void 
-#else
-int
-#endif /* VOIDSIG */
-reapchild()
+static RETSIGTYPE reapchild TAC_ARGS((int signo));
+
+static RETSIGTYPE
+reapchild(signo)
+int signo;
 {
 #ifdef UNIONWAIT
     union wait status;
@@ -61,6 +111,8 @@ reapchild()
 #endif
     int pid;
 
+    signal(SIGCHLD, reapchild);
+
     for (;;) {
        pid = wait3(&status, WNOHANG, 0);
        if (pid <= 0)
@@ -71,6 +123,8 @@ reapchild()
 }
 #endif /* REAPCHILD */
 
+static void die TAC_ARGS((int signum));
+
 static void
 die(signum)
 int signum;
@@ -80,21 +134,23 @@ int signum;
     tac_exit(0);
 }
 
+static void init TAC_ARGS((void));
+
 static void
 init()
 {
     if (initialised)
-       cfg_clean_config();    
+       cfg_clean_config();
 
     report(LOG_INFO, "Reading config");
 
     session.acctfile = tac_strdup("/var/log/acctfile");
-    
+
     if (!session.cfgfile) {
        report(LOG_ERR, "no config file specified");
        tac_exit(1);
     }
-    
+
     /* read the config file */
     if (cfg_read_config(session.cfgfile)) {
        report(LOG_ERR, "Parsing %s", session.cfgfile);
@@ -104,26 +160,59 @@ init()
 
     initialised++;
 
-    report(LOG_INFO, "Version %s Initialized %d", VERSION, initialised);
+    report(LOG_INFO, "Version %s%s Initialized %d", VERSION, VERSION_TAIL, initialised);
 
 }
 
-static void
+/* 'handler()' will be called during initialization to setup signal handler,
+ * keep it in mind when modifying it!
+ */
+
+static int handler_occured = 0;
+
+static RETSIGTYPE handler TAC_ARGS((int signum));
+
+static RETSIGTYPE
 handler(signum)
 int signum;
 {
-    report(LOG_INFO, "Received signal %d", signum);
-    init();
-#ifdef REARMSIGNAL
+    /* never execute any non-trivial (=system-call) commands here
+     * as it may immediately abort the whole 'handler()' (SYSV signal).
+     * We hope that SA_RESTART is NOT set for our signals
+     */
+    handler_occured = 1;
+    /* It is never wrong to reinstall 'handler' just to be safe */
     signal(SIGUSR1, handler);
-    signal(SIGHUP, handler);
-#endif REARMSIGNAL
+    signal(SIGHUP , handler);
+
+    /* DON'T interrupt! */
+#ifdef HAVE_SIGINTERRUPT
+    siginterrupt(SIGUSR1, 0 /* flag */);
+    siginterrupt(SIGHUP , 0 /* flag */);
+#endif
+}
+
+static void check_handler_occured TAC_ARGS((void));
+
+static RETSIGTYPE
+check_handler_occured()
+{
+
+    if (!handler_occured)
+       return;
+
+    handler_occured = 0;
+    report(LOG_INFO, "Signal detected, reloading configuration");
+    init();
 }
 
 /*
  * Return a socket bound to an appropriate port number/address. Exits
  * the program on failure */
 
+static int get_socket TAC_ARGS((void));
+
+static int
 get_socket()
 {
     int s;
@@ -171,6 +260,8 @@ get_socket()
     return (s);
 }
 
+static void open_logfile TAC_ARGS((void));
+
 static void
 open_logfile()
 {
@@ -182,6 +273,29 @@ open_logfile()
     setlogmask(LOG_UPTO(LOG_DEBUG));
 }
 
+static void prep_session_peer TAC_ARGS((const struct sockaddr_in *from));
+
+static void
+prep_session_peer(from)
+const struct sockaddr_in *from;
+{
+    struct hostent *hp;
+
+    if (session.peer_addr && session.peer_addr != session.peer)
+       free(session.peer_addr);
+    if (session.peer)
+       free(session.peer);
+
+    session.peer_addr = tac_strdup( (char *) inet_ntoa(from->sin_addr) );
+
+    hp = gethostbyaddr((char *) &from->sin_addr.s_addr, sizeof(from->sin_addr.s_addr), AF_INET);
+
+    if (hp)
+       session.peer = tac_strdup(hp->h_name);
+    else
+       session.peer = session.peer_addr;
+}
+
 /*
  * main
  *
@@ -189,6 +303,9 @@ open_logfile()
  * Parse arguments and act appropiately.
  */
 
+int main TAC_ARGS((int argc, char **argv));
+
+int
 main(argc, argv)
 int argc;
 char **argv;
@@ -214,6 +331,10 @@ char **argv;
     port = TAC_PLUS_PORT;
 #endif
 
+#ifdef MAINTAINER_MODE
+    session.cfgfile = "/etc/tacacs/tac_plus.cfg";
+#endif
+
     if (argc <= 1) {
        fprintf(stderr, "Usage: tac_plus -C <configuration file>\n");
        fprintf(stderr, "\t[ -t ] [ -P ] [ -g ] [ -p <port> ]\n");
@@ -284,8 +405,9 @@ char **argv;
 
     init();
 
-    signal(SIGUSR1, handler);
-    signal(SIGHUP, handler);
+    handler(-1 /* signum */);          /* connect to the signals */
+    handler_occured = 0;               /* post-fix cludge */
+
     signal(SIGTERM, die);
     signal(SIGPIPE, SIG_IGN);
 
@@ -293,31 +415,27 @@ char **argv;
        tac_exit(0);
 
     if (debug)
-       report(LOG_DEBUG, "tac_plus server %s starting", VERSION);
+       report(LOG_DEBUG, "tac_plus server %s%s starting", VERSION, VERSION_TAIL);
 
     if (!standalone) {
        /* running under inetd */
        struct sockaddr_in name;
-       int name_len;
-       int on = 1;
+       socklen_t name_len;
+#ifdef FIONBIO
+       int fionbio_on = 1;
+#endif
 
        name_len = sizeof(name);
 
-       session.sock = 0;
        if (getpeername(session.sock, (struct sockaddr *) &name, &name_len)) {
            report(LOG_ERR, "getpeername failure %s", sys_errlist[errno]);
-       } else {
-           struct hostent *hp;
-           hp = gethostbyaddr((char *) &name.sin_addr.s_addr,
-                              sizeof(name.sin_addr.s_addr), AF_INET);
-           if (session.peer) {
-               free(session.peer);
-           }
-           session.peer = tac_strdup(hp ? hp->h_name : 
-                                 (char *) inet_ntoa(name.sin_addr));
-       }
+           prep_session_peer(NULL);
+       } else
+           prep_session_peer(&name);
+
+       session.sock = 0;
 #ifdef FIONBIO
-       if (ioctl(session.sock, FIONBIO, &on) < 0) {
+       if (ioctl(session.sock, FIONBIO, &fionbio_on) < 0) {
            report(LOG_ERR, "ioctl(FIONBIO) %s", sys_errlist[errno]);
            tac_exit(1);
        }
@@ -338,9 +456,9 @@ char **argv;
 #ifdef SIGTSTP
        signal(SIGTSTP, SIG_IGN);
 #endif
-       
+
        signal(SIGHUP, SIG_IGN);
-    
+
        if ((childpid = fork()) < 0)
            report(LOG_ERR, "Can't fork first child");
        else if (childpid > 0)
@@ -351,23 +469,29 @@ char **argv;
 
 #ifndef REAPCHILD
 
-#ifdef LINUX
+#ifdef SETPGRP_VOID
        if (setpgrp() == -1)
-#else /* LINUX */
+#else /* SETPGRP_VOID */
        if (setpgrp(0, getpid()) == -1)
-#endif /* LINUX */
+#endif /* SETPGRP_VOID */
            report(LOG_ERR, "Can't change process group");
-       
+
+#ifdef TIOCNOTTY
        c = open("/dev/tty", O_RDWR);
        if (c >= 0) {
            ioctl(c, TIOCNOTTY, (char *) 0);
            (void) close(c);
        }
+#endif
        signal(SIGCHLD, reapchild);
 
 #else /* REAPCHILD */
 
+#ifdef SETPGRP_VOID
        if (setpgrp() == 1)
+#else /* SETPGRP_VOID */
+       if (setpgrp(0, getpid()) == 1)
+#endif /* SETPGRP_VOID */
            report(LOG_ERR, "Can't change process group");
 
        signal(SIGHUP, SIG_IGN);
@@ -376,7 +500,7 @@ char **argv;
            report(LOG_ERR, "Can't fork second child");
        else if (childpid > 0)
            exit(0);
-    
+
        if (debug & DEBUG_FORK_FLAG)
            report(LOG_DEBUG, "Forked grandchild");
 
@@ -393,18 +517,18 @@ char **argv;
        open_logfile();
 
     } /* ! single threaded */
-    
+
     ostream = NULL;
     /* chdir("/"); */
     umask(0);
     errno = 0;
 
     s = get_socket();
-   
+
 #ifndef SOMAXCONN
 #ifdef LINUX
 #define SOMAXCONN 128
-#else 
+#else
 #define SOMAXCONN 5
 #endif /* LINUX */
 #endif /* SOMAXCONN */
@@ -423,21 +547,21 @@ char **argv;
 
     /* write process id to pidfile */
     if ((fp = fopen(pidfilebuf, "w")) != NULL) {
-       fprintf(fp, "%d\n", getpid());
+       fprintf(fp, "%d\n", (int) getpid());
        fclose(fp);
-    } else 
-       report(LOG_ERR, "Cannot write pid to %s %s", 
+    } else
+       report(LOG_ERR, "Cannot write pid to %s %s",
               pidfilebuf, sys_errlist[errno]);
 
 #ifdef TACPLUS_GROUPID
     if (setgid(TACPLUS_GROUPID))
-       report(LOG_ERR, "Cannot set group id to %d %s", 
+       report(LOG_ERR, "Cannot set group id to %d %s",
               TACPLUS_GROUPID, sys_errlist[errno]);
 #endif
 
 #ifdef TACPLUS_USERID
-    if (setuid(TACPLUS_USERID)) 
-       report(LOG_ERR, "Cannot set user id to %d %s", 
+    if (setuid(TACPLUS_USERID))
+       report(LOG_ERR, "Cannot set user id to %d %s",
               TACPLUS_USERID, sys_errlist[errno]);
 #endif
 
@@ -446,41 +570,48 @@ char **argv;
 #endif /* MAXSESS */
 
     report(LOG_DEBUG, "uid=%d euid=%d gid=%d egid=%d s=%d",
-          getuid(), geteuid(), getgid(), getegid(), s);
+          (int) getuid(), (int) geteuid(), (int) getgid(), (int) getegid(), s);
 
     for (;;) {
        int pid;
        struct sockaddr_in from;
-       int from_len;
+       socklen_t from_len;
        int newsockfd;
-       struct hostent *hp = NULL;
+
+       check_handler_occured();
 
        bzero((char *) &from, sizeof(from));
        from_len = sizeof(from);
 
+       /* PERMIT interrupt of accept()! */
+#ifdef HAVE_SIGINTERRUPT
+       siginterrupt(SIGUSR1, 1 /* flag */);
+       siginterrupt(SIGHUP , 1 /* flag */);
+#endif
+
+       errno = 0;
        newsockfd = accept(s, (struct sockaddr *) &from, &from_len);
 
+       /* DON'T interrupt! */
+#ifdef HAVE_SIGINTERRUPT
+       siginterrupt(SIGUSR1, 0 /* flag */);
+       siginterrupt(SIGHUP , 0 /* flag */);
+#endif
+
+       check_handler_occured();
+
        if (newsockfd < 0) {
-           if (errno == EINTR)
+           /* sometimes we may get even 'errno==0' when 'handler()' signal occured */
+           if (errno == EINTR || errno == 0)
                continue;
 
            report(LOG_ERR, "accept: %s", sys_errlist[errno]);
            continue;
        }
-
-       if (lookup_peer) {
-           hp = gethostbyaddr((char *) &from.sin_addr.s_addr,
-                              sizeof(from.sin_addr.s_addr), AF_INET);
-       }
-
-       if (session.peer) {
-           free(session.peer);
-       }
-       session.peer = tac_strdup(hp ? hp->h_name : 
-                                 (char *) inet_ntoa(from.sin_addr));
+       prep_session_peer(&from);
 
        if (debug & DEBUG_PACKET_FLAG)
-           report(LOG_DEBUG, "session request from %s sock=%d", 
+           report(LOG_DEBUG, "session request from %s sock=%d",
                   session.peer, newsockfd);
 
        if (!single) {
@@ -514,25 +645,27 @@ char **argv;
 }
 
 #ifdef GETDTABLESIZE
-int 
+int
 getdtablesize()
 {
     return(_NFILE);
 }
 #endif /* GETDTABLESIZE */
 
+static int bad_version_check TAC_ARGS((u_char *pak));
+
 /* Make sure version number is kosher. Return 0 if it is */
-int
+static int
 bad_version_check(pak)
 u_char *pak;
 {
     HDR *hdr = (HDR *) pak;
-    
+
     switch (hdr->type) {
     case TAC_PLUS_AUTHEN:
-       /* 
+       /*
         * Let authen routines take care of more sophisticated version
-        * checking as its now a bit involved. 
+        * checking as its now a bit involved.
         */
        return(0);
 
@@ -555,12 +688,13 @@ u_char *pak;
  *
  */
 
-void
+static void start_session TAC_ARGS((void));
+
+static void
 start_session()
 {
-    u_char *pak, *read_packet();
+    u_char *pak;
     HDR *hdr;
-    void authen();
 
     session.seq_no = 0;
     session.aborted = 0;
@@ -608,9 +742,12 @@ start_session()
     }
 }
 
+static void version TAC_ARGS((void));
+
+static void
 version()
 {
-    fprintf(stdout, "tac_plus version %s\n", VERSION);
+    fprintf(stdout, "tac_plus version %s%s\n", VERSION, VERSION_TAIL);
 #ifdef AIX
     fprintf(stdout,"AIX\n");
 #endif
@@ -644,9 +781,6 @@ version()
 #ifdef LINUX
     fprintf(stdout,"LINUX\n");
 #endif
-#ifdef LITTLE_ENDIAN
-    fprintf(stdout,"LITTLE_ENDIAN\n");
-#endif
 #ifdef LOG_LOCAL6
     fprintf(stdout,"LOG_LOCAL6\n");
 #endif
@@ -662,15 +796,9 @@ version()
 #ifdef NETBSD
     fprintf(stdout,"NETBSD\n");
 #endif
-#ifdef NO_PWAGE
-    fprintf(stdout,"NO_PWAGE\n");
-#endif
 #ifdef REAPCHILD
     fprintf(stdout,"REAPCHILD\n");
 #endif
-#ifdef REARMSIGNAL
-    fprintf(stdout,"REARMSIGNAL\n");
-#endif
 #ifdef SHADOW_PASSWORDS
     fprintf(stdout,"SHADOW_PASSWORDS\n");
 #endif
@@ -692,14 +820,8 @@ version()
 #ifdef SO_REUSEADDR
     fprintf(stdout,"SO_REUSEADDR\n");
 #endif
-#ifdef STDLIB_MALLOC
-    fprintf(stdout,"STDLIB_MALLOC\n");
-#endif
-#ifdef STRCSPN
-    fprintf(stdout,"STRCSPN\n");
-#endif
-#ifdef SYSLOG_IN_SYS
-    fprintf(stdout,"SYSLOG_IN_SYS\n");
+#ifdef HAVE_STRCSPN
+    fprintf(stdout,"HAVE_STRCSPN\n");
 #endif
 #ifdef SYSV
     fprintf(stdout,"SYSV\n");
@@ -713,15 +835,9 @@ version()
 #ifdef TACPLUS_USERID
     fprintf(stdout,"TACPLUS_USERID\n");
 #endif
-#ifdef TRACE
-    fprintf(stdout,"TRACE\n");
-#endif
 #ifdef UNIONWAIT
     fprintf(stdout,"UNIONWAIT\n");
 #endif
-#ifdef VOIDSIG
-    fprintf(stdout,"VOIDSIG\n");
-#endif
 #ifdef _BSD1
     fprintf(stdout,"_BSD1\n");
 #endif
diff --git a/main.h b/main.h
new file mode 100644 (file)
index 0000000..79c643a
--- /dev/null
+++ b/main.h
@@ -0,0 +1,59 @@
+#ifndef MAIN_H
+#define MAIN_H 1
+
+#include "tac_plus.h"
+
+#include <sys/types.h>         /* for u_* */
+
+
+#define NAS_PORT_MAX_LEN                255
+
+struct session {
+    int session_id;                /* host specific unique session id */
+    int aborted;                   /* have we received an abort flag? */
+    int seq_no;                    /* seq. no. of last packet exchanged */
+    time_t last_exch;              /* time of last packet exchange */
+    int sock;                      /* socket for this connection */
+    char *key;                     /* the key */
+    int keyline;                   /* line number key was found on */
+    char *peer;                    /* name of connected peer */
+    char *peer_addr;               /* numerical name of connected peer */
+                                   /* it MAY (peer==peer_addr)! */
+    char *cfgfile;                 /* config file name */
+    char *acctfile;                /* name of accounting file */
+    char *db_acct;                        /* name of db accounting string */
+    char port[NAS_PORT_MAX_LEN+1]; /* For error reporting */
+    u_char version;                /* version of last packet read */
+};
+
+extern int debug;                  /* debugging flag */
+extern int single;                 /* do not fork (for debugging) */
+extern int console;                /* log to console */
+extern int parse_only;             /* exit after parsing verbosely */
+extern int sendauth_only;          /* don't do sendauth */
+
+/* Debugging flags */
+
+#define DEBUG_PARSE_FLAG     2
+#define DEBUG_FORK_FLAG      4
+#define DEBUG_AUTHOR_FLAG    8
+#define DEBUG_AUTHEN_FLAG    16
+#define DEBUG_PASSWD_FLAG    32
+#define DEBUG_ACCT_FLAG      64
+#define DEBUG_CONFIG_FLAG    128
+#define DEBUG_PACKET_FLAG    256
+#define DEBUG_HEX_FLAG       512
+#define DEBUG_MD5_HASH_FLAG  1024
+#define DEBUG_XOR_FLAG       2048
+#define DEBUG_CLEAN_FLAG     4096
+#define DEBUG_SUBST_FLAG     8192
+#define DEBUG_CFGEVAL_FLAG   16384
+#define DEBUG_MAXSESS_FLAG   32768
+#define DEBUG_LOCK_FLAG      65536
+
+
+extern struct session session;     /* the session */
+extern int main TAC_ARGS((int argc, char **argv));
+
+
+#endif /* MAIN_H */
index 83e0815..aa81a9a 100644 (file)
--- a/maxsess.c
+++ b/maxsess.c
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
 
 #ifdef MAXSESS
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <netdb.h>
+
+#include "maxsess.h"
+#include "report.h"
+#include "utils.h"
+#include "cfgfile.h"
+#include "main.h"
+#include "do_acct.h"
+#include "parse.h"
+
+
+void maxsess_loginit TAC_ARGS((void));
+
+
+/* Configurable:
+ */
+
+/* This is a shared file used to maintain a record of who's on
+ */
+#define WHOLOG_DEFAULT "/var/log/tac_who.log"
+
+
+/*
+ * This is state kept per user/session
+ */
+struct peruser {
+    char username[64];         /* User name */
+    char NAS_name[32];         /* NAS user logged into */
+    char NAS_port[32];         /*  ...port on that NAS */
+    char NAC_address[32];      /*  ...IP address of NAS */
+};
+
+
 char *wholog = WHOLOG_DEFAULT;
 /*
  * initialize wholog file for tracking of user logins/logouts from
@@ -41,6 +94,8 @@ maxsess_loginit()
     }
 }
 
+static char *portname TAC_ARGS((char *oldport));
+
 /*
  * Given a port description, return it in a canonical format.
  *
@@ -67,6 +122,8 @@ char *oldport;
     return (p);
 }
 
+static void write_record TAC_ARGS((char *name, FILE *fp, void *buf, int size, long int offset));
+
 /*
  * Seek to offset and write a buffer into the file pointed to by fp
  */
@@ -79,7 +136,7 @@ void *buf;
 char *name;
 {
     if (fseek(fp, offset, SEEK_SET) < 0) {
-       report(LOG_ERR, "%s fd=%d Cannot seek to %d %s",
+       report(LOG_ERR, "%s fd=%d Cannot seek to %ld %s",
               name, fileno(fp), offset, sys_errlist[errno]);
     }
     if (fwrite(buf, size, 1, fp) != 1) {
@@ -88,6 +145,8 @@ char *name;
     }
 }
 
+static void process_stop_record TAC_ARGS((struct identity *idp));
+
 static void
 process_stop_record(idp)
 struct identity *idp;
@@ -122,7 +181,7 @@ struct identity *idp;
        /* A match. Zero out this record */
        bzero(&pu, sizeof(pu));
 
-       write_record(wholog, fp, &pu, sizeof(pu), 
+       write_record(wholog, fp, &pu, sizeof(pu),
                     recnum * sizeof(struct peruser));
 
        if (debug & DEBUG_MAXSESS_FLAG) {
@@ -133,6 +192,8 @@ struct identity *idp;
     fclose(fp);
 }
 
+static void process_start_record TAC_ARGS((struct identity *idp));
+
 static void
 process_start_record(idp)
 struct identity *idp;
@@ -166,7 +227,7 @@ struct identity *idp;
 
     /* This is a START record, so write a new record or update the existing
      * one.  Note that we bzero(), so the strncpy()'s will truncate long
-     * names and always leave a null-terminated string. 
+     * names and always leave a null-terminated string.
      */
 
     bzero(&pu, sizeof(pu));
@@ -215,10 +276,13 @@ struct identity *idp;
 }
 
 
+void loguser TAC_ARGS((struct acct_rec *rec));
+
 /*
  * Given a start or a stop accounting record, update the file of
  * records which tracks who's logged on and where.
  */
+void
 loguser(rec)
 struct acct_rec *rec;
 {
@@ -260,10 +324,12 @@ struct acct_rec *rec;
  * Return -1 on error, eof or timeout. Otherwise return number of
  * bytes read. */
 
-int
+static int timed_read TAC_ARGS((int fd, void *ptr, int nbytes, int timeout));
+
+static int
 timed_read(fd, ptr, nbytes, timeout)
 int fd;
-u_char *ptr;
+void *ptr;
 int nbytes;
 int timeout;
 {
@@ -348,6 +414,8 @@ int timeout;
  * with a maximum possible width of 10.
  */
 
+static int ckfinger TAC_ARGS((char *user, char *nas, struct identity *idp));
+
 static int
 ckfinger(user, nas, idp)
 char *user, *nas;
@@ -372,7 +440,7 @@ struct identity *idp;
 
     /* Get IP addr for the NAS */
     inaddr = inet_addr(nas);
-    if (inaddr != -1) {
+    if (inaddr != (u_long)-1) {
        /* A dotted decimal address */
        bcopy(&inaddr, &sin.sin_addr, sizeof(inaddr));
        sin.sin_family = AF_INET;
@@ -492,6 +560,8 @@ struct identity *idp;
     return (count);
 }
 
+static int countusers_by_finger TAC_ARGS((struct identity *idp));
+
 /*
  * Verify how many sessions a user has according to the wholog file.
  * Use finger to contact each NAS that wholog says has this user
@@ -565,6 +635,8 @@ struct identity *idp;
     return (nsess);
 }
 
+static int countuser TAC_ARGS((struct identity *idp));
+
 /*
  * Estimate how many sessions a named user currently owns by looking in
  * the wholog file.
@@ -604,6 +676,8 @@ struct identity *idp;
     return (nsess);
 }
 
+static int is_async TAC_ARGS((char *portname));
+
 /*
  * is_async()
  * Tell if the named NAS port is an async-like device.
@@ -622,6 +696,8 @@ char *portname;
     return (0);
 }
 
+int maxsess_check_count TAC_ARGS((char *user, struct author_data *data));
+
 /*
  * See if this user can have more sessions.
  */
@@ -636,7 +712,7 @@ struct author_data *data;
     /* No max session configured--don't check */
     id = data->id;
 
-    maxsess = cfg_get_intvalue(user, TAC_IS_USER, S_maxsess, TAC_PLUS_RECURSE);
+    maxsess = cfg_get_intvalue(S_user, user, S_maxsess, TAC_PLUS_RECURSE);
     if (!maxsess) {
        if (debug & (DEBUG_MAXSESS_FLAG | DEBUG_AUTHOR_FLAG)) {
            report(LOG_DEBUG, "%s may run an unlimited number of sessions",
@@ -678,15 +754,8 @@ struct author_data *data;
     return (0);
 }
 
-#else                          /* MAXSESS */
-
-/*
- * The following code is not needed or used. It exists solely to
- * prevent compilers from "helpfully" complaining that this source
- * file is empty when MAXSESS is not defined. This upsets novices
- * building the software, and I get complaints
- */
+#else /* MAXSESS */
 
-static int dummy = 0;
+TAC_SOURCEFILE_EMPTY
 
-#endif                         /* MAXSESS */
+#endif /* MAXSESS */
diff --git a/maxsess.h b/maxsess.h
new file mode 100644 (file)
index 0000000..c96d2b8
--- /dev/null
+++ b/maxsess.h
@@ -0,0 +1,25 @@
+#ifndef MAXSESS_H
+#define MAXSESS_H 1
+
+#include "tac_plus.h"
+
+#ifdef MAXSESS
+
+#include "do_author.h"
+
+
+/* This is a shared file used to maintain a record of who's on
+ */
+extern char *wholog;
+
+
+struct acct_rec;
+
+extern void maxsess_loginit TAC_ARGS((void));
+extern void loguser TAC_ARGS((struct acct_rec *rec));
+extern int maxsess_check_count TAC_ARGS((char *user, struct author_data *data));
+
+
+#endif /* MAXSESS */
+
+#endif /* MAXSESS_H */
diff --git a/md4.c b/md4.c
index d99c84c..5ac377d 100644 (file)
--- a/md4.c
+++ b/md4.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
  */
 
 
+#include "tac_plus.h"
+
+#ifdef MSCHAP
+
 #include <string.h>
+
 #include "md4.h"
 /*
 #include "master.h"
 #include <ciscolib.h>
 */
 
+
 typedef unsigned char *POINTER;
 typedef unsigned short int UINT2;
 typedef unsigned long int UINT4;
 
-#define PROTO_LIST(list) ()
-#define const 
+static void MD4Transform TAC_ARGS((UINT4 state[4], const unsigned char block[64]));
+static void Encode TAC_ARGS((unsigned char *output, UINT4 *input, unsigned int len));
+static void Decode TAC_ARGS((UINT4 *output, const unsigned char *input, unsigned int len));
+
 
 /* Constants for MD4Transform routine.
  */
@@ -72,12 +80,6 @@ typedef unsigned long int UINT4;
 #define S33 11
 #define S34 15
 
-static void MD4Transform PROTO_LIST ((UINT4 [4], const unsigned char [64]));
-static void Encode PROTO_LIST
-  ((unsigned char *, UINT4 *, unsigned int));
-static void Decode PROTO_LIST
-  ((UINT4 *, const unsigned char *, unsigned int));
-
 static unsigned char PADDING[64] = {
   0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -111,6 +113,9 @@ static unsigned char PADDING[64] = {
 
 /* MD4 initialization. Begins an MD4 operation, writing a new context.
  */
+
+void MD4Init TAC_ARGS((MD4_CTX *context));
+
 void MD4Init (context)
 MD4_CTX *context;                                        /* context */
 {
@@ -128,6 +133,9 @@ MD4_CTX *context;                                        /* context */
      operation, processing another message block, and updating the
      context.
  */
+
+void MD4Update TAC_ARGS((MD4_CTX *context, const unsigned char *input, unsigned int inputLen));
+
 void MD4Update (context, input, inputLen)
 MD4_CTX *context;                                        /* context */
 const unsigned char *input;                                /* input block */
@@ -168,6 +176,9 @@ unsigned int inputLen;                     /* length of input block */
 /* MD4 finalization. Ends an MD4 message-digest operation, writing the
      the message digest and zeroizing the context.
  */
+
+void MD4Final TAC_ARGS((unsigned char digest[16], MD4_CTX *context));
+
 void MD4Final (digest, context)
 unsigned char digest[16];                         /* message digest */
 MD4_CTX *context;                                        /* context */
@@ -196,6 +207,9 @@ MD4_CTX *context;                                        /* context */
 
 /* MD4 basic transformation. Transforms state based on block.
  */
+
+static void MD4Transform TAC_ARGS((UINT4 state[4], const unsigned char block[64]));
+
 static void MD4Transform (state, block)
 UINT4 state[4];
 const unsigned char block[64];
@@ -271,6 +285,9 @@ const unsigned char block[64];
 /* Encodes input (UINT4) into output (unsigned char). Assumes len is
      a multiple of 4.
  */
+
+static void Encode TAC_ARGS((unsigned char *output, UINT4 *input, unsigned int len));
+
 static void Encode (output, input, len)
 unsigned char *output;
 UINT4 *input;
@@ -289,8 +306,10 @@ unsigned int len;
 /* Decodes input (unsigned char) into output (UINT4). Assumes len is
      a multiple of 4.
  */
-static void Decode (output, input, len)
 
+static void Decode TAC_ARGS((UINT4 *output, const unsigned char *input, unsigned int len));
+
+static void Decode (output, input, len)
 UINT4 *output;
 const unsigned char *input;
 unsigned int len;
@@ -301,3 +320,9 @@ unsigned int len;
     output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
       (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
 }
+
+#else /* MSCHAP */
+
+TAC_SOURCEFILE_EMPTY
+
+#endif /* MSCHAP */
diff --git a/md4.h b/md4.h
index d821229..38d0a81 100644 (file)
--- a/md4.h
+++ b/md4.h
@@ -1,4 +1,11 @@
-/* 
+#ifndef MD4_H
+#define MD4_H 1
+
+#include "tac_plus.h"
+
+#ifdef MSCHAP
+
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
@@ -42,8 +49,6 @@
    documentation and/or software.
  */
 
-#ifndef _MD4_H_
-#define _MD4_H_
 /* MD4 context. */
 typedef struct MD4Context {
   unsigned long int state[4];  /* state (ABCD) */
@@ -51,11 +56,12 @@ typedef struct MD4Context {
   unsigned char buffer[64];    /* input buffer */
 } MD4_CTX;
 
-void   MD4Init();
-void   MD4Update();
-void   MD4Final();
-char * MD4End();
-char * MD4File();
-char * MD4Data();
 
-#endif /* _MD4_H_ */
+extern void MD4Init TAC_ARGS((MD4_CTX *context));
+extern void MD4Update TAC_ARGS((MD4_CTX *context, const unsigned char *input, unsigned int inputLen));
+extern void MD4Final TAC_ARGS((unsigned char digest[16], MD4_CTX *context));
+
+
+#endif /* MSCHAP */
+
+#endif /* MD4_H */
diff --git a/md5.c b/md5.c
index 06225b0..32ca404 100644 (file)
--- a/md5.c
+++ b/md5.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
  * to contain all the information that RFC 1321's global.h contains.
  */
 
+
+#include "tac_plus.h"
+
 #include "md5.h"
 
+
+static void MD5Transform TAC_ARGS((UINT4 *state, unsigned char *block));
+static void Encode TAC_ARGS((unsigned char *output, UINT4 *input, unsigned int len));
+static void Decode TAC_ARGS((UINT4 *output, unsigned char *input, unsigned int len));
+
+
 /* Constants for MD5Transform routine.
  */
 
-
 #define S11 7
 #define S12 12
 #define S13 17
 #define S43 15
 #define S44 21
 
-static void MD5Transform PROTO_LIST((UINT4[4], unsigned char[64]));
-static void Encode PROTO_LIST
- ((unsigned char *, UINT4 *, unsigned int));
-static void Decode PROTO_LIST
- ((UINT4 *, unsigned char *, unsigned int));
-
-#if !defined(MD5_NEED_MEM_FUNCS)
-
-#define MD5_memcpy(out,in,len) memcpy(out, in, len)
-#define MD5_memset(ptr,val,len) memset(ptr, val, len)
-
-#else                          /* !defined(MD5_NEED_MEM_FUNCS) */
-
-static void MD5_memcpy PROTO_LIST((POINTER, POINTER, unsigned int));
-static void MD5_memset PROTO_LIST((POINTER, int, unsigned int));
-
-#endif                         /* !defined(MD5_NEED_MEM_FUNCS) */
-
 static unsigned char PADDING[64] = {
     0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -129,6 +119,8 @@ Rotation is separate from addition to prevent recomputation.
  (a) += (b); \
   }
 
+void MD5Init TAC_ARGS((MD5_CTX *context));
+
 /* MD5 initialization. Begins an MD5 operation, writing a new context.
  */
 void
@@ -143,6 +135,8 @@ MD5_CTX *context;           /* context */
     context->state[3] = 0x10325476;
 }
 
+void MD5Update TAC_ARGS((MD5_CTX *context, unsigned char *input, unsigned int inputLen));
+
 /* MD5 block update operation. Continues an MD5 message-digest
    operation, processing another message block, and updating the
    context.
@@ -168,8 +162,7 @@ unsigned int inputLen;              /* length of input block */
 
     /* Transform as many times as possible. */
     if (inputLen >= partLen) {
-       MD5_memcpy
-           ((POINTER) & context->buffer[index], (POINTER) input, partLen);
+       memcpy((POINTER) & context->buffer[index], (POINTER) input, partLen);
        MD5Transform(context->state, context->buffer);
 
        for (i = partLen; i + 63 < inputLen; i += 64)
@@ -180,11 +173,12 @@ unsigned int inputLen;            /* length of input block */
        i = 0;
 
     /* Buffer remaining input */
-    MD5_memcpy
-       ((POINTER) & context->buffer[index], (POINTER) & input[i],
-        inputLen - i);
+    memcpy((POINTER) & context->buffer[index], (POINTER) & input[i],
+       inputLen - i);
 }
 
+void MD5Final TAC_ARGS((unsigned char *digest, MD5_CTX *context));
+
 /* MD5 finalization. Ends an MD5 message-digest operation, writing the
    the message digest and zeroizing the context.
    */
@@ -211,9 +205,11 @@ MD5_CTX *context;          /* context */
     Encode(digest, context->state, 16);
 
     /* Zeroize sensitive information. */
-    MD5_memset((POINTER) context, 0, sizeof(*context));
+    memset((POINTER) context, 0, sizeof(*context));
 }
 
+static void MD5Transform TAC_ARGS((UINT4 *state, unsigned char *block));
+
 /* MD5 basic transformation. Transforms state based on block.
  */
 static void
@@ -303,9 +299,11 @@ unsigned char block[64];
     state[3] += d;
 
     /* Zeroize sensitive information. */
-    MD5_memset((POINTER) x, 0, sizeof(x));
+    memset((POINTER) x, 0, sizeof(x));
 }
 
+static void Encode TAC_ARGS((unsigned char *output, UINT4 *input, unsigned int len));
+
 /* Encodes input (UINT4) into output (unsigned char). Assumes len is
    a multiple of 4.
    */
@@ -325,6 +323,8 @@ unsigned int len;
     }
 }
 
+static void Decode TAC_ARGS((UINT4 *output, unsigned char *input, unsigned int len));
+
 /* Decodes input (unsigned char) into output (UINT4). Assumes len is
    a multiple of 4.
    */
@@ -340,36 +340,3 @@ unsigned int len;
        output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) |
            (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24);
 }
-
-#if defined(MD5_NEED_MEM_FUNC)
-
-/* 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;
-}
-
-#endif                         /* defined(MD5_NEED_MEM_FUNC) */
diff --git a/md5.h b/md5.h
index 097156e..90f9021 100644 (file)
--- a/md5.h
+++ b/md5.h
@@ -1,4 +1,9 @@
-/* 
+#ifndef MD5_H
+#define MD5_H 1
+
+#include "tac_plus.h"
+
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
@@ -44,8 +49,6 @@
  * documentation and/or software.
  */
 
-#ifndef _MD5_H
-#define _MD5_H
 
 /* delineate the cisco changes to the RSA supplied module */
 #define CISCO_MD5_MODS
 #if defined(CISCO_MD5_MODS)
 
 /* typedef a 32-bit type */
-typedef unsigned long int UINT4;
+typedef tac_uint32 UINT4;
 
 /* typedef a generic pointer type */
 typedef unsigned char *POINTER;
 
-/* enable prototyping */
-/* #define PROTO_LIST(x) x */
-/* disable prototyping */
-#define PROTO_LIST(x) ()
-
 #endif /* defined(CISCO_MD5_MODS) */
 
 /* MD5 context. */
@@ -72,10 +70,10 @@ typedef struct {
   unsigned char buffer[64];                         /* input buffer */
 } MD5_CTX;
 
-void MD5Init PROTO_LIST ((MD5_CTX *));
-void MD5Update PROTO_LIST
-  ((MD5_CTX *, unsigned char *, unsigned int));
-void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
+
+extern void MD5Init TAC_ARGS((MD5_CTX *context));
+extern void MD5Update TAC_ARGS((MD5_CTX *context, unsigned char *input, unsigned int inputLen));
+extern void MD5Final TAC_ARGS((unsigned char *digest, MD5_CTX *context));
 
 
-#endif                          /* _MD5_H */
+#endif /* MD5_H */
index 192d9d2..d98b84b 100644 (file)
--- a/mschap.h
+++ b/mschap.h
@@ -1,4 +1,9 @@
-/* 
+#ifndef MSCHAP_H
+#define MSCHAP_H 1
+
+#include "tac_plus.h"
+
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
@@ -17,4 +22,8 @@
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #define MSCHAP_KEY "Contact Microsoft for the MSCHAP key"
+
+
+#endif /* MSCHAP_H */
index f3f7023..30f5a2c 100644 (file)
--- a/packet.c
+++ b/packet.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
 
+#include <stdlib.h>
+#include <netinet/in.h>                /* for ntohl() */
+#include <errno.h>
+#include <time.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "packet.h"
+#include "utils.h"
+#include "report.h"
+#include "dump.h"
+#include "cfgfile.h"
+#include "encrypt.h"
+#include "main.h"
+#include "do_author.h"
+
+
+static int write_packet TAC_ARGS((u_char *pak));
+
+
+/* Configurable:
+ */
+
+#define TAC_PLUS_READ_TIMEOUT          180     /* seconds */
+#define TAC_PLUS_WRITE_TIMEOUT         180     /* seconds */
+
+
 /* Everything to do with reading and writing packets */
 
+void send_acct_reply TAC_ARGS((unsigned status, const char *msg, const char *data));
+
 /* send an accounting response packet */
+void
 send_acct_reply(status, msg, data)
-    u_char status;
-    char *msg, *data;
+unsigned status;                       /* promoted "u_char" type */
+const char *msg;
+const char *data;
 {
     u_char *pak, *p;
     HDR *hdr;
@@ -73,13 +110,16 @@ send_acct_reply(status, msg, data)
     free(pak);
 }
 
+void send_author_reply TAC_ARGS((unsigned status, const char *msg, const char *data, int arg_cnt, /* const */ char **args));
+
 /* send an authorization reply packet */
+void
 send_author_reply(status, msg, data, arg_cnt, args)
-u_char status;
-char *msg;
-char *data;
+unsigned status;                       /* promoted "u_char" type */
+const char *msg;
+const char *data;
 int arg_cnt;
-char **args;
+/* const */ char **args;
 {
     u_char *pak, *p;
     HDR *hdr;
@@ -145,9 +185,9 @@ char **args;
     if (debug & DEBUG_PACKET_FLAG) {
        report(LOG_DEBUG, "Writing %s size=%d",
               summarise_outgoing_packet_type(pak), len);
-       dump_tacacs_pak(pak); 
+       dump_tacacs_pak(pak);
     }
-    
+
     reply->msg_len  = htons(reply->msg_len);
     reply->data_len = htons(reply->data_len);
 
@@ -159,8 +199,11 @@ char **args;
 /* Send an authentication reply packet indicating an error has
    occurred. msg is a null terminated character string */
 
+void send_authen_error TAC_ARGS((const char *msg));
+
+void
 send_authen_error(msg)
-char *msg;
+const char *msg;
 {
     char buf[255];
 
@@ -176,13 +219,16 @@ char *msg;
 
 /* create and send an authentication reply packet from tacacs+ to a NAS */
 
+void send_authen_reply TAC_ARGS((int status, const char *msg, unsigned msg_len, const unsigned char *data, unsigned data_len, unsigned flags));
+
+void
 send_authen_reply(status, msg, msg_len, data, data_len, flags)
 int status;
-char *msg;
-u_short msg_len;
-char *data;
-u_short data_len;
-u_char flags;
+const char *msg;
+unsigned msg_len;                      /* promoted "u_short" type */
+const unsigned char *data;
+unsigned data_len;                     /* promoted "u_short" type */
+unsigned flags;                                /* promoted "u_char" type */
 {
     u_char *pak, *p;
     HDR *hdr;
@@ -228,12 +274,14 @@ u_char flags;
 }
 
 
+u_char *get_authen_continue TAC_ARGS((void));
+
 /* read an authentication GETDATA packet from a NAS. Return 0 on failure */
 u_char *
 get_authen_continue()
 {
     HDR *hdr;
-    u_char *pak, *read_packet();
+    u_char *pak;
     struct authen_cont *cont;
     char msg[255];
 
@@ -255,10 +303,10 @@ get_authen_continue()
     cont->user_msg_len  = ntohs(cont->user_msg_len);
     cont->user_data_len = ntohs(cont->user_data_len);
 
-    if (TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE + 
-       cont->user_msg_len + 
-       cont->user_data_len !=
-       ntohl(hdr->datalength)) {
+    if ((unsigned long)(TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE +
+       cont->user_msg_len +
+       cont->user_data_len) !=
+       (unsigned long) ntohl(hdr->datalength)) {
        char *m = "Illegally sized authentication cont packet";
        report(LOG_ERR, "%s: %s", session.peer, m);
        send_authen_error(m);
@@ -278,7 +326,9 @@ get_authen_continue()
  * Return -1 on error, eof or timeout. Otherwise return number of
  * bytes read. */
 
-int
+static int sockread TAC_ARGS((int fd, u_char *ptr, int nbytes, int timeout));
+
+static int
 sockread(fd, ptr, nbytes, timeout)
 int fd;
 u_char *ptr;
@@ -301,7 +351,7 @@ int timeout;
     nleft = nbytes;
 
     while (nleft > 0) {
-       int status = select(fd + 1, &readfds, (fd_set *) NULL, 
+       int status = select(fd + 1, &readfds, (fd_set *) NULL,
                            &exceptfds, &tout);
 
        if (status == 0) {
@@ -311,7 +361,7 @@ int timeout;
        if (status < 0) {
            if (errno == EINTR)
                continue;
-           report(LOG_DEBUG, "%s: error in select %s fd %d", 
+           report(LOG_DEBUG, "%s: error in select %s fd %d",
                   session.peer, sys_errlist[errno], fd);
            return (-1);
        }
@@ -331,17 +381,17 @@ int timeout;
        if (nread < 0) {
            if (errno == EINTR)
                goto again;
-           report(LOG_DEBUG, "%s %s: error reading fd %d nread=%d %s", 
+           report(LOG_DEBUG, "%s %s: error reading fd %d nread=%d %s",
                   session.peer, session.port, fd, nread, sys_errlist[errno]);
            return (-1);        /* error */
 
        } else if (nread == 0) {
-           report(LOG_DEBUG, "%s %s: fd %d eof (connection closed)", 
+           report(LOG_DEBUG, "%s %s: fd %d eof (connection closed)",
                   session.peer, session.port, fd);
            return (-1);        /* eof */
        }
        nleft -= nread;
-       if (nleft) 
+       if (nleft)
            ptr += nread;
     }
     return (nbytes - nleft);
@@ -354,7 +404,9 @@ int timeout;
  * Return -1 on error, eof or timeout. Otherwise return number of
  * bytes written. */
 
-int
+static int sockwrite TAC_ARGS((int fd, u_char *ptr, int bytes, int timeout));
+
+static int
 sockwrite(fd, ptr, bytes, timeout)
 int fd;
 u_char *ptr;
@@ -379,16 +431,16 @@ int timeout;
     remaining = bytes;
 
     while (remaining > 0) {
-       int status = select(fd + 1, (fd_set *) NULL, 
+       int status = select(fd + 1, (fd_set *) NULL,
                            &writefds, &exceptfds, &tout);
 
        if (status == 0) {
-           report(LOG_DEBUG, "%s: timeout writing to fd %d", 
+           report(LOG_DEBUG, "%s: timeout writing to fd %d",
                   session.peer, fd);
            return (-1);
        }
        if (status < 0) {
-           report(LOG_DEBUG, "%s: error in select fd %d", 
+           report(LOG_DEBUG, "%s: error in select fd %d",
                   session.peer, fd);
            return (-1);
        }
@@ -406,7 +458,7 @@ int timeout;
        sent = write(fd, ptr, remaining);
 
        if (sent <= 0) {
-           report(LOG_DEBUG, "%s: error writing fd %d sent=%d", 
+           report(LOG_DEBUG, "%s: error writing fd %d sent=%d",
                   session.peer, fd, sent);
            return (sent);      /* error */
        }
@@ -416,16 +468,32 @@ int timeout;
     return (bytes - remaining);
 }
 
+static const char *get_session_key TAC_ARGS((void));
+
+static const char *
+get_session_key()
+{
+    const char *retval = NULL;
+
+    if ((retval = cfg_get_host_key(session.peer_addr)))
+       return (retval);
+    if (session.peer_addr != session.peer
+     && (retval = cfg_get_host_key(session.peer     )))
+       return (retval);
+    return (session.key);
+}
+
 /* read a packet from the wire, and decrypt it. Increment the global
  seq_no return NULL on failure */
 
+u_char *read_packet TAC_ARGS((void));
+
 u_char *
 read_packet()
 {
     HDR hdr;
     u_char *pkt, *data;
     int len;
-    char *tkey;
 
     if (debug & DEBUG_PACKET_FLAG)
        report(LOG_DEBUG, "Waiting for packet");
@@ -433,13 +501,13 @@ read_packet()
     /* read a packet header */
     len = sockread(session.sock, (u_char *) & hdr, TAC_PLUS_HDR_SIZE, TAC_PLUS_READ_TIMEOUT);
     if (len != TAC_PLUS_HDR_SIZE) {
-       report(LOG_DEBUG, "Read %d bytes from %s %s, expecting %d", 
+       report(LOG_DEBUG, "Read %d bytes from %s %s, expecting %d",
               len, session.peer, session.port, TAC_PLUS_HDR_SIZE);
        return(NULL);
     }
 
     if ((hdr.version & TAC_PLUS_MAJOR_VER_MASK) != TAC_PLUS_MAJOR_VER) {
-       report(LOG_ERR, 
+       report(LOG_ERR,
               "%s: Illegal major version specified: found %d wanted %d\n",
               session.peer, hdr.version, TAC_PLUS_MAJOR_VER);
        return(NULL);
@@ -451,7 +519,7 @@ read_packet()
        len < TAC_PLUS_HDR_SIZE || len > 0x10000) {
        report(LOG_ERR,
               "%s: Illegal data size: %lu\n",
-              session.peer, ntohl(hdr.datalength));
+              session.peer, (unsigned long) ntohl(hdr.datalength));
        return(NULL);
     }
     pkt = (u_char *) tac_malloc(len);
@@ -463,9 +531,9 @@ read_packet()
     data = pkt + TAC_PLUS_HDR_SIZE;
 
     /* read the rest of the packet data */
-    if (sockread(session.sock, data, ntohl(hdr.datalength), 
+    if ((unsigned long)sockread(session.sock, data, ntohl(hdr.datalength),
                 TAC_PLUS_READ_TIMEOUT) !=
-       ntohl(hdr.datalength)) {
+       (unsigned long) ntohl(hdr.datalength)) {
        report(LOG_ERR, "%s: start_session: bad socket read", session.peer);
        return (NULL);
     }
@@ -479,11 +547,11 @@ read_packet()
        return (NULL);
     }
 
-    /* decrypt the data portion */
-    if ( !(tkey=(char *)cfg_get_host_key(session.peer)) )
-               tkey = session.key;     
+    /* Now we are starting our new 'request' cycle */
+    cfg_request_scan_begin();
 
-    if (md5_xor((HDR *)pkt, data, tkey)) {
+    /* decrypt the data portion */
+    if (md5_xor((HDR *)pkt, data, get_session_key())) {
        report(LOG_ERR, "%s: start_session error decrypting data",
               session.peer);
        return (NULL);
@@ -498,14 +566,16 @@ read_packet()
     return (pkt);
 }
 
+static int write_packet TAC_ARGS((u_char *pak));
+
 /* write a packet to the wire, encrypting it */
+static int
 write_packet(pak)
 u_char *pak;
 {
     HDR *hdr = (HDR *) pak;
     u_char *data;
     int len;
-    char *tkey;
 
     len = TAC_PLUS_HDR_SIZE + ntohl(hdr->datalength);
 
@@ -513,10 +583,7 @@ u_char *pak;
     data = pak + TAC_PLUS_HDR_SIZE;
 
     /* encrypt the data portion */
-   if ( !(tkey=(char *)cfg_get_host_key(session.peer)) )
-                tkey = session.key;
-
-   if (md5_xor((HDR *)pak, data, tkey)) {
+    if (md5_xor((HDR *)pak, data, get_session_key())) {
        report(LOG_ERR, "%s: write_packet: error encrypting data", session.peer);
        return (-1);
     }
@@ -528,6 +595,9 @@ u_char *pak;
     return (0);
 }
 
+void send_error_reply TAC_ARGS((int type, char *msg));
+
+void
 send_error_reply(type, msg)
 int type;
 char *msg;
diff --git a/packet.h b/packet.h
new file mode 100644 (file)
index 0000000..83a4d9c
--- /dev/null
+++ b/packet.h
@@ -0,0 +1,217 @@
+#ifndef PACKET_H
+#define PACKET_H 1
+
+#include "tac_plus.h"
+
+#include <sys/types.h>         /* for u_* */
+
+
+/* All tacacs+ packets have the same header format */
+
+struct tac_plus_pak_hdr {
+    u_char version;
+
+#define TAC_PLUS_MAJOR_VER_MASK 0xf0
+#define TAC_PLUS_MAJOR_VER      0xc0
+
+#define TAC_PLUS_MINOR_VER_0    0x0
+#define TAC_PLUS_VER_0  (TAC_PLUS_MAJOR_VER | TAC_PLUS_MINOR_VER_0)
+
+#define TAC_PLUS_MINOR_VER_1    0x01
+#define TAC_PLUS_VER_1  (TAC_PLUS_MAJOR_VER | TAC_PLUS_MINOR_VER_1)
+
+    u_char type;
+
+#define TAC_PLUS_AUTHEN                        1
+#define TAC_PLUS_AUTHOR                        2
+#define TAC_PLUS_ACCT                  3
+
+    u_char seq_no;             /* packet sequence number */
+    u_char encryption;         /* packet is encrypted or cleartext */
+
+#define TAC_PLUS_ENCRYPTED 0x0         /* packet is encrypted */
+#define TAC_PLUS_CLEAR     0x1         /* packet is not encrypted */
+
+    int session_id;            /* session identifier FIXME: Is this needed? */
+    int datalength;            /* length of encrypted data following this
+                                * header */
+    /* datalength bytes of encrypted data */
+};
+
+#define TAC_PLUS_HDR_SIZE 12
+
+typedef struct tac_plus_pak_hdr HDR;
+
+/* Authentication packet NAS sends to us */
+
+struct authen_start {
+    u_char action;
+
+#define TAC_PLUS_AUTHEN_LOGIN    0x1
+#define TAC_PLUS_AUTHEN_CHPASS   0x2
+#define TAC_PLUS_AUTHEN_SENDPASS 0x3 /* deprecated */
+#define TAC_PLUS_AUTHEN_SENDAUTH 0x4
+
+    u_char priv_lvl;
+
+#define TAC_PLUS_PRIV_LVL_MIN 0x0
+#define TAC_PLUS_PRIV_LVL_MAX 0xf
+
+    u_char authen_type;
+
+#define TAC_PLUS_AUTHEN_TYPE_ASCII  1
+#define TAC_PLUS_AUTHEN_TYPE_PAP    2
+#define TAC_PLUS_AUTHEN_TYPE_CHAP   3
+#define TAC_PLUS_AUTHEN_TYPE_ARAP   4
+#ifdef MSCHAP
+#define TAC_PLUS_AUTHEN_TYPE_MSCHAP 5
+#endif /* MSCHAP */
+
+    u_char service;
+
+#define TAC_PLUS_AUTHEN_SVC_LOGIN  1
+#define TAC_PLUS_AUTHEN_SVC_ENABLE 2
+#define TAC_PLUS_AUTHEN_SVC_PPP    3
+#define TAC_PLUS_AUTHEN_SVC_ARAP   4
+#define TAC_PLUS_AUTHEN_SVC_PT     5
+#define TAC_PLUS_AUTHEN_SVC_RCMD   6
+#define TAC_PLUS_AUTHEN_SVC_X25    7
+#define TAC_PLUS_AUTHEN_SVC_NASI   8
+
+    u_char user_len;
+    u_char port_len;
+    u_char rem_addr_len;
+    u_char data_len;
+    /* <user_len bytes of char data> */
+    /* <port_len bytes of char data> */
+    /* <rem_addr_len bytes of u_char data> */
+    /* <data_len bytes of u_char data> */
+};
+
+#define TAC_AUTHEN_START_FIXED_FIELDS_SIZE 8
+
+/* Authentication continue packet NAS sends to us */
+struct authen_cont {
+    u_short user_msg_len;
+    u_short user_data_len;
+    u_char flags;
+
+#define TAC_PLUS_CONTINUE_FLAG_ABORT 0x1
+
+    /* <user_msg_len bytes of u_char data> */
+    /* <user_data_len bytes of u_char data> */
+};
+
+#define TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE 5
+
+/* Authentication reply packet we send to NAS */
+struct authen_reply {
+    u_char status;
+
+#define TAC_PLUS_AUTHEN_STATUS_PASS     1
+#define TAC_PLUS_AUTHEN_STATUS_FAIL     2
+#define TAC_PLUS_AUTHEN_STATUS_GETDATA  3
+#define TAC_PLUS_AUTHEN_STATUS_GETUSER  4
+#define TAC_PLUS_AUTHEN_STATUS_GETPASS  5
+#define TAC_PLUS_AUTHEN_STATUS_RESTART  6
+#define TAC_PLUS_AUTHEN_STATUS_ERROR    7
+#define TAC_PLUS_AUTHEN_STATUS_FOLLOW   0x21
+
+    u_char flags;
+
+#define TAC_PLUS_AUTHEN_FLAG_NOECHO     0x1
+
+    u_short msg_len;
+    u_short data_len;
+
+    /* <msg_len bytes of char data> */
+    /* <data_len bytes of u_char data> */
+};
+
+#define TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE 6
+
+/* An authorization request packet */
+struct author {
+    u_char authen_method;
+    u_char priv_lvl;
+    u_char authen_type;
+    u_char service;
+
+    u_char user_len;
+    u_char port_len;
+    u_char rem_addr_len;
+    u_char arg_cnt;            /* the number of args */
+
+    /* <arg_cnt u_chars containing the lengths of args 1 to arg n> */
+    /* <user_len bytes of char data> */
+    /* <port_len bytes of char data> */
+    /* <rem_addr_len bytes of u_char data> */
+    /* <char data for each arg> */
+};
+
+#define TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE 8
+
+/* An authorization reply packet */
+struct author_reply {
+    u_char status;
+    u_char arg_cnt;
+    u_short msg_len;
+    u_short data_len;
+
+    /* <arg_cnt u_chars containing the lengths of arg 1 to arg n> */
+    /* <msg_len bytes of char data> */
+    /* <data_len bytes of char data> */
+    /* <char data for each arg> */
+};
+
+#define TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE 6
+
+struct acct {
+    u_char flags;
+
+#define TAC_PLUS_ACCT_FLAG_MORE     0x1
+#define TAC_PLUS_ACCT_FLAG_START    0x2
+#define TAC_PLUS_ACCT_FLAG_STOP     0x4
+#define TAC_PLUS_ACCT_FLAG_WATCHDOG 0x8
+
+    u_char authen_method;
+    u_char priv_lvl;
+    u_char authen_type;
+    u_char authen_service;
+    u_char user_len;
+    u_char port_len;
+    u_char rem_addr_len;
+    u_char arg_cnt; /* the number of cmd args */
+    /* one u_char containing size for each arg */
+    /* <user_len bytes of char data> */
+    /* <port_len bytes of char data> */
+    /* <rem_addr_len bytes of u_char data> */
+    /* char data for args 1 ... n */
+};
+
+#define TAC_ACCT_REQ_FIXED_FIELDS_SIZE 9
+
+struct acct_reply {
+    u_short msg_len;
+    u_short data_len;
+    u_char status;
+
+#define TAC_PLUS_ACCT_STATUS_SUCCESS 0x1
+#define TAC_PLUS_ACCT_STATUS_ERROR   0x2
+#define TAC_PLUS_ACCT_STATUS_FOLLOW  0x21
+
+};
+
+#define TAC_ACCT_REPLY_FIXED_FIELDS_SIZE 5
+
+
+extern void send_acct_reply TAC_ARGS((unsigned status, const char *msg, const char *data));
+extern void send_author_reply TAC_ARGS((unsigned status, const char *msg, const char *data, int arg_cnt, /* const */ char **args));
+extern void send_authen_error TAC_ARGS((const char *msg));
+extern void send_authen_reply TAC_ARGS((int status, const char *msg, unsigned msg_len, const unsigned char *data, unsigned data_len, unsigned flags));
+extern u_char *get_authen_continue TAC_ARGS((void));
+extern u_char *read_packet TAC_ARGS((void));
+extern void send_error_reply TAC_ARGS((int type, char *msg));
+
+
+#endif /* PACKET_H */
diff --git a/parse.c b/parse.c
index 6ac6908..b9f3360 100644 (file)
--- a/parse.c
+++ b/parse.c
 
 /* Keywords of the configuration language */
 
+
 #include "tac_plus.h"
 
+#include "parse.h"
+#include "utils.h"
+#include "report.h"
+#include "hash.h"
+
+
 static void *wordtable[HASH_TAB_SIZE]; /* Table of keyword declarations */
 
 struct keyword {
@@ -31,6 +38,8 @@ struct keyword {
 
 typedef struct keyword KEYWORD;
 
+static void declare TAC_ARGS((char *name, int value));
+
 static void
 declare(name, value)
     char *name;
@@ -53,7 +62,9 @@ declare(name, value)
 
 /* Declare keywords of the "configuration language". */
 
-void 
+void parser_init TAC_ARGS((void));
+
+void
 parser_init()
 {
     bzero(wordtable, sizeof(wordtable));
@@ -85,7 +96,6 @@ parser_init()
     declare("group", S_group);
     declare("global", S_global);
     declare("host", S_host);
-    declare("type", S_type);
     declare("ip", S_ip);
     declare("ipx", S_ipx);
     declare("key", S_key);
@@ -115,12 +125,23 @@ parser_init()
     declare("service", S_svc);
     declare("user", S_user);
     declare("time", S_time);
+    declare("and", S_and);
+    declare("closeparen", S_closeparen);
+    declare("enlist", S_enlist);
+    declare("first", S_first);
+    declare("not", S_not);
+    declare("openparen", S_openparen);
+    declare("or", S_or);
+    declare("recursive", S_recursive);
+    declare("when", S_when);
 }
 
+int keycode TAC_ARGS((const char *keyword));
+
 /* Return a keyword code if a keyword is recognized. 0 otherwise */
 int
 keycode(keyword)
-char *keyword;
+const char *keyword;
 {
     KEYWORD *k = hash_lookup(wordtable, keyword);
 
@@ -129,7 +150,9 @@ char *keyword;
     return (S_unknown);
 }
 
-char *
+const char *codestring TAC_ARGS((int type));
+
+const char *
 codestring(type)
 int type;
 {
@@ -156,8 +179,6 @@ int type;
        return ("group");
     case S_host:
        return ("host");
-    case S_type:
-       return ("type");
     case S_file:
        return ("file");
     case S_skey:
@@ -205,7 +226,7 @@ int type;
 #ifdef USE_PAM
     case S_pam:
        return ("pam");
-#endif /*USE_PAM */    
+#endif /*USE_PAM */
     case S_nopasswd:
        return("nopassword");
     case S_des:
@@ -250,5 +271,23 @@ int type;
        return("lcp");
     case S_time:
        return("time");
+    case S_and:
+       return("and");
+    case S_closeparen:
+       return(")");
+    case S_enlist:
+       return("enlist");
+    case S_first:
+       return("first");
+    case S_not:
+       return("not");
+    case S_openparen:
+       return("(");
+    case S_or:
+       return("or");
+    case S_recursive:
+       return("recursive");
+    case S_when:
+       return("when");
     }
 }
diff --git a/parse.h b/parse.h
index e5be7f7..34d72ee 100644 (file)
--- a/parse.h
+++ b/parse.h
@@ -1,4 +1,9 @@
-/* 
+#ifndef PARSE_H
+#define PARSE_H 1
+
+#include "tac_plus.h"
+
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
@@ -17,8 +22,6 @@
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
-/* Dummy password, if nopasswd is specified */
-extern char *nopasswd_str;
 
 /* Keywords & values */
 
@@ -82,9 +85,24 @@ extern char *nopasswd_str;
 #define S_db             44
 #define S_db_accounting          45
 #endif  /*DB*/
-#define S_type           46
 #ifdef USE_LDAP
 #define S_ldap            47
 #endif /* LDAP */
 #define S_time           48
+#define S_and            49
+#define S_closeparen     50
+#define S_enlist         51
+#define S_first                  52
+#define S_not            53
+#define S_openparen      54
+#define S_or             55
+#define S_recursive      56
+#define S_when           57
+
+
+extern void parser_init TAC_ARGS((void));
+extern int keycode TAC_ARGS((const char *keyword));
+extern const char *codestring TAC_ARGS((int type));
+
 
+#endif /* PARSE_H */
index bce0178..ac42b23 100644 (file)
 
 /* Routines to fork children and communicate with them via pipes */
 
+
 #include "tac_plus.h"
-#include "sys/wait.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
-#include "signal.h"
+#endif
+#include <signal.h>
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+#ifdef HAVE_SYS_SYSLOG_H
+#include <sys/syslog.h>
+#endif
+
+#include "programs.h"
+#include "utils.h"
+#include "report.h"
+#include "do_author.h"                 /* for "struct author_data" */
+#include "main.h"
+
 
 /* Support for dollar variables.  Look in the authorization data and
 return strings representing values found there.  If not found, return
@@ -38,6 +57,8 @@ type    -- (1 to 4)
 service -- (1 to 7)
 status  -- (pass, fail, error, unknown) */
 
+static char *lookup TAC_ARGS((char *sym, struct author_data *data));
+
 static char *
 lookup(sym, data)
 char *sym;
@@ -96,12 +117,14 @@ struct author_data *data;
    values for the various $ variables by looking in the authorization
    data */
 
+static char *substitute TAC_ARGS((const char *string, struct author_data *data));
+
 static char *
 substitute(string, data)
-char *string;
+const char *string;
 struct author_data *data;
 {
-    char *cp;
+    const char *cp;
     char out[MAX_INPUT_LINE_LEN], *outp;
     char sym[MAX_INPUT_LINE_LEN], *symp;
     char *value, *valuep;
@@ -129,7 +152,7 @@ struct author_data *data;
 
        } else {
            /* copy symbol into sym */
-           while (*cp && isalpha(*cp))
+           while (*cp && isalpha((int) *cp))
                *symp++ = *cp++;
        }
 
@@ -160,6 +183,8 @@ struct author_data *data;
 /* Wait for a (child) pid to terminate. Return its status. Probably
    horribly implementation dependent. */
 
+static int waitfor TAC_ARGS((int pid));
+
 static int
 waitfor(pid)
 int pid;
@@ -189,6 +214,8 @@ int pid;
     return (WEXITSTATUS(status));
 }
 
+static int write_args TAC_ARGS((int fd, char **args, int arg_cnt));
+
 /* Write an argv array of strings to fd, adding a newline to each one */
 static int
 write_args(fd, args, arg_cnt)
@@ -211,6 +238,8 @@ char **args;
     return (0);
 }
 
+static void close_fds TAC_ARGS((int fd1, int fd2, int fd3));
+
 /* Close the three given file-descruptors */
 static void
 close_fds(fd1, fd2, fd3)
@@ -230,6 +259,8 @@ close_fds(fd1, fd2, fd3)
 /* Fork a command. Return read and write file descriptors in readfdp
    and writefdp. Return the pid or -1 if unsuccessful */
 
+static int my_popen TAC_ARGS((char *cmd, int *readfdp, int *writefdp, int *errorfdp));
+
 static int
 my_popen(cmd, readfdp, writefdp, errorfdp)
 char *cmd;
@@ -240,7 +271,7 @@ int *readfdp, *writefdp, *errorfdp;
 
     fd1[0] = fd1[1] = fd2[0] = fd2[1] = fd3[0] = fd3[1] = -1;
     *readfdp = *writefdp = *errorfdp = -1;
-    
+
     if (pipe(fd1) < 0 || pipe(fd2) < 0 || pipe(fd3) < 0) {
        report(LOG_ERR, "%s: Cannot create pipes", session.peer);
        close_fds(fd1[0], fd2[0], fd3[0]);
@@ -297,6 +328,8 @@ int *readfdp, *writefdp, *errorfdp;
     return(0); /* keep Codecenter quiet */
 }
 
+static int read_string TAC_ARGS((int fd, char *string, int len));
+
 /* read the file descriptor and stuff the data into the given array for
  * the number of bytes given. Throw the rest away.
  */
@@ -305,9 +338,9 @@ read_string (fd, string, len)
 int fd, len;
 char *string;
 {
-    uint i, ret;
+    int i, ret;
     char c;
-    
+
     i=0;
     do {
        ret = read(fd, &c, 1);
@@ -324,6 +357,8 @@ char *string;
    the count of lines seen so far. When eof is read, the array is
    allocated, and the recursion unravels */
 
+static char **read_args TAC_ARGS((int n, int fd));
+
 static char **
 read_args(n, fd)
 int n, fd;
@@ -356,12 +391,16 @@ int n, fd;
    standard input and read its standard output into outarray. Return
    the commands final status when it terminates */
 
+int call_pre_process TAC_ARGS((const char *string, struct author_data *data, char ***outargsp, int *outargs_cntp, char *error, int err_len));
+
 int
 call_pre_process(string, data, outargsp, outargs_cntp, error, err_len)
-char *string, *error;
+const char *string;
 struct author_data *data;
 char ***outargsp;
-int *outargs_cntp, err_len;
+int *outargs_cntp;
+char *error;
+int err_len;
 {
     char **new_args;
     int readfd, writefd, errorfd;
@@ -370,7 +409,7 @@ int *outargs_cntp, err_len;
     int pid = my_popen(cmd, &readfd, &writefd, &errorfd);
 
     memset(error, '\0', err_len);
-    
+
     free(cmd);
 
     if (pid < 0) {
@@ -402,10 +441,10 @@ int *outargs_cntp, err_len;
 
     read_string(errorfd, error, err_len);
     if (error[0] != '\0') {
-       report(LOG_ERR, "Error from program (%d): \"%s\" ",
-              strlen(error), error);
+       report(LOG_ERR, "Error from program (%u): \"%s\" ",
+              (unsigned) strlen(error), error);
     }
-       
+
     /* count the args */
     for (i = 0; new_args[i]; i++)
         /* NULL stmt */ ;
@@ -422,9 +461,11 @@ int *outargs_cntp, err_len;
    standard input and read its standard output into outarray. Return
    the commands final status when it terminates */
 
+int call_post_process TAC_ARGS((const char *string, struct author_data *data, char ***outargsp, int *outargs_cntp));
+
 int
 call_post_process(string, data, outargsp, outargs_cntp)
-char *string;
+const char *string;
 struct author_data *data;
 char ***outargsp;
 int *outargs_cntp;
diff --git a/programs.h b/programs.h
new file mode 100644 (file)
index 0000000..31ebef3
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef PROGRAMS_H
+#define PROGRAMS_H 1
+
+#include "tac_plus.h"
+
+
+struct author_data;
+
+extern int call_pre_process TAC_ARGS((const char *string, struct author_data *data, char ***outargsp, int *outargs_cntp, char *error, int err_len));
+extern int call_post_process TAC_ARGS((const char *string, struct author_data *data, char ***outargsp, int *outargs_cntp));
+
+
+#endif /* PROGRAMS_H */
diff --git a/pw.c b/pw.c
index 96c761e..a749262 100644 (file)
--- a/pw.c
+++ b/pw.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
 /* Tacacs+ password lookup routine for those systems which don't have
    setpwfile. Not for use on /etc/passwd files */
 
+
 #include "tac_plus.h"
+
+#include <stdlib.h>
 #include <pwd.h>
 #include <string.h>
 
+#include "pw.h"
+#include "report.h"
+#include "main.h"
+
+
 static struct passwd pw_passwd;
 
+struct passwd *tac_passwd_lookup TAC_ARGS((const char *name, const char *file));
+
 struct passwd *
 tac_passwd_lookup(name, file)
-    char *name, *file;
+const char *name;
+const char *file;
 {
     FILE *passwd_fp = NULL;
 
@@ -44,10 +55,10 @@ tac_passwd_lookup(name, file)
 
     if (passwd_fp) {
        if (debug & DEBUG_PASSWD_FLAG)
-           report(LOG_DEBUG, "tac_passwd_lookup: open %s %d", 
+           report(LOG_DEBUG, "tac_passwd_lookup: open %s %d",
                   file, fileno(passwd_fp));
     } else {
-       report(LOG_ERR, "tac_passwd_lookup: cannot open file %s for reading", 
+       report(LOG_ERR, "tac_passwd_lookup: cannot open file %s for reading",
               file);
        return(NULL);
     }
@@ -113,16 +124,18 @@ tac_passwd_lookup(name, file)
 
         pw_passwd.pw_name    = uname;
         pw_passwd.pw_passwd  = password;
-#ifndef NO_PWAGE
+#ifdef HAVE_PASSWD_PW_AGE
         pw_passwd.pw_age     = NULL;
+#endif
+#ifdef HAVE_PASSWD_PW_COMMENT
         pw_passwd.pw_comment = NULL;
-#endif /* NO_PWAGE */
+#endif
         pw_passwd.pw_gecos   = gecos;
         pw_passwd.pw_dir     = homedir;
         pw_passwd.pw_shell   = shell;
 
        if (debug & DEBUG_PASSWD_FLAG)
-           report(LOG_DEBUG, "tac_passwd_lookup: close %s %d", 
+           report(LOG_DEBUG, "tac_passwd_lookup: close %s %d",
                   file, fileno(passwd_fp));
        fclose(passwd_fp);
        return(&pw_passwd);
@@ -130,7 +143,7 @@ tac_passwd_lookup(name, file)
 
     /* no match found */
     if (debug & DEBUG_PASSWD_FLAG)
-           report(LOG_DEBUG, "tac_passwd_lookup: close %s %d", 
+           report(LOG_DEBUG, "tac_passwd_lookup: close %s %d",
                   file, fileno(passwd_fp));
     fclose(passwd_fp);
     return(NULL);
diff --git a/pw.h b/pw.h
new file mode 100644 (file)
index 0000000..44dc425
--- /dev/null
+++ b/pw.h
@@ -0,0 +1,10 @@
+#ifndef PW_H
+#define PW_H 1
+
+#include "tac_plus.h"
+
+
+extern struct passwd *tac_passwd_lookup TAC_ARGS((const char *name, const char *file));
+
+
+#endif /* PW_H */
diff --git a/pwlib.c b/pwlib.c
index 75f90b1..70a468e 100644 (file)
--- a/pwlib.c
+++ b/pwlib.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
-#include "expire.h"
-#include "time_limit.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <pwd.h>
+#include <sys/types.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
 
 #ifdef SHADOW_PASSWORDS
+#ifdef HAVE_SHADOW_H
 #include <shadow.h>
 #endif
+#endif
 
-#ifdef USE_PAM
-int
-tac_pam_auth(char *UserName,char *Password,struct authen_data *data,char *Service);
-#endif /* USE_PAM   */
+#include "pwlib.h"
+#include "expire.h"
+#include "time_limit.h"
+#include "report.h"
+#include "utils.h"
+#include "cfgfile.h"
+#include "pw.h"
+#include "choose_authen.h"                     /* for "struct authen_data" */
+#include "packet.h"
+#include "main.h"
+#include "parse.h"
 
-/* For database verification */
+#ifdef USE_PAM
+#include "tac_pam.h"
+#endif
 #ifdef DB
-int db_verify();
-#endif /* DB */
-
-/* For LDAP verification */
+#include "db.h"                        /* For database verification */
+#endif
 #ifdef USE_LDAP
-#include "ldap.h"
-#endif /* LDAP */
+#include "ldap_author.h"               /* For LDAP verification */
+#endif
+
+
+static int passwd_file_verify TAC_ARGS((const char *user, const char *supplied_passwd, struct authen_data *data, const char *filename));
+
 
 /* Generic password verification routines for des, file and cleartext
    passwords */
 
-static int passwd_file_verify();
-
 /* Adjust data->status depending on whether a user has expired or not */
 
+void set_expiration_status TAC_ARGS((const char *exp_date, struct authen_data *data));
+
 void
 set_expiration_status(exp_date, data)
-char *exp_date;
+const char *exp_date;
 struct authen_data *data;
 {
     int expired;
@@ -66,7 +88,7 @@ struct authen_data *data;
     switch (expired) {
     case PW_OK:
        if (debug & DEBUG_PASSWD_FLAG)
-           report(LOG_DEBUG, "Password has not expired %s", 
+           report(LOG_DEBUG, "Password has not expired %s",
                   exp_date ? exp_date : "<no expiry date set>");
 
        data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
@@ -74,7 +96,7 @@ struct authen_data *data;
 
     case PW_EXPIRING:
        if (debug & DEBUG_PASSWD_FLAG)
-           report(LOG_DEBUG, "Password will expire soon %s", 
+           report(LOG_DEBUG, "Password will expire soon %s",
                   exp_date ? exp_date : "<no expiry date set>");
        if (data->server_msg)
            free(data->server_msg);
@@ -84,7 +106,7 @@ struct authen_data *data;
 
     case PW_EXPIRED:
        if (debug & DEBUG_PASSWD_FLAG)
-           report(LOG_DEBUG, "Password has expired %s", 
+           report(LOG_DEBUG, "Password has expired %s",
                   exp_date ? exp_date : "<no expiry date set>");
        if (data->server_msg)
            free(data->server_msg);
@@ -93,7 +115,7 @@ struct authen_data *data;
        return;
 
     default:
-       report(LOG_ERR, "%s: Bogus return value %d from check_expiration", 
+       report(LOG_ERR, "%s: Bogus return value %d from check_expiration",
               session.peer, expired);
        data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
        return;
@@ -102,28 +124,28 @@ struct authen_data *data;
 
 /* Verify that this user/password is valid.  Works only for cleartext,
    file and des passwords.
-   
+
    Return 1 if password is valid */
 
+int verify TAC_ARGS((const char *name, const char *passwd, struct authen_data *data, int recurse));
+
 int
 verify(name, passwd, data, recurse)
-char *name, *passwd;
+const char *name;
+const char *passwd;
 struct authen_data *data;
 int recurse;
 {
-    char *exp_date;
-    char *timestamp;
-    char *cfg_passwd;
-    char *p;
-    
-    timestamp = (char *)cfg_get_timestamp(name, recurse); 
-    if ( timestamp != NULL ) { 
+    const char *exp_date, *cfg_passwd, *p, *timestamp;
+
+    timestamp = cfg_get_timestamp(name, recurse);
+    if ( timestamp != NULL ) {
        if( time_limit_process(timestamp) == 0  ) {
-               if ( debug & DEBUG_AUTHEN_FLAG ) 
-                       report(LOG_DEBUG,"Timestamp check failed");     
+               if ( debug & DEBUG_AUTHEN_FLAG )
+                       report(LOG_DEBUG,"Timestamp check failed");
                data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
                return (0);
-       } 
+       }
     }
 
     if (data->type == TAC_PLUS_AUTHEN_TYPE_PAP) {
@@ -132,7 +154,7 @@ int recurse;
        cfg_passwd = cfg_get_login_secret(name, recurse);
     }
 
-    /* If there is no login or pap password for this user, see if there is 
+    /* If there is no login or pap password for this user, see if there is
        a global password for her that we can use */
 
     if (!cfg_passwd) {
@@ -144,30 +166,30 @@ int recurse;
        has been issued, attempt to use this password file */
 
     if (!cfg_passwd) {
-       char *file = cfg_get_authen_default();
+       const char *file = cfg_get_authen_default();
        switch (cfg_get_authen_default_method()) {
+
        case (S_file):
+           if (file)
+               return (passwd_file_verify(name, passwd, data, file));
+           break;
 
-       if (file) {
-           return (passwd_file_verify(name, passwd, data, file));
-       }
-        break;
 #ifdef DB
        case (S_db):
-   /* ugly check for database connect string */
-   if( strstr(file, "://") ){
-           if (debug & DEBUG_PASSWD_FLAG)
-               report(LOG_DEBUG,"%s %s: DB access to %s for user %s",session.peer, session.port, file, name);
-        if (!db_verify(name, passwd, file)) {
-            data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
-            return (0);
-        } else {
-            data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
-        }
-        exp_date = NULL;
-        set_expiration_status(exp_date, data);
-        return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
-    }
+       /* ugly check for database connect string */
+       if( strstr(file, "://") ) {
+            if (debug & DEBUG_PASSWD_FLAG)
+                report(LOG_DEBUG,"%s %s: DB access to %s for user %s",session.peer, session.port, file, name);
+            if (!db_verify(name, passwd, file)) {
+                data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
+                return (0);
+            } else {
+                data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
+            }
+            exp_date = NULL;
+            set_expiration_status(exp_date, data);
+            return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
+       }
        break;
 #endif
 
@@ -188,8 +210,8 @@ int recurse;
 #ifdef USE_PAM
         case (S_pam):
        if (debug & DEBUG_PASSWD_FLAG)
-           report(LOG_DEBUG, "PAM verify daemon %s == NAS %s", p,passwd);
-       if (tac_pam_auth(name, passwd, data,file)) {
+           report(LOG_DEBUG, "PAM verify daemon [PAM] == NAS %s", passwd);
+       if (tac_pam_auth(name, passwd, data, file)) {
            if (debug & DEBUG_PASSWD_FLAG)
                report(LOG_DEBUG, "PAM default authentication fail");
            data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
@@ -205,14 +227,13 @@ int recurse;
        set_expiration_status(exp_date, data);
        return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
        break;
-#endif 
+#endif
        default:
        /* otherwise, we fail */
        data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
        return (0);
-
+       }
     }
-}
 
     /* We have a configured password. Deal with it depending on its
        type */
@@ -225,14 +246,14 @@ int recurse;
 
        if (strcmp(passwd, p)) {
            if (debug & DEBUG_PASSWD_FLAG)
-               report(LOG_DEBUG, "Password is incorrect"); 
+               report(LOG_DEBUG, "Password is incorrect");
            data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
            return(0);
        } else {
            data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
 
            if (debug & DEBUG_PASSWD_FLAG)
-               report(LOG_DEBUG, "Password is correct"); 
+               report(LOG_DEBUG, "Password is correct");
        }
 
        exp_date = cfg_get_expires(name, recurse);
@@ -292,7 +313,7 @@ int recurse;
 
         if (debug & DEBUG_PASSWD_FLAG)
                 report(LOG_DEBUG, "DB Password is incorrect");
-   
+
         return (0);
         } else {
 
@@ -310,24 +331,28 @@ int recurse;
     if (p) {
        return (passwd_file_verify(name, passwd, data, p));
     }
-    
+
     /* Oops. No idea what kind of password this is. This should never
        happen as the parser should never create such passwords. */
 
     report(LOG_ERR, "%s: Error cannot identify password type %s for %s",
-          session.peer, 
-          cfg_passwd && cfg_passwd[0] ? cfg_passwd : "<NULL>", 
+          session.peer,
+          cfg_passwd && cfg_passwd[0] ? cfg_passwd : "<NULL>",
           name ? name : "<unknown>");
 
     data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
     return (0);
 }
 
+static int etc_passwd_file_verify TAC_ARGS((const char *user, const char *supplied_passwd, struct authen_data *data));
+
 /* verify that this user/password is valid per /etc/passwd.
-   Return 0 if invalid. */
+ * Return 0 if invalid.
+ */
 static int
 etc_passwd_file_verify(user, supplied_passwd, data)
-char *user, *supplied_passwd;
+const char *user;
+const char *supplied_passwd;
 struct authen_data *data;
 {
     struct passwd *pw;
@@ -373,12 +398,12 @@ struct authen_data *data;
        }
        cfg_passwd = spwd->sp_pwdp;
 
-       /* 
+       /*
         * Sigh. The Solaris shadow password file contains its own
         * expiry date as the number of days after the epoch
         * (January 1, 1970) when the password expires.
         * Convert this to ascii so that the traditional tacacs
-        * password expiration routines work correctly. 
+        * password expiration routines work correctly.
         */
 
        if (spwd->sp_expire > 0) {
@@ -409,11 +434,14 @@ struct authen_data *data;
 /* verify that this user/password is valid per a passwd(5) style
    database. Return 0 if invalid. */
 
+static int passwd_file_verify TAC_ARGS((const char *user, const char *supplied_passwd, struct authen_data *data, const char *filename));
+
 static int
 passwd_file_verify(user, supplied_passwd, data, filename)
-char *user, *supplied_passwd;
+const char *user;
+const char *supplied_passwd;
 struct authen_data *data;
-char *filename;
+const char *filename;
 {
     struct passwd *pw;
     char *exp_date;
@@ -424,7 +452,7 @@ char *filename;
     if (filename && (STREQ(filename, "/etc/passwd")|| STREQ(filename,"/etc/shadow") )) {
        return(etc_passwd_file_verify(user, supplied_passwd, data));
     }
+
 
 
     /* an alternate filename */
@@ -467,9 +495,12 @@ char *filename;
  * return 1 if verified, 0 otherwise.
  */
 
+int des_verify TAC_ARGS((const char *users_passwd, const char *encrypted_passwd));
+
 int
 des_verify(users_passwd, encrypted_passwd)
-char *users_passwd, *encrypted_passwd;
+const char *users_passwd;
+const char *encrypted_passwd;
 {
     char *ep;
 
diff --git a/pwlib.h b/pwlib.h
new file mode 100644 (file)
index 0000000..92b54af
--- /dev/null
+++ b/pwlib.h
@@ -0,0 +1,14 @@
+#ifndef PWLIB_H
+#define PWLIB_H 1
+
+#include "tac_plus.h"
+
+
+struct authen_data;
+
+extern void set_expiration_status TAC_ARGS((const char *exp_date, struct authen_data *data));
+extern int verify TAC_ARGS((const char *name, const char *passwd, struct authen_data *data, int recurse));
+extern int des_verify TAC_ARGS((const char *users_passwd, const char *encrypted_passwd));
+
+
+#endif /* PWLIB_H */
diff --git a/regexp.3 b/regexp.3
deleted file mode 100644 (file)
index ba0bad3..0000000
--- a/regexp.3
+++ /dev/null
@@ -1,179 +0,0 @@
-.TH REGEXP 3 local
-.DA 2 April 1986
-.SH NAME
-regcomp, regexec, regsub, regerror \- regular expression handler
-.SH SYNOPSIS
-.ft B
-.nf
-#include <regexp.h>
-
-regexp *regcomp(exp)
-char *exp;
-
-int regexec(prog, string)
-regexp *prog;
-char *string;
-
-regsub(prog, source, dest)
-regexp *prog;
-char *source;
-char *dest;
-
-regerror(msg)
-char *msg;
-.SH DESCRIPTION
-These functions implement
-.IR egrep (1)-style
-regular expressions and supporting facilities.
-.PP
-.I Regcomp
-compiles a regular expression into a structure of type
-.IR regexp ,
-and returns a pointer to it.
-The space has been allocated using
-.IR malloc (3)
-and may be released by
-.IR free .
-.PP
-.I Regexec
-matches a NUL-terminated \fIstring\fR against the compiled regular expression
-in \fIprog\fR.
-It returns 1 for success and 0 for failure, and adjusts the contents of
-\fIprog\fR's \fIstartp\fR and \fIendp\fR (see below) accordingly.
-.PP
-The members of a
-.I regexp
-structure include at least the following (not necessarily in order):
-.PP
-.RS
-char *startp[NSUBEXP];
-.br
-char *endp[NSUBEXP];
-.RE
-.PP
-where
-.I NSUBEXP
-is defined (as 10) in the header file.
-Once a successful \fIregexec\fR has been done using the \fIregexp\fR,
-each \fIstartp\fR-\fIendp\fR pair describes one substring
-within the \fIstring\fR,
-with the \fIstartp\fR pointing to the first character of the substring and
-the \fIendp\fR pointing to the first character following the substring.
-The 0th substring is the substring of \fIstring\fR that matched the whole
-regular expression.
-The others are those substrings that matched parenthesized expressions
-within the regular expression, with parenthesized expressions numbered
-in left-to-right order of their opening parentheses.
-.PP
-.I Regsub
-copies \fIsource\fR to \fIdest\fR, making substitutions according to the
-most recent \fIregexec\fR performed using \fIprog\fR.
-Each instance of `&' in \fIsource\fR is replaced by the substring
-indicated by \fIstartp\fR[\fI0\fR] and
-\fIendp\fR[\fI0\fR].
-Each instance of `\e\fIn\fR', where \fIn\fR is a digit, is replaced by
-the substring indicated by
-\fIstartp\fR[\fIn\fR] and
-\fIendp\fR[\fIn\fR].
-To get a literal `&' or `\e\fIn\fR' into \fIdest\fR, prefix it with `\e';
-to get a literal `\e' preceding `&' or `\e\fIn\fR', prefix it with
-another `\e'.
-.PP
-.I Regerror
-is called whenever an error is detected in \fIregcomp\fR, \fIregexec\fR,
-or \fIregsub\fR.
-The default \fIregerror\fR writes the string \fImsg\fR,
-with a suitable indicator of origin,
-on the standard
-error output
-and invokes \fIexit\fR(2).
-.I Regerror
-can be replaced by the user if other actions are desirable.
-.SH "REGULAR EXPRESSION SYNTAX"
-A regular expression is zero or more \fIbranches\fR, separated by `|'.
-It matches anything that matches one of the branches.
-.PP
-A branch is zero or more \fIpieces\fR, concatenated.
-It matches a match for the first, followed by a match for the second, etc.
-.PP
-A piece is an \fIatom\fR possibly followed by `*', `+', or `?'.
-An atom followed by `*' matches a sequence of 0 or more matches of the atom.
-An atom followed by `+' matches a sequence of 1 or more matches of the atom.
-An atom followed by `?' matches a match of the atom, or the null string.
-.PP
-An atom is a regular expression in parentheses (matching a match for the
-regular expression), a \fIrange\fR (see below), `.'
-(matching any single character), `^' (matching the null string at the
-beginning of the input string), `$' (matching the null string at the
-end of the input string), a `\e' followed by a single character (matching
-that character), or a single character with no other significance
-(matching that character).
-.PP
-A \fIrange\fR is a sequence of characters enclosed in `[]'.
-It normally matches any single character from the sequence.
-If the sequence begins with `^',
-it matches any single character \fInot\fR from the rest of the sequence.
-If two characters in the sequence are separated by `\-', this is shorthand
-for the full list of ASCII characters between them
-(e.g. `[0-9]' matches any decimal digit).
-To include a literal `]' in the sequence, make it the first character
-(following a possible `^').
-To include a literal `\-', make it the first or last character.
-.SH AMBIGUITY
-If a regular expression could match two different parts of the input string,
-it will match the one which begins earliest.
-If both begin in the same place        but match different lengths, or match
-the same length in different ways, life gets messier, as follows.
-.PP
-In general, the possibilities in a list of branches are considered in
-left-to-right order, the possibilities for `*', `+', and `?' are
-considered longest-first, nested constructs are considered from the
-outermost in, and concatenated constructs are considered leftmost-first.
-The match that will be chosen is the one that uses the earliest
-possibility in the first choice that has to be made.
-If there is more than one choice, the next will be made in the same manner
-(earliest possibility) subject to the decision on the first choice.
-And so forth.
-.PP
-For example, `(ab|a)b*c' could match `abc' in one of two ways.
-The first choice is between `ab' and `a'; since `ab' is earlier, and does
-lead to a successful overall match, it is chosen.
-Since the `b' is already spoken for,
-the `b*' must match its last possibility\(emthe empty string\(emsince
-it must respect the earlier choice.
-.PP
-In the particular case where no `|'s are present and there is only one
-`*', `+', or `?', the net effect is that the longest possible
-match will be chosen.
-So `ab*', presented with `xabbbby', will match `abbbb'.
-Note that if `ab*' is tried against `xabyabbbz', it
-will match `ab' just after `x', due to the begins-earliest rule.
-(In effect, the decision on where to start the match is the first choice
-to be made, hence subsequent choices must respect it even if this leads them
-to less-preferred alternatives.)
-.SH SEE ALSO
-egrep(1), expr(1)
-.SH DIAGNOSTICS
-\fIRegcomp\fR returns NULL for a failure
-(\fIregerror\fR permitting),
-where failures are syntax errors, exceeding implementation limits,
-or applying `+' or `*' to a possibly-null operand.
-.SH HISTORY
-Both code and manual page were
-written at U of T.
-They are intended to be compatible with the Bell V8 \fIregexp\fR(3),
-but are not derived from Bell code.
-.SH BUGS
-Empty branches and empty regular expressions are not portable to V8.
-.PP
-The restriction against
-applying `*' or `+' to a possibly-null operand is an artifact of the
-simplistic implementation.
-.PP
-Does not support \fIegrep\fR's newline-separated branches;
-neither does the V8 \fIregexp\fR(3), though.
-.PP
-Due to emphasis on
-compactness and simplicity,
-it's not strikingly fast.
-It does give special attention to handling simple cases quickly.
diff --git a/regexp.c b/regexp.c
deleted file mode 100644 (file)
index 9c0357a..0000000
--- a/regexp.c
+++ /dev/null
@@ -1,1234 +0,0 @@
-/* 
-   Copyright (c) 1995-1998 by Cisco systems, 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 of the
-   software and supporting documentation, the name of Cisco Systems,
-   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 modification,
-   copying and distribution is by permission of Cisco Systems, Inc.
-
-   Cisco Systems, Inc. makes no representations about the suitability
-   of this software for any purpose.  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.
-*/
-
-/*
- * regcomp and regexec -- regsub and regerror are elsewhere
- * @(#)regexp.c        1.3 of 18 April 87
- *
- *     Copyright (c) 1986 by University of Toronto.
- *     Written by Henry Spencer.  Not derived from licensed software.
- *
- *     Permission is granted to anyone to use this software for any
- *     purpose on any computer system, and to redistribute it freely,
- *     subject to the following restrictions:
- *
- *     1. The author is not responsible for the consequences of use of
- *             this software, no matter how awful, even if they arise
- *             from defects in it.
- *
- *     2. The origin of this software must not be misrepresented, either
- *             by explicit claim or by omission.
- *
- *     3. Altered versions must be plainly marked as such, and must not
- *             be misrepresented as being the original software.
- *
- * Beware that some of this code is subtly aware of the way operator
- * precedence is structured in regular expressions.  Serious changes in
- * regular-expression syntax might require a total rethink.
- */
-#include <stdio.h>
-#include "regexp.h"
-#include "regmagic.h"
-
-/*
- * The "internal use only" fields in regexp.h are present to pass info from
- * compile to execute that permits the execute phase to run lots faster on
- * simple cases.  They are:
- *
- * regstart    char that must begin a match; '\0' if none obvious
- * reganch     is the match anchored (at beginning-of-line only)?
- * regmust     string (pointer into program) that match must include, or NULL
- * regmlen     length of regmust string
- *
- * Regstart and reganch permit very fast decisions on suitable starting points
- * for a match, cutting down the work a lot.  Regmust permits fast rejection
- * of lines that cannot possibly match.  The regmust tests are costly enough
- * that regcomp() supplies a regmust only if the r.e. contains something
- * potentially expensive (at present, the only such thing detected is * or +
- * at the start of the r.e., which can involve a lot of backup).  Regmlen is
- * supplied because the test in regexec() needs it and regcomp() is computing
- * it anyway.
- */
-
-/*
- * Structure for regexp "program".  This is essentially a linear encoding
- * of a nondeterministic finite-state machine (aka syntax charts or
- * "railroad normal form" in parsing technology).  Each node is an opcode
- * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
- * all nodes except BRANCH implement concatenation; a "next" pointer with
- * a BRANCH on both ends of it is connecting two alternatives.  (Here we
- * have one of the subtle syntax dependencies:  an individual BRANCH (as
- * opposed to a collection of them) is never concatenated with anything
- * because of operator precedence.)  The operand of some types of node is
- * a literal string; for others, it is a node leading into a sub-FSM.  In
- * particular, the operand of a BRANCH node is the first node of the branch.
- * (NB this is *not* a tree structure:  the tail of the branch connects
- * to the thing following the set of BRANCHes.)  The opcodes are:
- */
-
-/* definition  number  opnd?   meaning */
-#define        END     0       /* no   End of program. */
-#define        BOL     1       /* no   Match "" at beginning of line. */
-#define        EOL     2       /* no   Match "" at end of line. */
-#define        ANY     3       /* no   Match any one character. */
-#define        ANYOF   4       /* str  Match any character in this string. */
-#define        ANYBUT  5       /* str  Match any character not in this string. */
-#define        BRANCH  6       /* node Match this alternative, or the next... */
-#define        BACK    7       /* no   Match "", "next" ptr points backward. */
-#define        EXACTLY 8       /* str  Match this string. */
-#define        NOTHING 9       /* no   Match empty string. */
-#define        STAR    10      /* node Match this (simple) thing 0 or more times. */
-#define        PLUS    11      /* node Match this (simple) thing 1 or more times. */
-#define        OPEN    20      /* no   Mark this point in input as start of #n. */
-                       /*      OPEN+1 is number 1, etc. */
-#define        CLOSE   30      /* no   Analogous to OPEN. */
-
-/*
- * Opcode notes:
- *
- * BRANCH      The set of branches constituting a single choice are hooked
- *             together with their "next" pointers, since precedence prevents
- *             anything being concatenated to any individual branch.  The
- *             "next" pointer of the last BRANCH in a choice points to the
- *             thing following the whole choice.  This is also where the
- *             final "next" pointer of each individual branch points; each
- *             branch starts with the operand node of a BRANCH node.
- *
- * BACK                Normal "next" pointers all implicitly point forward; BACK
- *             exists to make loop structures possible.
- *
- * STAR,PLUS   '?', and complex '*' and '+', are implemented as circular
- *             BRANCH structures using BACK.  Simple cases (one character
- *             per match) are implemented with STAR and PLUS for speed
- *             and to minimize recursive plunges.
- *
- * OPEN,CLOSE  ...are numbered at compile time.
- */
-
-/*
- * A node is one char of opcode followed by two chars of "next" pointer.
- * "Next" pointers are stored as two 8-bit pieces, high order first.  The
- * value is a positive offset from the opcode of the node containing it.
- * An operand, if any, simply follows the node.  (Note that much of the
- * code generation knows about this implicit relationship.)
- *
- * Using two bytes for the "next" pointer is vast overkill for most things,
- * but allows patterns to get big without disasters.
- */
-#define        OP(p)   (*(p))
-#define        NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
-#define        OPERAND(p)      ((p) + 3)
-
-/*
- * See regmagic.h for one further detail of program structure.
- */
-
-
-/*
- * Utility definitions.
- */
-#ifndef CHARBITS
-#define        UCHARAT(p)      ((int)*(unsigned char *)(p))
-#else
-#define        UCHARAT(p)      ((int)*(p)&CHARBITS)
-#endif
-
-#define        FAIL(m) { regerror(m); return(NULL); }
-#define        ISMULT(c)       ((c) == '*' || (c) == '+' || (c) == '?')
-#define        META    "^$.[()|?+*\\"
-
-/*
- * Flags to be passed up and down.
- */
-#define        HASWIDTH        01      /* Known never to match null string. */
-#define        SIMPLE          02      /* Simple enough to be STAR/PLUS operand. */
-#define        SPSTART         04      /* Starts with * or +. */
-#define        WORST           0       /* Worst case. */
-
-/*
- * Global work variables for regcomp().
- */
-static char *regparse;         /* Input-scan pointer. */
-static int regnpar;            /* () count. */
-static char regdummy;
-static char *regcode;          /* Code-emit pointer; &regdummy = don't. */
-static long regsize;           /* Code size. */
-
-/*
- * Forward declarations for regcomp()'s friends.
- */
-#ifndef STATIC
-#define        STATIC  static
-#endif
-STATIC char *reg();
-STATIC char *regbranch();
-STATIC char *regpiece();
-STATIC char *regatom();
-STATIC char *regnode();
-STATIC char *regnext();
-STATIC void regc();
-STATIC void reginsert();
-STATIC void regtail();
-STATIC void regoptail();
-#ifdef STRCSPN
-STATIC int strcspn();
-#endif
-
-/*
- - regcomp - compile a regular expression into internal code
- *
- * We can't allocate space until we know how big the compiled form will be,
- * but we can't compile it (and thus know how big it is) until we've got a
- * place to put the code.  So we cheat:  we compile it twice, once with code
- * generation turned off and size counting turned on, and once "for real".
- * This also means that we don't allocate space until we are sure that the
- * thing really will compile successfully, and we never have to move the
- * code and thus invalidate pointers into it.  (Note that it has to be in
- * one piece because free() must be able to free it all.)
- *
- * Beware that the optimization-preparation code in here knows about some
- * of the structure of the compiled regexp.
- */
-regexp *
-regcomp(exp)
-char *exp;
-{
-       register regexp *r;
-       register char *scan;
-       register char *longest;
-       register int len;
-       int flags;
-       extern char *malloc();
-
-       if (exp == NULL)
-               FAIL("NULL argument");
-
-       /* First pass: determine size, legality. */
-       regparse = exp;
-       regnpar = 1;
-       regsize = 0L;
-       regcode = &regdummy;
-       regc(MAGIC);
-       if (reg(0, &flags) == NULL)
-               return(NULL);
-
-       /* Small enough for pointer-storage convention? */
-       if (regsize >= 32767L)          /* Probably could be 65535L. */
-               FAIL("regexp too big");
-
-       /* Allocate space. */
-       r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
-       if (r == NULL)
-               FAIL("out of space");
-
-       /* Second pass: emit code. */
-       regparse = exp;
-       regnpar = 1;
-       regcode = r->program;
-       regc(MAGIC);
-       if (reg(0, &flags) == NULL)
-               return(NULL);
-
-       /* Dig out information for optimizations. */
-       r->regstart = '\0';     /* Worst-case defaults. */
-       r->reganch = 0;
-       r->regmust = NULL;
-       r->regmlen = 0;
-       scan = r->program+1;                    /* First BRANCH. */
-       if (OP(regnext(scan)) == END) {         /* Only one top-level choice. */
-               scan = OPERAND(scan);
-
-               /* Starting-point info. */
-               if (OP(scan) == EXACTLY)
-                       r->regstart = *OPERAND(scan);
-               else if (OP(scan) == BOL)
-                       r->reganch++;
-
-               /*
-                * If there's something expensive in the r.e., find the
-                * longest literal string that must appear and make it the
-                * regmust.  Resolve ties in favor of later strings, since
-                * the regstart check works with the beginning of the r.e.
-                * and avoiding duplication strengthens checking.  Not a
-                * strong reason, but sufficient in the absence of others.
-                */
-               if (flags&SPSTART) {
-                       longest = NULL;
-                       len = 0;
-                       for (; scan != NULL; scan = regnext(scan))
-                               if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
-                                       longest = OPERAND(scan);
-                                       len = strlen(OPERAND(scan));
-                               }
-                       r->regmust = longest;
-                       r->regmlen = len;
-               }
-       }
-
-       return(r);
-}
-
-/*
- - reg - regular expression, i.e. main body or parenthesized thing
- *
- * Caller must absorb opening parenthesis.
- *
- * Combining parenthesis handling with the base level of regular expression
- * is a trifle forced, but the need to tie the tails of the branches to what
- * follows makes it hard to avoid.
- */
-static char *
-reg(paren, flagp)
-int paren;                     /* Parenthesized? */
-int *flagp;
-{
-       register char *ret;
-       register char *br;
-       register char *ender;
-       register int parno;
-       int flags;
-
-       *flagp = HASWIDTH;      /* Tentatively. */
-
-       /* Make an OPEN node, if parenthesized. */
-       if (paren) {
-               if (regnpar >= NSUBEXP)
-                       FAIL("too many ()");
-               parno = regnpar;
-               regnpar++;
-               ret = regnode(OPEN+parno);
-       } else
-               ret = NULL;
-
-       /* Pick up the branches, linking them together. */
-       br = regbranch(&flags);
-       if (br == NULL)
-               return(NULL);
-       if (ret != NULL)
-               regtail(ret, br);       /* OPEN -> first. */
-       else
-               ret = br;
-       if (!(flags&HASWIDTH))
-               *flagp &= ~HASWIDTH;
-       *flagp |= flags&SPSTART;
-       while (*regparse == '|') {
-               regparse++;
-               br = regbranch(&flags);
-               if (br == NULL)
-                       return(NULL);
-               regtail(ret, br);       /* BRANCH -> BRANCH. */
-               if (!(flags&HASWIDTH))
-                       *flagp &= ~HASWIDTH;
-               *flagp |= flags&SPSTART;
-       }
-
-       /* Make a closing node, and hook it on the end. */
-       ender = regnode((paren) ? CLOSE+parno : END);   
-       regtail(ret, ender);
-
-       /* Hook the tails of the branches to the closing node. */
-       for (br = ret; br != NULL; br = regnext(br))
-               regoptail(br, ender);
-
-       /* Check for proper termination. */
-       if (paren && *regparse++ != ')') {
-               FAIL("unmatched ()");
-       } else if (!paren && *regparse != '\0') {
-               if (*regparse == ')') {
-                       FAIL("unmatched ()");
-               } else
-                       FAIL("junk on end");    /* "Can't happen". */
-               /* NOTREACHED */
-       }
-
-       return(ret);
-}
-
-/*
- - regbranch - one alternative of an | operator
- *
- * Implements the concatenation operator.
- */
-static char *
-regbranch(flagp)
-int *flagp;
-{
-       register char *ret;
-       register char *chain;
-       register char *latest;
-       int flags;
-
-       *flagp = WORST;         /* Tentatively. */
-
-       ret = regnode(BRANCH);
-       chain = NULL;
-       while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
-               latest = regpiece(&flags);
-               if (latest == NULL)
-                       return(NULL);
-               *flagp |= flags&HASWIDTH;
-               if (chain == NULL)      /* First piece. */
-                       *flagp |= flags&SPSTART;
-               else
-                       regtail(chain, latest);
-               chain = latest;
-       }
-       if (chain == NULL)      /* Loop ran zero times. */
-               (void) regnode(NOTHING);
-
-       return(ret);
-}
-
-/*
- - regpiece - something followed by possible [*+?]
- *
- * Note that the branching code sequences used for ? and the general cases
- * of * and + are somewhat optimized:  they use the same NOTHING node as
- * both the endmarker for their branch list and the body of the last branch.
- * It might seem that this node could be dispensed with entirely, but the
- * endmarker role is not redundant.
- */
-static char *
-regpiece(flagp)
-int *flagp;
-{
-       register char *ret;
-       register char op;
-       register char *next;
-       int flags;
-
-       ret = regatom(&flags);
-       if (ret == NULL)
-               return(NULL);
-
-       op = *regparse;
-       if (!ISMULT(op)) {
-               *flagp = flags;
-               return(ret);
-       }
-
-       if (!(flags&HASWIDTH) && op != '?')
-               FAIL("*+ operand could be empty");
-       *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
-
-       if (op == '*' && (flags&SIMPLE))
-               reginsert(STAR, ret);
-       else if (op == '*') {
-               /* Emit x* as (x&|), where & means "self". */
-               reginsert(BRANCH, ret);                 /* Either x */
-               regoptail(ret, regnode(BACK));          /* and loop */
-               regoptail(ret, ret);                    /* back */
-               regtail(ret, regnode(BRANCH));          /* or */
-               regtail(ret, regnode(NOTHING));         /* null. */
-       } else if (op == '+' && (flags&SIMPLE))
-               reginsert(PLUS, ret);
-       else if (op == '+') {
-               /* Emit x+ as x(&|), where & means "self". */
-               next = regnode(BRANCH);                 /* Either */
-               regtail(ret, next);
-               regtail(regnode(BACK), ret);            /* loop back */
-               regtail(next, regnode(BRANCH));         /* or */
-               regtail(ret, regnode(NOTHING));         /* null. */
-       } else if (op == '?') {
-               /* Emit x? as (x|) */
-               reginsert(BRANCH, ret);                 /* Either x */
-               regtail(ret, regnode(BRANCH));          /* or */
-               next = regnode(NOTHING);                /* null. */
-               regtail(ret, next);
-               regoptail(ret, next);
-       }
-       regparse++;
-       if (ISMULT(*regparse))
-               FAIL("nested *?+");
-
-       return(ret);
-}
-
-/*
- - regatom - the lowest level
- *
- * Optimization:  gobbles an entire sequence of ordinary characters so that
- * it can turn them into a single node, which is smaller to store and
- * faster to run.  Backslashed characters are exceptions, each becoming a
- * separate node; the code is simpler that way and it's not worth fixing.
- */
-static char *
-regatom(flagp)
-int *flagp;
-{
-       register char *ret;
-       int flags;
-
-       *flagp = WORST;         /* Tentatively. */
-
-       switch (*regparse++) {
-       case '^':
-               ret = regnode(BOL);
-               break;
-       case '$':
-               ret = regnode(EOL);
-               break;
-       case '.':
-               ret = regnode(ANY);
-               *flagp |= HASWIDTH|SIMPLE;
-               break;
-       case '[': {
-                       register int class;
-                       register int classend;
-
-                       if (*regparse == '^') { /* Complement of range. */
-                               ret = regnode(ANYBUT);
-                               regparse++;
-                       } else
-                               ret = regnode(ANYOF);
-                       if (*regparse == ']' || *regparse == '-')
-                               regc(*regparse++);
-                       while (*regparse != '\0' && *regparse != ']') {
-                               if (*regparse == '-') {
-                                       regparse++;
-                                       if (*regparse == ']' || *regparse == '\0')
-                                               regc('-');
-                                       else {
-                                               class = UCHARAT(regparse-2)+1;
-                                               classend = UCHARAT(regparse);
-                                               if (class > classend+1)
-                                                       FAIL("invalid [] range");
-                                               for (; class <= classend; class++)
-                                                       regc(class);
-                                               regparse++;
-                                       }
-                               } else
-                                       regc(*regparse++);
-                       }
-                       regc('\0');
-                       if (*regparse != ']')
-                               FAIL("unmatched []");
-                       regparse++;
-                       *flagp |= HASWIDTH|SIMPLE;
-               }
-               break;
-       case '(':
-               ret = reg(1, &flags);
-               if (ret == NULL)
-                       return(NULL);
-               *flagp |= flags&(HASWIDTH|SPSTART);
-               break;
-       case '\0':
-       case '|':
-       case ')':
-               FAIL("internal urp");   /* Supposed to be caught earlier. */
-               break;
-       case '?':
-       case '+':
-       case '*':
-               FAIL("?+* follows nothing");
-               break;
-       case '\\':
-               if (*regparse == '\0')
-                       FAIL("trailing \\");
-               ret = regnode(EXACTLY);
-               regc(*regparse++);
-               regc('\0');
-               *flagp |= HASWIDTH|SIMPLE;
-               break;
-       default: {
-                       register int len;
-                       register char ender;
-
-                       regparse--;
-                       len = strcspn(regparse, META);
-                       if (len <= 0)
-                               FAIL("internal disaster");
-                       ender = *(regparse+len);
-                       if (len > 1 && ISMULT(ender))
-                               len--;          /* Back off clear of ?+* operand. */
-                       *flagp |= HASWIDTH;
-                       if (len == 1)
-                               *flagp |= SIMPLE;
-                       ret = regnode(EXACTLY);
-                       while (len > 0) {
-                               regc(*regparse++);
-                               len--;
-                       }
-                       regc('\0');
-               }
-               break;
-       }
-
-       return(ret);
-}
-
-/*
- - regnode - emit a node
- */
-static char *                  /* Location. */
-regnode(op)
-char op;
-{
-       register char *ret;
-       register char *ptr;
-
-       ret = regcode;
-       if (ret == &regdummy) {
-               regsize += 3;
-               return(ret);
-       }
-
-       ptr = ret;
-       *ptr++ = op;
-       *ptr++ = '\0';          /* Null "next" pointer. */
-       *ptr++ = '\0';
-       regcode = ptr;
-
-       return(ret);
-}
-
-/*
- - regc - emit (if appropriate) a byte of code
- */
-static void
-regc(b)
-char b;
-{
-       if (regcode != &regdummy)
-               *regcode++ = b;
-       else
-               regsize++;
-}
-
-/*
- - reginsert - insert an operator in front of already-emitted operand
- *
- * Means relocating the operand.
- */
-static void
-reginsert(op, opnd)
-char op;
-char *opnd;
-{
-       register char *src;
-       register char *dst;
-       register char *place;
-
-       if (regcode == &regdummy) {
-               regsize += 3;
-               return;
-       }
-
-       src = regcode;
-       regcode += 3;
-       dst = regcode;
-       while (src > opnd)
-               *--dst = *--src;
-
-       place = opnd;           /* Op node, where operand used to be. */
-       *place++ = op;
-       *place++ = '\0';
-       *place++ = '\0';
-}
-
-/*
- - regtail - set the next-pointer at the end of a node chain
- */
-static void
-regtail(p, val)
-char *p;
-char *val;
-{
-       register char *scan;
-       register char *temp;
-       register int offset;
-
-       if (p == &regdummy)
-               return;
-
-       /* Find last node. */
-       scan = p;
-       for (;;) {
-               temp = regnext(scan);
-               if (temp == NULL)
-                       break;
-               scan = temp;
-       }
-
-       if (OP(scan) == BACK)
-               offset = scan - val;
-       else
-               offset = val - scan;
-       *(scan+1) = (offset>>8)&0377;
-       *(scan+2) = offset&0377;
-}
-
-/*
- - regoptail - regtail on operand of first argument; nop if operandless
- */
-static void
-regoptail(p, val)
-char *p;
-char *val;
-{
-       /* "Operandless" and "op != BRANCH" are synonymous in practice. */
-       if (p == NULL || p == &regdummy || OP(p) != BRANCH)
-               return;
-       regtail(OPERAND(p), val);
-}
-
-/*
- * regexec and friends
- */
-
-/*
- * Global work variables for regexec().
- */
-static char *reginput;         /* String-input pointer. */
-static char *regbol;           /* Beginning of input, for ^ check. */
-static char **regstartp;       /* Pointer to startp array. */
-static char **regendp;         /* Ditto for endp. */
-
-/*
- * Forwards.
- */
-STATIC int regtry();
-STATIC int regmatch();
-STATIC int regrepeat();
-
-#ifdef DEBUG
-int regnarrate = 0;
-void regdump();
-STATIC char *regprop();
-#endif
-
-/*
- - regexec - match a regexp against a string
- */
-int
-regexec(prog, string)
-register regexp *prog;
-register char *string;
-{
-       register char *s;
-       extern char *strchr();
-
-       /* Be paranoid... */
-       if (prog == NULL || string == NULL) {
-               regerror("NULL parameter");
-               return(0);
-       }
-
-       /* Check validity of program. */
-       if (UCHARAT(prog->program) != MAGIC) {
-               regerror("corrupted program");
-               return(0);
-       }
-
-       /* If there is a "must appear" string, look for it. */
-       if (prog->regmust != NULL) {
-               s = string;
-               while ((s = strchr(s, prog->regmust[0])) != NULL) {
-                       if (strncmp(s, prog->regmust, prog->regmlen) == 0)
-                               break;  /* Found it. */
-                       s++;
-               }
-               if (s == NULL)  /* Not present. */
-                       return(0);
-       }
-
-       /* Mark beginning of line for ^ . */
-       regbol = string;
-
-       /* Simplest case:  anchored match need be tried only once. */
-       if (prog->reganch)
-               return(regtry(prog, string));
-
-       /* Messy cases:  unanchored match. */
-       s = string;
-       if (prog->regstart != '\0')
-               /* We know what char it must start with. */
-               while ((s = strchr(s, prog->regstart)) != NULL) {
-                       if (regtry(prog, s))
-                               return(1);
-                       s++;
-               }
-       else
-               /* We don't -- general case. */
-               do {
-                       if (regtry(prog, s))
-                               return(1);
-               } while (*s++ != '\0');
-
-       /* Failure. */
-       return(0);
-}
-
-/*
- - regtry - try match at specific point
- */
-static int                     /* 0 failure, 1 success */
-regtry(prog, string)
-regexp *prog;
-char *string;
-{
-       register int i;
-       register char **sp;
-       register char **ep;
-
-       reginput = string;
-       regstartp = prog->startp;
-       regendp = prog->endp;
-
-       sp = prog->startp;
-       ep = prog->endp;
-       for (i = NSUBEXP; i > 0; i--) {
-               *sp++ = NULL;
-               *ep++ = NULL;
-       }
-       if (regmatch(prog->program + 1)) {
-               prog->startp[0] = string;
-               prog->endp[0] = reginput;
-               return(1);
-       } else
-               return(0);
-}
-
-/*
- - regmatch - main matching routine
- *
- * Conceptually the strategy is simple:  check to see whether the current
- * node matches, call self recursively to see whether the rest matches,
- * and then act accordingly.  In practice we make some effort to avoid
- * recursion, in particular by going through "ordinary" nodes (that don't
- * need to know whether the rest of the match failed) by a loop instead of
- * by recursion.
- */
-static int                     /* 0 failure, 1 success */
-regmatch(prog)
-char *prog;
-{
-       register char *scan;    /* Current node. */
-       char *next;             /* Next node. */
-       extern char *strchr();
-
-       scan = prog;
-#ifdef DEBUG
-       if (scan != NULL && regnarrate)
-               fprintf(stderr, "%s(\n", regprop(scan));
-#endif
-       while (scan != NULL) {
-#ifdef DEBUG
-               if (regnarrate)
-                       fprintf(stderr, "%s...\n", regprop(scan));
-#endif
-               next = regnext(scan);
-
-               switch (OP(scan)) {
-               case BOL:
-                       if (reginput != regbol)
-                               return(0);
-                       break;
-               case EOL:
-                       if (*reginput != '\0')
-                               return(0);
-                       break;
-               case ANY:
-                       if (*reginput == '\0')
-                               return(0);
-                       reginput++;
-                       break;
-               case EXACTLY: {
-                               register int len;
-                               register char *opnd;
-
-                               opnd = OPERAND(scan);
-                               /* Inline the first character, for speed. */
-                               if (*opnd != *reginput)
-                                       return(0);
-                               len = strlen(opnd);
-                               if (len > 1 && strncmp(opnd, reginput, len) != 0)
-                                       return(0);
-                               reginput += len;
-                       }
-                       break;
-               case ANYOF:
-                       if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
-                               return(0);
-                       reginput++;
-                       break;
-               case ANYBUT:
-                       if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
-                               return(0);
-                       reginput++;
-                       break;
-               case NOTHING:
-                       break;
-               case BACK:
-                       break;
-               case OPEN+1:
-               case OPEN+2:
-               case OPEN+3:
-               case OPEN+4:
-               case OPEN+5:
-               case OPEN+6:
-               case OPEN+7:
-               case OPEN+8:
-               case OPEN+9: {
-                               register int no;
-                               register char *save;
-
-                               no = OP(scan) - OPEN;
-                               save = reginput;
-
-                               if (regmatch(next)) {
-                                       /*
-                                        * Don't set startp if some later
-                                        * invocation of the same parentheses
-                                        * already has.
-                                        */
-                                       if (regstartp[no] == NULL)
-                                               regstartp[no] = save;
-                                       return(1);
-                               } else
-                                       return(0);
-                       }
-                       break;
-               case CLOSE+1:
-               case CLOSE+2:
-               case CLOSE+3:
-               case CLOSE+4:
-               case CLOSE+5:
-               case CLOSE+6:
-               case CLOSE+7:
-               case CLOSE+8:
-               case CLOSE+9: {
-                               register int no;
-                               register char *save;
-
-                               no = OP(scan) - CLOSE;
-                               save = reginput;
-
-                               if (regmatch(next)) {
-                                       /*
-                                        * Don't set endp if some later
-                                        * invocation of the same parentheses
-                                        * already has.
-                                        */
-                                       if (regendp[no] == NULL)
-                                               regendp[no] = save;
-                                       return(1);
-                               } else
-                                       return(0);
-                       }
-                       break;
-               case BRANCH: {
-                               register char *save;
-
-                               if (OP(next) != BRANCH)         /* No choice. */
-                                       next = OPERAND(scan);   /* Avoid recursion. */
-                               else {
-                                       do {
-                                               save = reginput;
-                                               if (regmatch(OPERAND(scan)))
-                                                       return(1);
-                                               reginput = save;
-                                               scan = regnext(scan);
-                                       } while (scan != NULL && OP(scan) == BRANCH);
-                                       return(0);
-                                       /* NOTREACHED */
-                               }
-                       }
-                       break;
-               case STAR:
-               case PLUS: {
-                               register char nextch;
-                               register int no;
-                               register char *save;
-                               register int min;
-
-                               /*
-                                * Lookahead to avoid useless match attempts
-                                * when we know what character comes next.
-                                */
-                               nextch = '\0';
-                               if (OP(next) == EXACTLY)
-                                       nextch = *OPERAND(next);
-                               min = (OP(scan) == STAR) ? 0 : 1;
-                               save = reginput;
-                               no = regrepeat(OPERAND(scan));
-                               while (no >= min) {
-                                       /* If it could work, try it. */
-                                       if (nextch == '\0' || *reginput == nextch)
-                                               if (regmatch(next))
-                                                       return(1);
-                                       /* Couldn't or didn't -- back up. */
-                                       no--;
-                                       reginput = save + no;
-                               }
-                               return(0);
-                       }
-                       break;
-               case END:
-                       return(1);      /* Success! */
-                       break;
-               default:
-                       regerror("memory corruption");
-                       return(0);
-                       break;
-               }
-
-               scan = next;
-       }
-
-       /*
-        * We get here only if there's trouble -- normally "case END" is
-        * the terminating point.
-        */
-       regerror("corrupted pointers");
-       return(0);
-}
-
-/*
- - regrepeat - repeatedly match something simple, report how many
- */
-static int
-regrepeat(p)
-char *p;
-{
-       register int count = 0;
-       register char *scan;
-       register char *opnd;
-       extern char *strchr();
-
-       scan = reginput;
-       opnd = OPERAND(p);
-       switch (OP(p)) {
-       case ANY:
-               count = strlen(scan);
-               scan += count;
-               break;
-       case EXACTLY:
-               while (*opnd == *scan) {
-                       count++;
-                       scan++;
-               }
-               break;
-       case ANYOF:
-               while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
-                       count++;
-                       scan++;
-               }
-               break;
-       case ANYBUT:
-               while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
-                       count++;
-                       scan++;
-               }
-               break;
-       default:                /* Oh dear.  Called inappropriately. */
-               regerror("internal foulup");
-               count = 0;      /* Best compromise. */
-               break;
-       }
-       reginput = scan;
-
-       return(count);
-}
-
-/*
- - regnext - dig the "next" pointer out of a node
- */
-static char *
-regnext(p)
-register char *p;
-{
-       register int offset;
-
-       if (p == &regdummy)
-               return(NULL);
-
-       offset = NEXT(p);
-       if (offset == 0)
-               return(NULL);
-
-       if (OP(p) == BACK)
-               return(p-offset);
-       else
-               return(p+offset);
-}
-
-#ifdef DEBUG
-
-STATIC char *regprop();
-
-/*
- - regdump - dump a regexp onto stdout in vaguely comprehensible form
- */
-void
-regdump(r)
-regexp *r;
-{
-       register char *s;
-       register char op = EXACTLY;     /* Arbitrary non-END op. */
-       register char *next;
-       extern char *strchr();
-
-
-       s = r->program + 1;
-       while (op != END) {     /* While that wasn't END last time... */
-               op = OP(s);
-               printf("%2d%s", s-r->program, regprop(s));      /* Where, what. */
-               next = regnext(s);
-               if (next == NULL)               /* Next ptr. */
-                       printf("(0)");
-               else 
-                       printf("(%d)", (s-r->program)+(next-s));
-               s += 3;
-               if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
-                       /* Literal string, where present. */
-                       while (*s != '\0') {
-                               putchar(*s);
-                               s++;
-                       }
-                       s++;
-               }
-               putchar('\n');
-       }
-
-       /* Header fields of interest. */
-       if (r->regstart != '\0')
-               printf("start `%c' ", r->regstart);
-       if (r->reganch)
-               printf("anchored ");
-       if (r->regmust != NULL)
-               printf("must have \"%s\"", r->regmust);
-       printf("\n");
-}
-
-/*
- - regprop - printable representation of opcode
- */
-static char *
-regprop(op)
-char *op;
-{
-       register char *p;
-       static char buf[50];
-
-       (void) strcpy(buf, ":");
-
-       switch (OP(op)) {
-       case BOL:
-               p = "BOL";
-               break;
-       case EOL:
-               p = "EOL";
-               break;
-       case ANY:
-               p = "ANY";
-               break;
-       case ANYOF:
-               p = "ANYOF";
-               break;
-       case ANYBUT:
-               p = "ANYBUT";
-               break;
-       case BRANCH:
-               p = "BRANCH";
-               break;
-       case EXACTLY:
-               p = "EXACTLY";
-               break;
-       case NOTHING:
-               p = "NOTHING";
-               break;
-       case BACK:
-               p = "BACK";
-               break;
-       case END:
-               p = "END";
-               break;
-       case OPEN+1:
-       case OPEN+2:
-       case OPEN+3:
-       case OPEN+4:
-       case OPEN+5:
-       case OPEN+6:
-       case OPEN+7:
-       case OPEN+8:
-       case OPEN+9:
-               sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
-               p = NULL;
-               break;
-       case CLOSE+1:
-       case CLOSE+2:
-       case CLOSE+3:
-       case CLOSE+4:
-       case CLOSE+5:
-       case CLOSE+6:
-       case CLOSE+7:
-       case CLOSE+8:
-       case CLOSE+9:
-               sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
-               p = NULL;
-               break;
-       case STAR:
-               p = "STAR";
-               break;
-       case PLUS:
-               p = "PLUS";
-               break;
-       default:
-               regerror("corrupted opcode");
-               break;
-       }
-       if (p != NULL)
-               (void) strcat(buf, p);
-       return(buf);
-}
-#endif
-
-/*
- * The following is provided for those people who do not have strcspn() in
- * their C libraries.  They should get off their butts and do something
- * about it; at least one public-domain implementation of those (highly
- * useful) string routines has been published on Usenet.
- */
-#ifdef STRCSPN
-/*
- * strcspn - find length of initial segment of s1 consisting entirely
- * of characters not from s2
- */
-
-static int
-strcspn(s1, s2)
-char *s1;
-char *s2;
-{
-       register char *scan1;
-       register char *scan2;
-       register int count;
-
-       count = 0;
-       for (scan1 = s1; *scan1 != '\0'; scan1++) {
-               for (scan2 = s2; *scan2 != '\0';)       /* ++ moved down. */
-                       if (*scan1 == *scan2++)
-                               return(count);
-               count++;
-       }
-       return(count);
-}
-#endif
diff --git a/regexp.h b/regexp.h
deleted file mode 100644 (file)
index b23d97e..0000000
--- a/regexp.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* 
-   Copyright (c) 1995-1998 by Cisco systems, 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 of the
-   software and supporting documentation, the name of Cisco Systems,
-   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 modification,
-   copying and distribution is by permission of Cisco Systems, Inc.
-
-   Cisco Systems, Inc. makes no representations about the suitability
-   of this software for any purpose.  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.
-*/
-
-/*
- * Definitions etc. for regexp(3) routines.
- *
- * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
- * not the System V one.
- */
-#define NSUBEXP  10
-typedef struct regexp {
-       char *startp[NSUBEXP];
-       char *endp[NSUBEXP];
-       char regstart;          /* Internal use only. */
-       char reganch;           /* Internal use only. */
-       char *regmust;          /* Internal use only. */
-       int regmlen;            /* Internal use only. */
-       char program[1];        /* Unwarranted chumminess with compiler. */
-} regexp;
-
-extern regexp *regcomp();
-extern int regexec();
-extern void regsub();
-extern void regerror();
diff --git a/regmagic.h b/regmagic.h
deleted file mode 100644 (file)
index 0b18b0a..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* 
-   Copyright (c) 1995-1998 by Cisco systems, 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 of the
-   software and supporting documentation, the name of Cisco Systems,
-   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 modification,
-   copying and distribution is by permission of Cisco Systems, Inc.
-
-   Cisco Systems, Inc. makes no representations about the suitability
-   of this software for any purpose.  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.
-*/
-
-/*
- * The first byte of the regexp internal "program" is actually this magic
- * number; the start node begins in the second byte.
- */
-#define        MAGIC   0234
index a458617..d46abfd 100644 (file)
--- a/report.c
+++ b/report.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
-#include <stdio.h>
 
-#ifdef AIX
+#include <stdio.h>
 #include <sys/types.h>
-#else
 #include <time.h>
+#include <sys/stat.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
 #endif
-
-#ifdef __STDC__
-#include <stdarg.h>            /* ANSI C, variable length args */
-#else
-#include <varargs.h>           /* has 'vararg' definitions */
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
 #endif
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+#ifdef HAVE_SYS_SYSLOG_H
+#include <sys/syslog.h>
+#endif
+
+#include "report.h"
+#include "utils.h"
+#include "main.h"
+
+
+/* Configurable:
+ */
+
+#define LOGFILE_DEFAULT "/var/log/tac_plus.log"
+
 
 FILE *ostream = NULL;
 
@@ -45,21 +62,30 @@ char *logfile = LOGFILE_DEFAULT;
  * All other priorities are always logged to syslog.
  */
 
+void report TAC_ARGS((int priority, const char *fmt, ...)) G_GNUC_PRINTF(2, 3);
+
 #ifdef __STDC__
+
+#include <stdarg.h>            /* ANSI C, variable length args */
 void
-report(int priority, char *fmt,...)
-#else
+report(int priority, const char *fmt,...)
+
+#else /* __STDC__ */
+
+#include <varargs.h>           /* has 'vararg' definitions */
 /* VARARGS2 */
 void
 report(priority, fmt, va_alist)
 int priority;
-char *fmt;
+const char *fmt;
 va_dcl                         /* no terminating semi-colon */
-#endif
+
+#endif /* __STDC__ */
 {
     char msg[255];             /* temporary string */
-    char *fp, *bufp, *charp;
-    int len, m, i, n;
+    const char *fp;
+    char *bufp, *charp = NULL /* GCC paranoia */;
+    int len, m = 0 /* GCC paranoia */, i, n;
     char digits[16];
     va_list ap;
 
@@ -119,8 +145,11 @@ va_dcl                             /* no terminating semi-colon */
            m = strlen(digits);
            charp = digits;
            break;
+       default:
+           syslog(LOG_ERR, "Unknown format character '%c', ignoring it", *fp);
+           continue;
        }
-           
+
        if ((len + m + 1) >= n) {
            break;
        }
@@ -143,7 +172,7 @@ va_dcl                              /* no terminating semi-colon */
 
     if (console) {
        extern int errno;
-       
+
        if (!ostream)
            ostream = fopen("/dev/console", "w");
 
@@ -152,7 +181,7 @@ va_dcl                              /* no terminating semi-colon */
                fprintf(ostream, "Error ");
            fprintf(ostream, "%s\n", msg);
        }
-       else 
+       else
            syslog(LOG_ERR, "Cannot open /dev/console errno=%d", errno);
     }
 
@@ -167,7 +196,7 @@ va_dcl                              /* no terminating semi-colon */
 
            ct[24] = '\0';
            tac_lockfd(logfile, logfd);
-           sprintf(buf, "%s [%d]: ", ct, getpid());
+           sprintf(buf, "%s [%d]: ", ct, (int) getpid());
            write(logfd, buf, strlen(buf));
            if (priority == LOG_ERR)
                write(logfd, "Error ", 6);
@@ -190,6 +219,8 @@ va_dcl                              /* no terminating semi-colon */
        syslog(priority, "%s", msg);
 }
 
+void report_hex TAC_ARGS((int priority, u_char *p, int len));
+
 /* format a hex dump for syslog */
 void
 report_hex(priority, p, len)
@@ -200,7 +231,7 @@ int len;
     char digit[10];
     int buflen;
     int i;
-    
+
     if (len <= 0)
        return;
 
@@ -225,6 +256,8 @@ int len;
 }
 
 
+void report_string TAC_ARGS((int priority, u_char *p, int len));
+
 /* format a non-null terminated string for syslog */
 void
 report_string(priority, p, len)
@@ -251,10 +284,11 @@ int len;
     report(priority, "%s", buf);
 }
 
+void tac_regerror TAC_ARGS((const char *s));
+
 void
-regerror(s)
-char *s;
+tac_regerror(s)
+const char *s;
 {
     report(LOG_ERR, "in regular expression %s", s);
 }
-
diff --git a/report.h b/report.h
new file mode 100644 (file)
index 0000000..5e5d1bb
--- /dev/null
+++ b/report.h
@@ -0,0 +1,26 @@
+#ifndef REPORT_H
+#define REPORT_H 1
+
+#include "tac_plus.h"
+
+#include <stdio.h>
+#include <sys/types.h>         /* for u_* */
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>            /* for LOG_* level values */
+#endif
+#ifdef HAVE_SYS_SYSLOG_H
+#include <sys/syslog.h>                /* for LOG_* level values */
+#endif
+
+
+extern FILE *ostream;              /* for logging to console */
+extern char *logfile;
+
+
+extern void report TAC_ARGS((int priority, const char *fmt, ...)) G_GNUC_PRINTF(2, 3);
+extern void report_hex TAC_ARGS((int priority, u_char *p, int len));
+extern void report_string TAC_ARGS((int priority, u_char *p, int len));
+extern void tac_regerror TAC_ARGS((const char *s));
+
+
+#endif /* REPORT_H */
index 68e5482..2076dc9 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
+
+#include <stdlib.h>
+
+#include "sendauth.h"
 #include "expire.h"
 #include "md5.h"
+#include "report.h"
+#include "cfgfile.h"
+#include "utils.h"
+#include "pwlib.h"
+#include "choose_authen.h"             /* for "struct authen_data" */
+#include "do_author.h"                 /* for "struct identity" */
+#include "packet.h"
+#include "main.h"
 
-static int do_sendauth_fn();
-static void outbound_chap();
 #ifdef MSCHAP
-static void outbound_mschap();
-#endif /* MSCHAP */
-void outbound_pap();
+#include "default_fn.h"
+#endif
+
+
+static int do_sendauth_fn TAC_ARGS((struct authen_data *data));
+static void outbound_chap TAC_ARGS((struct authen_data *data));
+static void outbound_pap TAC_ARGS((struct authen_data *data));
+
+#ifdef MSCHAP
+static void outbound_mschap TAC_ARGS((struct authen_data *data));
+#endif
+
+
+int sendauth_fn TAC_ARGS((struct authen_data *data));
 
 int sendauth_fn(data)
 struct authen_data *data;
 {
-    int status;
+    int retval;
     char *name, *p;
 
     name = data->NAS_id->username;
@@ -39,8 +61,9 @@ struct authen_data *data;
     if (STREQ(name, DEFAULT_USERNAME)) {
        /* This username is only valid for authorization */
        data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
+       retval = 0;
     } else {
-       status = do_sendauth_fn(data);
+       retval = do_sendauth_fn(data);
     }
 
     if (debug) {
@@ -67,28 +90,30 @@ struct authen_data *data;
        report(LOG_INFO, "%s-sendauth query for '%s' %s from %s %s",
               p,
               name && name[0] ? name : "unknown",
-              session.peer, session.port, 
+              session.peer, session.port,
               (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ?
               "accepted" : "rejected");
     }
-    return(status);
+    return (retval);
 }
 
 /*
  * For PAP we need to supply the outgoing PAP cleartext password.
- * from the config file. 
+ * from the config file.
  *
  * For CHAP, we expect an id and a challenge. We will return an MD5 hash
  * if we're successful,
  *
- * Return 0 if data->status is valid, otherwise 1 
+ * Return 0 if data->status is valid, otherwise 1
  */
 
+static int do_sendauth_fn TAC_ARGS((struct authen_data *data));
+
 static int
 do_sendauth_fn(data)
 struct authen_data *data;
 {
-    char *name, *exp_date;
+    const char *name, *exp_date;
 
     data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
 
@@ -119,9 +144,9 @@ struct authen_data *data;
 
     default:
        data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
-       report(LOG_ERR, "%s %s: %s Illegal data type for sendauth_fn", 
+       report(LOG_ERR, "%s %s: %s Illegal data type for sendauth_fn",
               session.peer, session.port, name);
-       return (0);     
+       return (0);
     }
 
     exp_date = cfg_get_expires(name, TAC_PLUS_RECURSE);
@@ -129,11 +154,13 @@ struct authen_data *data;
     return (0);
 }
 
-void
+static void outbound_pap TAC_ARGS((struct authen_data *data));
+
+static void
 outbound_pap(data)
 struct authen_data *data;
 {
-    char *secret, *p, *name;
+    const char *secret, *p, *name;
 
     name = data->NAS_id->username;
 
@@ -163,17 +190,19 @@ struct authen_data *data;
        return;
     }
 
-    data->server_data = tac_strdup(p);
-    data->server_dlen = strlen(data->server_data);
+    data->server_data = (unsigned char *) tac_strdup(p);
+    data->server_dlen = strlen((char *) data->server_data);
     data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
 }
 
+static void outbound_chap TAC_ARGS((struct authen_data *data));
+
 static void
 outbound_chap(data)
 struct authen_data *data;
 {
-    char *name, *secret, *chal, digest[MD5_LEN];
-    char *p;
+    const char *name, *secret, *chal, *p;
+    char digest[MD5_LEN];
     u_char *mdp;
     char id;
     int chal_len, inlen;
@@ -182,7 +211,7 @@ struct authen_data *data;
     name = data->NAS_id->username;
 
     if (!name) {
-       report(LOG_ERR, "%s %s: no username for outbound_chap", 
+       report(LOG_ERR, "%s %s: no username for outbound_chap",
               session.peer, session.port);
        data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
        return;
@@ -207,7 +236,7 @@ struct authen_data *data;
     /* Get the secret */
     secret = cfg_get_chap_secret(name, TAC_PLUS_RECURSE);
 
-    /* If there is no chap password for this user, see if there is 
+    /* If there is no chap password for this user, see if there is
        a global password for her that we can use */
     if (!secret) {
        secret = cfg_get_global_secret(name, TAC_PLUS_RECURSE);
@@ -235,7 +264,7 @@ struct authen_data *data;
     secret = p;
 
     /*
-     * We now have the secret, the id, and the challenge value. 
+     * We now have the secret, the id, and the challenge value.
      * Put them all together, and run them through the MD5 digest
      * algorithm. */
 
@@ -262,12 +291,13 @@ struct authen_data *data;
 
 #ifdef MSCHAP
 
+static void outbound_mschap TAC_ARGS((struct authen_data *data));
+
 static void
 outbound_mschap(data)
 struct authen_data *data;
 {
-    char *name, *secret, *chal;
-    char *p;
+    const char *name, *secret, *chal, *p;
     char id;
     int chal_len;
 
@@ -299,7 +329,7 @@ struct authen_data *data;
     /* Get the secret */
     secret = cfg_get_mschap_secret(name, TAC_PLUS_RECURSE);
 
-    /* If there is no chap password for this user, see if there is 
+    /* If there is no chap password for this user, see if there is
        a global password for her that we can use */
     if (!secret) {
        secret = cfg_get_global_secret(name, TAC_PLUS_RECURSE);
@@ -326,7 +356,7 @@ struct authen_data *data;
     secret = p;
 
     /*
-     * We now have the secret, the id, and the challenge value. 
+     * We now have the secret, the id, and the challenge value.
      * Put them all together, and run them through the MD4 digest
      * algorithm. */
 
diff --git a/sendauth.h b/sendauth.h
new file mode 100644 (file)
index 0000000..d3e2fbc
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef SENDAUTH_H
+#define SENDAUTH_H 1
+
+#include "tac_plus.h"
+
+
+struct authen_data;
+
+extern int sendauth_fn TAC_ARGS((struct authen_data *data));
+
+
+#endif /* SENDAUTH_H */
index f7f0b3c..9d8ab00 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
+
+#include "sendpass.h"
 #include "expire.h"
+#include "report.h"
+#include "utils.h"
+#include "cfgfile.h"
+#include "choose_authen.h"             /* for "struct authen_data" */
+#include "do_author.h"                 /* for "struct identity" */
+#include "main.h"
+#include "packet.h"
 
-static int
-do_sendpass_fn();
+
+static int do_sendpass_fn TAC_ARGS((struct authen_data *data));
+
+
+int sendpass_fn TAC_ARGS((struct authen_data *data));
 
 int sendpass_fn(data)
 struct authen_data *data;
@@ -48,8 +61,8 @@ struct authen_data *data;
     if (debug)
        report(LOG_INFO, "sendpass query for '%s' %s from %s %s",
               name && name[0] ? name : "unknown",
-              port && port[0] ? port : "unknown", 
-              session.peer, 
+              port && port[0] ? port : "unknown",
+              session.peer,
               (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ?
               "accepted" : "rejected");
 
@@ -63,17 +76,17 @@ struct authen_data *data;
  * Any strings pointed to by authen_data must come from the heap. They
  * will get freed by the caller.
  *
- * Return 0 if data->status is valid, otherwise 1 */
+ * Return 0 if data->status is valid, otherwise 1
+ */
+
+static int do_sendpass_fn TAC_ARGS((struct authen_data *data));
 
 static int
 do_sendpass_fn(data)
 struct authen_data *data;
 {
-    char *name;
-    char *p;
+    const char *name, *exp_date, *secret, *p;
     int expired;
-    char *exp_date;
-    char *secret;
 
     data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
 
@@ -159,8 +172,8 @@ struct authen_data *data;
            return(0);
        }
 
-       data->server_data = tac_strdup(p);
-       data->server_dlen = strlen(data->server_data);
+       data->server_data = (unsigned char *) tac_strdup(p);
+       data->server_dlen = strlen((char *) data->server_data);
        data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
        if (expired == PW_EXPIRING) {
            data->server_msg = tac_strdup("Secret will expire soon");
diff --git a/sendpass.h b/sendpass.h
new file mode 100644 (file)
index 0000000..7481cff
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef SENDPASS_H
+#define SENDPASS_H 1
+
+#include "tac_plus.h"
+
+
+struct authen_data;
+
+extern int sendpass_fn TAC_ARGS((struct authen_data *data));
+
+
+#endif /* SENDPASS_H */
index d3c9860..0a74fa8 100644 (file)
--- a/skey_fn.c
+++ b/skey_fn.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
-#ifdef SKEY
+
 #include "tac_plus.h"
+
+#ifdef SKEY
+
+#include <skey.h>
+
+#include "skey_fn.h"
 #include "expire.h"
 
+
 /* internal state variables */
 #define STATE_AUTHEN_START   0 /* no requests issued */
 #define STATE_AUTHEN_GETUSER 1 /* username has been requested */
 #define STATE_AUTHEN_GETPASS 2 /* password has been requested */
 
-#include <skey.h>
-
 struct private_data {
     struct skey skey;
     char password[MAX_PASSWD_LEN + 1];
@@ -37,6 +42,8 @@ struct private_data {
 /* Use s/key to verify a supplied password using state set up earlier
 when the username was supplied */
 
+static int skey_verify TAC_ARGS((char *passwd, struct authen_data *data)); 
+
 static int
 skey_verify(passwd, data)
 char *passwd;
@@ -73,6 +80,8 @@ struct authen_data *data;
  * Return 0 if data->status is valid, otherwise 1
  */
 
+int skey_fn TAC_ARGS((struct authen_data *data));
+
 int
 skey_fn(data)
 struct authen_data *data;
@@ -126,7 +135,7 @@ struct authen_data *data;
 
        default:
            /* something awful has happened. Give up and die */
-           report(LOG_ERR, "%s: skey_fn bad state %d", 
+           report(LOG_ERR, "%s: skey_fn bad state %d",
                   session.peer, p->state);
            return (1);
        }
@@ -173,7 +182,7 @@ struct authen_data *data;
                data->status = TAC_PLUS_AUTHEN_STATUS_GETPASS;
                p->state = STATE_AUTHEN_GETPASS;
                return (0);
-           } 
+           }
 
            data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
            report(LOG_ERR, "Cannot generate skey prompt for %s", name);
@@ -201,7 +210,7 @@ struct authen_data *data;
 
     default:
        data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
-       report(LOG_ERR, "%s: Bogus service value %d from packet", 
+       report(LOG_ERR, "%s: Bogus service value %d from packet",
               session.peer, data->service);
        break;
     }
@@ -222,12 +231,9 @@ struct authen_data *data;
        return (1);
     }
 }
-#else /* SKEY */
 
-/* The following code is not needed or used. It exists solely to
-   prevent compilers from "helpfully" complaining that this source
-   file is empty, which upsets novices building the software */
+#else /* SKEY */
 
-static int dummy = 0;
+TAC_SOURCEFILE_EMPTY
 
 #endif /* SKEY */
diff --git a/skey_fn.h b/skey_fn.h
new file mode 100644 (file)
index 0000000..1b7474a
--- /dev/null
+++ b/skey_fn.h
@@ -0,0 +1,14 @@
+#ifndef SKEY_FN_H
+#define SKEY_FN_H 1
+
+#include "tac_plus.h"
+
+#ifdef SKEY
+
+
+extern int skey_fn TAC_ARGS((struct authen_data *data));
+
+
+#endif /* SKEY */
+
+#endif /* SKEY_FN_H */
diff --git a/stamp-h b/stamp-h
deleted file mode 100644 (file)
index 9788f70..0000000
--- a/stamp-h
+++ /dev/null
@@ -1 +0,0 @@
-timestamp
index bf1b215..4f088a0 100644 (file)
--- a/tac_pam.c
+++ b/tac_pam.c
@@ -1,12 +1,10 @@
-#ifdef USE_PAM
-
 /* tac_pam.auth.c
- * A simple pam authentication  routine written by 
+ * A simple pam authentication  routine written by
  * Max Liccardo <ravel@tiscalinet.it>
  * PAM_RUSER=username/rem_addr.
  */
 
- /*
+/*
     This program was contributed by Shane Watts
     [modifications by AGM]
 
     # check authorization
     check_user   auth       required     /usr/lib/security/pam_unix_auth.so
     check_user   account    required     /usr/lib/security/pam_unix_acct.so
-   */
+*/
+
+
+#include "tac_plus.h"
+
+#ifdef USE_PAM
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <security/pam_appl.h>
-#include "tac_plus.h"
 
-typedef struct
-{
-       char *UserName;
-       char *Passwd;
+#include "tac_pam.h"
+#include "report.h"
+#include "utils.h"
+#include "choose_authen.h"             /* for "struct authen_data" */
+#include "do_author.h"                 /* for "struct identity" */
+#include "main.h"
+
+
+typedef struct {
+    const char *UserName;
+    const char *Passwd;
 } UserCred;
 
 
-static int fconv(int num_msg, const struct pam_message **msg,
-               struct pam_response **resp,void *appdata_ptr)
+static int fconv TAC_ARGS((int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr));
+
+static int fconv(num_msg, msg, resp, appdata_ptr)
+int num_msg;
+const struct pam_message **msg;
+struct pam_response **resp;
+void *appdata_ptr;
 {
-       int             i;
-    UserCred   *lUserCred;
+    int i;
+    UserCred *lUserCred;
 
 
-       lUserCred  = appdata_ptr;
+    lUserCred = appdata_ptr;
 
-       if(lUserCred == NULL)
-       {
-               report(LOG_ERR,"argh....maybe a SunOs 5.6 ???");
-               return(PAM_CONV_ERR);
-       }
+    if(lUserCred == NULL) {
+       report(LOG_ERR,"argh....maybe a SunOs 5.6 ???");
+       return(PAM_CONV_ERR);
+    }
+
+    *resp = (struct pam_response *) tac_malloc(num_msg * sizeof(struct pam_response));
+
+    for (i=0; i<num_msg; i++) {
+       switch(msg[i]->msg_style) {
+
+       case PAM_PROMPT_ECHO_OFF:
+           resp[i]->resp = strdup(lUserCred->Passwd);
+           break;
 
+       case PAM_PROMPT_ECHO_ON:
+           resp[i]->resp = strdup(lUserCred->UserName);
+           break;
 
-       *resp = (struct pam_response *) calloc(num_msg,sizeof(struct pam_response));    
-       
-       for(i=0;i<num_msg;i++)
-       {
-               switch(msg[i]->msg_style)
-               {
-                       case PAM_PROMPT_ECHO_OFF:
-                resp[i]->resp = strdup(lUserCred->Passwd);
-                break;
-                       
-                       case PAM_PROMPT_ECHO_ON:
-                resp[i]->resp = strdup(lUserCred->UserName);
-                break;         
-                       
-                       default:
-                                report(LOG_DEBUG,"conv default");
-                       break;
-               }
-               resp[i]->resp_retcode = 0;
+       default:
+           resp[i]->resp = NULL;
+           report(LOG_DEBUG,"conv default");
+           break;
        }
+       resp[i]->resp_retcode = 0;
+    }
 
-       return(PAM_SUCCESS);
+    return(PAM_SUCCESS);
 }
 
 
-
+int tac_pam_auth TAC_ARGS((const char *aszUserName, const char *aszPassword, struct authen_data *data, const char *aszService));
 
 int
-tac_pam_auth(char *aszUserName,char *aszPassword,struct authen_data *data,char *aszService)
+tac_pam_auth(aszUserName, aszPassword, data, aszService)
+const char *aszUserName;
+const char *aszPassword;
+struct authen_data *data;
+const char *aszService;
 {
-       pam_handle_t    *pamh=NULL;
-       int                     retval;
-       char                    *lpszRemoteUser;                                /* Username/NAC address */
+    pam_handle_t *pamh = NULL;
+    int retval;
+    char *lpszRemoteUser;                      /* Username/NAC address */
     struct pam_conv s_conv;
-       UserCred                s_UserCred;
+    UserCred s_UserCred;
 
 
-       s_UserCred.UserName = aszUserName;
-    s_UserCred.Passwd  = aszPassword;
+    s_UserCred.UserName = aszUserName;
+    s_UserCred.Passwd   = aszPassword;
 
-       s_conv.conv = fconv;
+    s_conv.conv = fconv;
     s_conv.appdata_ptr = (void *) &s_UserCred;
 
 
-       if((lpszRemoteUser = calloc(strlen(aszUserName)+strlen(data->NAS_id->NAC_address)+2,sizeof(char))) == NULL)
-       {
-        report(LOG_ERR,"cannot malloc");
-               return(1);
-       }
+    lpszRemoteUser = tac_malloc((strlen(aszUserName)+1+strlen(data->NAS_id->NAC_address)+1) * sizeof(char));
 
-       retval = pam_start(aszService,aszUserName , &s_conv, &pamh);
+    retval = pam_start(aszService,aszUserName , &s_conv, &pamh);
 
-       if (retval != PAM_SUCCESS)
-       {
-           report(LOG_ERR, "cannot start pam-authentication"); 
-               pamh = NULL;
-               return(1);
+    if (retval != PAM_SUCCESS) {
+       report(LOG_ERR, "cannot start pam-authentication");
+       free(lpszRemoteUser);
+       pamh = NULL;
+       return(1);
     }
 
     sprintf(lpszRemoteUser,"%s:%s",aszUserName,data->NAS_id->NAC_address);
@@ -110,19 +122,19 @@ tac_pam_auth(char *aszUserName,char *aszPassword,struct authen_data *data,char *
     pam_set_item(pamh,PAM_RHOST,data->NAS_id->NAS_name);
     pam_set_item(pamh,PAM_TTY,data->NAS_id->NAS_port);
 
-       free(lpszRemoteUser);
+    free(lpszRemoteUser);
 
-    retval = pam_authenticate(pamh,0);                                 /* is user really user? */
+    retval = pam_authenticate(pamh,0);                 /* is user really user? */
 
     if(retval != PAM_SUCCESS)
-       report(LOG_ERR, "%s",pam_strerror(pamh,retval));
-    
-    if (pam_end(pamh,retval) != PAM_SUCCESS) {     /* close Linux-PAM */
-               pamh = NULL;
-               return(1);
-       }
+       report(LOG_ERR, "%s",pam_strerror(pamh,retval));
+
+    if (pam_end(pamh,retval) != PAM_SUCCESS) {         /* close Linux-PAM */
+       pamh = NULL;
+       return(1);
+    }
 
-    return ( retval == PAM_SUCCESS ? 0:1 );       /* indicate success */
+    return ( retval == PAM_SUCCESS ? 0:1 );            /* indicate success */
 }
 
 
@@ -130,41 +142,40 @@ tac_pam_auth(char *aszUserName,char *aszPassword,struct authen_data *data,char *
  * Devrim SERAL <devrim@tef.gazi.edu.tr>
 */
 
+int tac_pam_authorization TAC_ARGS((const char *aszUserName, struct author_data *data, const char *aszService));
+
 int
-tac_pam_authorization (char *aszUserName,struct author_data *data,char *aszService)
+tac_pam_authorization(aszUserName, data, aszService)
+const char *aszUserName;
+struct author_data *data;
+const char *aszService;
 {
-       pam_handle_t    *pamh=NULL;
-       int                     retval;
-       char                    *lpszRemoteUser;                                /* Username/NAC address */
-       struct pam_conv s_conv;
-       UserCred                s_UserCred;
+    pam_handle_t *pamh = NULL;
+    int retval;
+    char *lpszRemoteUser;                      /* Username/NAC address */
+    struct pam_conv s_conv;
+    UserCred s_UserCred;
 
 
-       s_UserCred.UserName = aszUserName;
+    s_UserCred.UserName = aszUserName;
 
-       s_conv.conv = fconv;
-        s_conv.appdata_ptr = (void *) &s_UserCred;
+    s_conv.conv = fconv;
+    s_conv.appdata_ptr = (void *) &s_UserCred;
 
-       if (aszService== NULL) 
-       {
+    if (aszService== NULL) {
        report(LOG_ERR,"Service Name doesn't available So authorize him");
-                return(0);
-        }
-       
-
-       if((lpszRemoteUser = calloc(strlen(aszUserName)+strlen(data->id->NAC_address)+2,sizeof(char))) == NULL)
-       {
-        report(LOG_ERR,"cannot malloc");
-               return(1);
-       }
+       return(0);
+    }
+
+    lpszRemoteUser = tac_malloc((strlen(aszUserName)+strlen(data->id->NAC_address)+2) * sizeof(char));
 
-       retval = pam_start(aszService,aszUserName , &s_conv, &pamh);
+    retval = pam_start(aszService,aszUserName , &s_conv, &pamh);
 
-       if (retval != PAM_SUCCESS)
-       {
-           report(LOG_ERR, "cannot start pam-authentication"); 
-               pamh = NULL;
-               return(1);
+    if (retval != PAM_SUCCESS) {
+       report(LOG_ERR, "cannot start pam-authentication");
+       free(lpszRemoteUser);
+       pamh = NULL;
+       return(1);
     }
 
     sprintf(lpszRemoteUser,"%s:%s",aszUserName,data->id->NAC_address);
@@ -173,27 +184,27 @@ tac_pam_authorization (char *aszUserName,struct author_data *data,char *aszServi
     pam_set_item(pamh,PAM_RHOST,data->id->NAS_name);
     pam_set_item(pamh,PAM_TTY,data->id->NAS_port);
 
-       free(lpszRemoteUser);
-
-    retval = pam_acct_mgmt(pamh, 0); /* Is user permit to gain access system */
-    
-    if(retval != PAM_SUCCESS)
-        report(LOG_ERR, "Pam Account Managment:%s",pam_strerror(pamh,retval));
-    else 
-       if (debug & DEBUG_AUTHOR_FLAG)
-        report(LOG_DEBUG, "PAM authorization allow user");    
-    
-   if (pam_end(pamh,retval) != PAM_SUCCESS) {     /* close Linux-PAM */
-               pamh = NULL;
-               return(1);
-       }
+    free(lpszRemoteUser);
 
-    return ( retval == PAM_SUCCESS ? 0:1 );       /* indicate success */
-}
+    retval = pam_acct_mgmt(pamh, 0);           /* Is user permit to gain access system */
 
+    if (retval != PAM_SUCCESS)
+       report(LOG_ERR, "Pam Account Managment:%s",pam_strerror(pamh,retval));
+    else {
+       if (debug & DEBUG_AUTHOR_FLAG)
+           report(LOG_DEBUG, "PAM authorization allow user");
+    }
 
-#endif /* USE_PAM */
+   if (pam_end(pamh,retval) != PAM_SUCCESS) {          /* close Linux-PAM */
+       pamh = NULL;
+       return(1);
+    }
 
+    return ( retval == PAM_SUCCESS ? 0:1 );            /* indicate success */
+}
 
+#else /* USE_PAM */
 
+TAC_SOURCEFILE_EMPTY
 
+#endif /* USE_PAM */
diff --git a/tac_pam.h b/tac_pam.h
new file mode 100644 (file)
index 0000000..c8306ba
--- /dev/null
+++ b/tac_pam.h
@@ -0,0 +1,18 @@
+#ifndef TAC_PAM_H
+#define TAC_PAM_H 1
+
+#include "tac_plus.h"
+
+#ifdef USE_PAM
+
+
+struct authen_data;
+struct author_data;
+
+extern int tac_pam_auth TAC_ARGS((const char *aszUserName, const char *aszPassword, struct authen_data *data, const char *aszService));
+extern int tac_pam_authorization TAC_ARGS((const char *aszUserName, struct author_data *data, const char *aszService));
+
+
+#endif /* USE_PAM */
+
+#endif /* TAC_PAM_H */
index 579c7ee..69f3502 100644 (file)
@@ -24,7 +24,7 @@ tac_plus \- tacacs plus daemon
 .SH DESCRIPTION
 tac_plus listens on tcp port
 .B
-49 
+49
 and provides Cisco systems routers and access servers with
 authentication, authorisation and accounting services.
 .LP
@@ -42,7 +42,7 @@ if possible, containing its process id.
 Specify the configuration file name. A configuration file is
 .B
 always required.
-.TP 
+.TP
 .B \-P
 Just parse the configuration file, echoing it to standard output while
 parsing, and then exit. Used for debugging configuration file syntax.
@@ -50,14 +50,14 @@ parsing, and then exit. Used for debugging configuration file syntax.
 .B \-t
 Log all informational, debugging or error messages to
 .B
-/dev/console 
+/dev/console
 in addition to logging to syslogd. Useful for debugging.
 .IP
 .B
-NOTE: 
+NOTE:
 messages at priority LOG_DEBUG are never logged to syslog, Use the
 .B
-\-t, \-d or \-g 
+\-t, \-d or \-g
 flags to see all messages produced by tac_plus.  These flags
 should not be used in normal service.
 .TP
@@ -77,7 +77,7 @@ logging, instead of just using its ip address.
 .B \-p <port>
 Use the specified port number instead of the default port
 .B
-49 
+49
 for incoming tcp connections. Note that this changes the name of the
 pid file created by the daemon, which will append the port number to
 the file name if the port is not the default one.
@@ -85,25 +85,25 @@ the file name if the port is not the default one.
 .B \-d <level>
 Switch on debugging and write debug output into
 .B
-/var/log/tac_plus.log. 
+/var/log/tac_plus.log.
 
 See the definitions of debugging flags at the bottom of tac_plus.h for
 available flags and their meanings.  Most flags cause extra messages
-to be sent to 
+to be sent to
 .B
-/var/log/tac_plus.log 
-and also to 
+/var/log/tac_plus.log
+and also to
 .B
 syslog.
 .IP
 .B
-NOTE: 
-The 
+NOTE:
+The
 .B
-\-g 
+\-g
 flag will cause these messages to also appear on stdout.  The
 .B
-\-t 
+\-t
 flag will cause these messages to also be written to /dev/console.
 .IP
 The values represent bits, so they can be added together. Currently
@@ -111,6 +111,8 @@ the following values are recognised:
 .nf
 
 Value   Meaning
+2       config file parsing debugging
+4       process forking debugging
 8       authorisation debugging
 16      authentication debugging
 32      password file processing debugging
@@ -120,6 +122,11 @@ Value   Meaning
 512     encryption/decryption
 1024    MD5 hash algorithm debugging
 2048    very low level encryption/decryption
+4096    config file memory allocation freeing
+8192    pre/post authorization program arguments substitutions
+16384   config file expressions with entity tracing
+32768   maxsess (concurrent logins) debugging
+65536   file locking progress reporting
 
 .fi
 .TP
diff --git a/tac_plus.c b/tac_plus.c
deleted file mode 100644 (file)
index cf0ffd8..0000000
+++ /dev/null
@@ -1,734 +0,0 @@
-/*
- * tac_plus.c
- *
- * TACACS_PLUS daemon suitable for using on Un*x systems.
- *
- * October 1994, Lol Grant
- *
- * Copyright (c) 1994-1998 by Cisco systems, 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 of the
- * software and supporting documentation, the name of Cisco Systems,
- * 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 modification,
- * copying and distribution is by permission of Cisco Systems, Inc.
-
- * Cisco Systems, Inc. makes no representations about the suitability
- * of this software for any purpose.  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 "tac_plus.h"
-#include "sys/wait.h"
-#include "signal.h"
-
-static int standalone  = 1; /* running standalone (1) or under inetd (0) */
-static int initialised = 0; /* data structures have been allocated */
-int sendauth_only      = 0; /* don't respond to sendpass requests */
-int debug              = 0; /* debugging flags */
-int port               = 0; /* port we're listening on */
-int console            = 0; /* write all syslog messages to console */
-int parse_only         = 0; /* exit after verbose parsing */
-int single             = 0; /* single thread (for debugging) */
-int wtmpfd            = 0; /* for wtmp file logging */
-char *wtmpfile         = NULL;
-
-struct timeval started_at;
-
-struct session session;     /* session data */
-
-static char pidfilebuf[75]; /* holds current name of the pidfile */
-
-void start_session();
-
-#ifndef REAPCHILD
-static
-#ifdef VOIDSIG
-void 
-#else
-int
-#endif /* VOIDSIG */
-reapchild()
-{
-#ifdef UNIONWAIT
-    union wait status;
-#else
-    int status;
-#endif
-    int pid;
-
-    for (;;) {
-       pid = wait3(&status, WNOHANG, 0);
-       if (pid <= 0)
-           return;
-       if (debug & DEBUG_FORK_FLAG)
-           report(LOG_DEBUG, "%d reaped", pid);
-    }
-}
-#endif /* REAPCHILD */
-
-static void
-die(signum)
-int signum;
-{
-    report(LOG_INFO, "Received signal %d, shutting down", signum);
-    unlink(pidfilebuf);
-    tac_exit(0);
-}
-
-static void
-init()
-{
-    if (initialised)
-       cfg_clean_config();    
-
-    report(LOG_INFO, "Reading config");
-
-    session.acctfile = tac_strdup("/var/log/acctfile");
-    
-    if (!session.cfgfile) {
-       report(LOG_ERR, "no config file specified");
-       tac_exit(1);
-    }
-    
-    /* read the config file */
-    if (cfg_read_config(session.cfgfile)) {
-       report(LOG_ERR, "Parsing %s", session.cfgfile);
-       fprintf(stderr,"Config file not found!!\n");
-       tac_exit(1);
-    }
-
-    initialised++;
-
-    report(LOG_INFO, "Version %s Initialized %d", VERSION, initialised);
-
-}
-
-static void
-handler(signum)
-int signum;
-{
-    report(LOG_INFO, "Received signal %d", signum);
-    init();
-#ifdef REARMSIGNAL
-    signal(SIGUSR1, handler);
-    signal(SIGHUP, handler);
-#endif REARMSIGNAL
-}
-
-/*
- * Return a socket bound to an appropriate port number/address. Exits
- * the program on failure */
-
-get_socket()
-{
-    int s;
-    struct sockaddr_in sin;
-    struct servent *sp;
-    int on = 1;
-
-    bzero((char *) &sin, sizeof(sin));
-
-    if (port) {
-       sin.sin_port = htons(port);
-    } else {
-       sp = getservbyname("tacacs", "tcp");
-       if (sp)
-           sin.sin_port = sp->s_port;
-       else {
-           report(LOG_ERR, "Cannot find socket port");
-           tac_exit(1);
-       }
-    }
-
-    sin.sin_family = AF_INET;
-    sin.sin_addr.s_addr = htonl(INADDR_ANY);
-
-    s = socket(AF_INET, SOCK_STREAM, 0);
-
-    if (s < 0) {
-       console++;
-       report(LOG_ERR, "get_socket: socket: %s", sys_errlist[errno]);
-       tac_exit(1);
-    }
-#ifdef SO_REUSEADDR
-       if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
-                      sizeof(on)) < 0)
-           perror("setsockopt - SO_REUSEADDR");
-#endif                         /* SO_REUSEADDR */
-
-    if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
-       console++;
-       report(LOG_ERR, "get_socket: bind %d %s",
-              ntohs(sin.sin_port),
-              sys_errlist[errno]);
-       tac_exit(1);
-    }
-    return (s);
-}
-
-static void
-open_logfile()
-{
-#ifdef LOG_LOCAL6
-    openlog("tac_plus", LOG_PID, LOG_LOCAL6);
-#else
-    openlog("tac_plus", LOG_PID);
-#endif
-    setlogmask(LOG_UPTO(LOG_DEBUG));
-}
-
-/*
- * main
- *
- * We will eventually be called from inetd or via the rc scripts directly
- * Parse arguments and act appropiately.
- */
-
-main(argc, argv)
-int argc;
-char **argv;
-{
-    extern char *optarg;
-    int childpid;
-    int c;
-    int s;
-    FILE *fp;
-    int lookup_peer = 0;
-
-    debug = 0;                 /* no debugging */
-    standalone = 1;                    /* standalone */
-    single = 0;                        /* single threaded */
-
-    /* initialise global session data */
-    bzero(&session, sizeof(session));
-    session.peer = tac_strdup("unknown");
-
-    open_logfile();
-
-#ifdef TAC_PLUS_PORT
-    port = TAC_PLUS_PORT;
-#endif
-
-    if (argc <= 1) {
-       fprintf(stderr, "Usage: tac_plus -C <configuration file>\n");
-       fprintf(stderr, "\t[ -t ] [ -P ] [ -g ] [ -p <port> ]\n");
-       fprintf(stderr, "\t[ -d <debug level> ] [ -i ] [ -v ] [ -s ]\n");
-       fprintf(stderr, "\t[ -l logfile ]");
-#ifdef MAXSESS
-       fprintf(stderr, " [ -w whologfile ]");
-#endif
-       fprintf(stderr, "\n");
-       tac_exit(1);
-    }
-
-    while ((c = getopt(argc, argv, "td:C:ip:PgvsLl:w:u:")) != EOF)
-       switch (c) {
-       case 'L':               /* lookup peer names via DNS */
-           lookup_peer++;
-           break;
-       case 's':               /* don't respond to sendpass */
-           sendauth_only++;
-           break;
-       case 'v':               /* print version and exit */
-           version();
-           tac_exit(1);
-       case 't':
-           console++;          /* log to console too */
-           break;
-       case 'P':               /* Parse config file only */
-           parse_only++;
-           break;
-       case 'g':               /* single threaded */
-           single++;
-           break;
-       case 'p':               /* port */
-           port = atoi(optarg);
-           break;
-       case 'd':               /* debug */
-           debug = atoi(optarg);
-           break;
-       case 'C':               /* config file name */
-           session.cfgfile = tac_strdup(optarg);
-           break;
-       case 'i':               /* stand-alone */
-           standalone = 0;
-           break;
-       case 'l':               /* logfile */
-           logfile = tac_strdup(optarg);
-           break;
-#ifdef MAXSESS
-       case 'w':               /* wholog file */
-           wholog = tac_strdup(optarg);
-           break;
-#endif
-       case 'u':
-           wtmpfile = tac_strdup(optarg);
-           break;
-
-       default:
-           fprintf(stderr, "%s: bad switch %c\n", argv[0], c);
-           tac_exit(1);
-       }
-
-    if (geteuid() != 0) {
-       fprintf(stderr, "Warning, not running as uid 0\n");
-       fprintf(stderr, "Tac_plus is usually run as root\n");
-    }
-
-    parser_init();
-
-    init();
-
-    signal(SIGUSR1, handler);
-    signal(SIGHUP, handler);
-    signal(SIGTERM, die);
-    signal(SIGPIPE, SIG_IGN);
-
-    if (parse_only)
-       tac_exit(0);
-
-    if (debug)
-       report(LOG_DEBUG, "tac_plus server %s starting", VERSION);
-
-    if (!standalone) {
-       /* running under inetd */
-       struct sockaddr_in name;
-       int name_len;
-       int on = 1;
-
-       name_len = sizeof(name);
-
-       session.sock = 0;
-       if (getpeername(session.sock, (struct sockaddr *) &name, &name_len)) {
-           report(LOG_ERR, "getpeername failure %s", sys_errlist[errno]);
-       } else {
-           struct hostent *hp;
-           hp = gethostbyaddr((char *) &name.sin_addr.s_addr,
-                              sizeof(name.sin_addr.s_addr), AF_INET);
-           if (session.peer) {
-               free(session.peer);
-           }
-           session.peer = tac_strdup(hp ? hp->h_name : 
-                                 (char *) inet_ntoa(name.sin_addr));
-       }
-#ifdef FIONBIO
-       if (ioctl(session.sock, FIONBIO, &on) < 0) {
-           report(LOG_ERR, "ioctl(FIONBIO) %s", sys_errlist[errno]);
-           tac_exit(1);
-       }
-#endif
-       start_session();
-       tac_exit(0);
-    }
-
-    if (!single) {
-       /* Running standalone. Background ourselves, let go of controlling tty */
-
-#ifdef SIGTTOU
-       signal(SIGTTOU, SIG_IGN);
-#endif
-#ifdef SIGTTIN
-       signal(SIGTTIN, SIG_IGN);
-#endif
-#ifdef SIGTSTP
-       signal(SIGTSTP, SIG_IGN);
-#endif
-       
-       signal(SIGHUP, SIG_IGN);
-    
-       if ((childpid = fork()) < 0)
-           report(LOG_ERR, "Can't fork first child");
-       else if (childpid > 0)
-           exit(0);            /* parent */
-
-       if (debug)
-           report(LOG_DEBUG, "Backgrounded");
-
-#ifndef REAPCHILD
-
-#ifdef LINUX
-       if (setpgrp() == -1)
-#else /* LINUX */
-       if (setpgrp(0, getpid()) == -1)
-#endif /* LINUX */
-           report(LOG_ERR, "Can't change process group");
-       
-       c = open("/dev/tty", O_RDWR);
-       if (c >= 0) {
-           ioctl(c, TIOCNOTTY, (char *) 0);
-           (void) close(c);
-       }
-       signal(SIGCHLD, reapchild);
-
-#else /* REAPCHILD */
-
-       if (setpgrp() == 1)
-           report(LOG_ERR, "Can't change process group");
-
-       signal(SIGHUP, SIG_IGN);
-
-       if ((childpid = fork()) < 0)
-           report(LOG_ERR, "Can't fork second child");
-       else if (childpid > 0)
-           exit(0);
-    
-       if (debug & DEBUG_FORK_FLAG)
-           report(LOG_DEBUG, "Forked grandchild");
-
-       signal(SIGCHLD, SIG_IGN);
-
-#endif /* REAPCHILD */
-
-       closelog(); /* some systems require this */
-
-       for (c = 0; c < getdtablesize(); c++)
-           (void) close(c);
-
-       /* make sure we can still log to syslog now we've closed everything */
-       open_logfile();
-
-    } /* ! single threaded */
-    
-    ostream = NULL;
-    /* chdir("/"); */
-    umask(0);
-    errno = 0;
-
-    s = get_socket();
-   
-#ifndef SOMAXCONN
-#ifdef LINUX
-#define SOMAXCONN 128
-#else 
-#define SOMAXCONN 5
-#endif /* LINUX */
-#endif /* SOMAXCONN */
-
-    if (listen(s, SOMAXCONN) < 0) {
-       console++;
-       report(LOG_ERR, "listen: %s", sys_errlist[errno]);
-       tac_exit(1);
-    }
-
-    if (port == TAC_PLUS_PORT) {
-       strcpy(pidfilebuf, TACPLUS_PIDFILE);
-    } else {
-       sprintf(pidfilebuf, "%s.%d", TACPLUS_PIDFILE, port);
-    }
-
-    /* write process id to pidfile */
-    if ((fp = fopen(pidfilebuf, "w")) != NULL) {
-       fprintf(fp, "%d\n", getpid());
-       fclose(fp);
-    } else 
-       report(LOG_ERR, "Cannot write pid to %s %s", 
-              pidfilebuf, sys_errlist[errno]);
-
-#ifdef TACPLUS_GROUPID
-    if (setgid(TACPLUS_GROUPID))
-       report(LOG_ERR, "Cannot set group id to %d %s", 
-              TACPLUS_GROUPID, sys_errlist[errno]);
-#endif
-
-#ifdef TACPLUS_USERID
-    if (setuid(TACPLUS_USERID)) 
-       report(LOG_ERR, "Cannot set user id to %d %s", 
-              TACPLUS_USERID, sys_errlist[errno]);
-#endif
-
-#ifdef MAXSESS
-    maxsess_loginit();
-#endif /* MAXSESS */
-
-    report(LOG_DEBUG, "uid=%d euid=%d gid=%d egid=%d s=%d",
-          getuid(), geteuid(), getgid(), getegid(), s);
-
-    for (;;) {
-       int pid;
-       struct sockaddr_in from;
-       int from_len;
-       int newsockfd;
-       struct hostent *hp = NULL;
-
-       bzero((char *) &from, sizeof(from));
-       from_len = sizeof(from);
-
-       newsockfd = accept(s, (struct sockaddr *) &from, &from_len);
-
-       if (newsockfd < 0) {
-           if (errno == EINTR)
-               continue;
-
-           report(LOG_ERR, "accept: %s", sys_errlist[errno]);
-           continue;
-       }
-
-       if (lookup_peer) {
-           hp = gethostbyaddr((char *) &from.sin_addr.s_addr,
-                              sizeof(from.sin_addr.s_addr), AF_INET);
-       }
-
-       if (session.peer) {
-           free(session.peer);
-       }
-       session.peer = tac_strdup(hp ? hp->h_name : 
-                                 (char *) inet_ntoa(from.sin_addr));
-
-       if (debug & DEBUG_PACKET_FLAG)
-           report(LOG_DEBUG, "session request from %s sock=%d", 
-                  session.peer, newsockfd);
-
-       if (!single) {
-           pid = fork();
-
-           if (pid < 0) {
-               report(LOG_ERR, "fork error");
-               tac_exit(1);
-           }
-       } else {
-           pid = 0;
-       }
-
-       if (pid == 0) {
-           /* child */
-           if (!single)
-               close(s);
-           session.sock = newsockfd;
-           start_session();
-           shutdown(session.sock, 2);
-           close(session.sock);
-           if (!single)
-               tac_exit(0);
-       } else {
-           if (debug & DEBUG_FORK_FLAG)
-               report(LOG_DEBUG, "forked %d", pid);
-           /* parent */
-           close(newsockfd);
-       }
-    }
-}
-
-#ifdef GETDTABLESIZE
-int 
-getdtablesize()
-{
-    return(_NFILE);
-}
-#endif /* GETDTABLESIZE */
-
-/* Make sure version number is kosher. Return 0 if it is */
-int
-bad_version_check(pak)
-u_char *pak;
-{
-    HDR *hdr = (HDR *) pak;
-    
-    switch (hdr->type) {
-    case TAC_PLUS_AUTHEN:
-       /* 
-        * Let authen routines take care of more sophisticated version
-        * checking as its now a bit involved. 
-        */
-       return(0);
-
-    case TAC_PLUS_AUTHOR:
-    case TAC_PLUS_ACCT:
-       if (hdr->version != TAC_PLUS_VER_0) {
-           send_error_reply(hdr->type, "Illegal packet version");
-           return(1);
-       }
-       return(0);
-
-    default:
-       return(1);
-    }
-}
-
-/*
- * Determine the packet type, read the rest of the packet data,
- * decrypt it and call the appropriate service routine.
- *
- */
-
-void
-start_session()
-{
-    u_char *pak, *read_packet();
-    HDR *hdr;
-    void authen();
-
-    session.seq_no = 0;
-    session.aborted = 0;
-    session.version = 0;
-
-    pak = read_packet();
-    if (!pak) {
-       return;
-    }
-
-    if (debug & DEBUG_PACKET_FLAG) {
-       report(LOG_DEBUG, "validation request from %s", session.peer);
-       dump_nas_pak(pak);
-    }
-    hdr = (HDR *) pak;
-
-    session.session_id = ntohl(hdr->session_id);
-
-    /* Do some version checking */
-    if (bad_version_check(pak)) {
-       free(pak);
-       return;
-    }
-
-    switch (hdr->type) {
-    case TAC_PLUS_AUTHEN:
-       authen(pak);
-       free(pak);
-       return;
-
-    case TAC_PLUS_AUTHOR:
-       author(pak);
-       free(pak);
-       return;
-
-    case TAC_PLUS_ACCT:
-       accounting(pak);
-       return;
-
-    default:
-       /* Note: can't send error reply if type is unknown */
-       report(LOG_ERR, "Illegal type %d in received packet", hdr->type);
-       free(pak);
-       return;
-    }
-}
-
-version()
-{
-    fprintf(stdout, "tac_plus version %s\n", VERSION);
-#ifdef AIX
-    fprintf(stdout,"AIX\n");
-#endif
-#ifdef ARAP_DES
-    fprintf(stdout,"ARAP_DES\n");
-#endif
-#ifdef BSDI
-    fprintf(stdout,"BSDI\n");
-#endif
-#ifdef CONST_SYSERRLIST
-    fprintf(stdout,"CONST_SYSERRLIST\n");
-#endif
-#ifdef DEBUG
-    fprintf(stdout,"DEBUG\n");
-#endif
-#ifdef DES_DEBUG
-    fprintf(stdout,"DES_DEBUG\n");
-#endif
-#ifdef FIONBIO
-    fprintf(stdout,"FIONBIO\n");
-#endif
-#ifdef FREEBSD
-    fprintf(stdout,"FREEBSD\n");
-#endif
-#ifdef GETDTABLESIZE
-    fprintf(stdout,"GETDTABLESIZE\n");
-#endif
-#ifdef HPUX
-    fprintf(stdout,"HPUX\n");
-#endif
-#ifdef LINUX
-    fprintf(stdout,"LINUX\n");
-#endif
-#ifdef LITTLE_ENDIAN
-    fprintf(stdout,"LITTLE_ENDIAN\n");
-#endif
-#ifdef LOG_LOCAL6
-    fprintf(stdout,"LOG_LOCAL6\n");
-#endif
-#ifdef MAXSESS
-    fprintf(stdout,"MAXSESS\n");
-#endif
-#ifdef MIPS
-    fprintf(stdout,"MIPS\n");
-#endif
-#ifdef NEED_BZERO
-    fprintf(stdout,"NEED_BZERO\n");
-#endif
-#ifdef NETBSD
-    fprintf(stdout,"NETBSD\n");
-#endif
-#ifdef NO_PWAGE
-    fprintf(stdout,"NO_PWAGE\n");
-#endif
-#ifdef REAPCHILD
-    fprintf(stdout,"REAPCHILD\n");
-#endif
-#ifdef REARMSIGNAL
-    fprintf(stdout,"REARMSIGNAL\n");
-#endif
-#ifdef SHADOW_PASSWORDS
-    fprintf(stdout,"SHADOW_PASSWORDS\n");
-#endif
-#ifdef SIGTSTP
-    fprintf(stdout,"SIGTSTP\n");
-#endif
-#ifdef SIGTTIN
-    fprintf(stdout,"SIGTTIN\n");
-#endif
-#ifdef SIGTTOU
-    fprintf(stdout,"SIGTTOU\n");
-#endif
-#ifdef SKEY
-    fprintf(stdout,"SKEY\n");
-#endif
-#ifdef SOLARIS
-    fprintf(stdout,"SOLARIS\n");
-#endif
-#ifdef SO_REUSEADDR
-    fprintf(stdout,"SO_REUSEADDR\n");
-#endif
-#ifdef STDLIB_MALLOC
-    fprintf(stdout,"STDLIB_MALLOC\n");
-#endif
-#ifdef STRCSPN
-    fprintf(stdout,"STRCSPN\n");
-#endif
-#ifdef SYSLOG_IN_SYS
-    fprintf(stdout,"SYSLOG_IN_SYS\n");
-#endif
-#ifdef SYSV
-    fprintf(stdout,"SYSV\n");
-#endif
-#ifdef TACPLUS_GROUPID
-    fprintf(stdout,"TACPLUS_GROUPID\n");
-#endif
-#ifdef TAC_PLUS_PORT
-    fprintf(stdout,"TAC_PLUS_PORT\n");
-#endif
-#ifdef TACPLUS_USERID
-    fprintf(stdout,"TACPLUS_USERID\n");
-#endif
-#ifdef TRACE
-    fprintf(stdout,"TRACE\n");
-#endif
-#ifdef UNIONWAIT
-    fprintf(stdout,"UNIONWAIT\n");
-#endif
-#ifdef VOIDSIG
-    fprintf(stdout,"VOIDSIG\n");
-#endif
-#ifdef _BSD1
-    fprintf(stdout,"_BSD1\n");
-#endif
-#ifdef _BSD_INCLUDES
-    fprintf(stdout,"_BSD_INCLUDES\n");
-#endif
-#ifdef __STDC__
-    fprintf(stdout,"__STDC__\n");
-#endif
-}
index 31e53f5..d217258 100644 (file)
@@ -22,14 +22,14 @@ default authentication = file /etc/passwd
 # db_name : Database name
 # db_table : authentication table name
 # name_field and pass_field: Username and password field name at the db_table
+
 # Accounting records log file
 
 accounting file = /var/log/tac_acc.log
 
 # Would you like to store accounting records in database..
 # db_accounting = "db_type://db_user:db_pass@db_hostname/db_name/db_table"
-# Same as above.. 
+# Same as above..
 
 #All services are alowed..
 
@@ -37,13 +37,13 @@ user = DEFAULT {
     service = ppp protocol = ip {}
 }
 
-# Yes we have more features like per host key 
+# Yes we have more features like per host key
 #host = 127.0.0.1 {
-#        key = test 
+#        key = test
 #        type = cisco
 #}
 #user = test {
-#    name = Test User 
+#    name = Test User
 #    pap = cleartext test
 #    member = staff
 #}
@@ -51,4 +51,3 @@ user = DEFAULT {
 #group = staff {
 #    time = "Wd1800-1817|!Wd1819-2000"
 #}
-
index 99d95e0..1bb658f 100644 (file)
@@ -1,4 +1,7 @@
-/* 
+#ifndef TAC_PLUS_H
+#define TAC_PLUS_H 1
+
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    FITNESS FOR A PARTICULAR PURPOSE.
 */
-/* For autoconfig */
+
+
+#ifdef HAVE_CONFIG_H
 #include "config.h"
+#endif
+
 
-/* 
+/*
  * If you are defining a system from scratch, the following may be useful.
  * Otherwise, just use the system definitions below this section.
  */
 /* Do you need tacacs+ versions of bzero etc. */
 /* #define NEED_BZERO */
 
-/* Define this if you have shadow passwords in /etc/passwd and
- * /etc/shadow. Note that you usually need to be root to read
- * /etc/shadow */
-/*#define SHADOW_PASSWORDS*/
-
-/* Define this if your malloc is defined in malloc.h instead of stdlib.h */
-/* #define STDLIB_MALLOC */
-
 /* Define this if your wait call status is a union as opposed to an int */
 /* #define UNIONWAIT */
 
-/* Define this if your signal() uses a function returning void instead 
- * of int
- */
-/* #define VOIDSIG */
-
-/* Define this if your password file does not contain age and comment fields. */
-/* #define NO_PWAGE */
-
 /* Define this if you need a getdtablesize routine defined */
 /* #define GETDTABLESIZE */
 
 /* #define REAPCHILD */
 
 /* Define this if you have DES routines you can link to for ARAP (See
- * the user's guide for more details). 
+ * the user's guide for more details).
  */
 /* #define ARAP_DES */
 
-/* Define this if you find that your daemon quits after being sent more than
- * one SIGUSR1. Some systems need to explicitly rearm signals after they've been
- * used once
- */
-/* #define REARMSIGNAL */
-
-#define VERSION "F4.0.3.alpha.v8 (Extended Tac_plus)"
+#define VERSION_TAIL " (Extended Tac_plus)"
 
 /*
- * System definitions. 
+ * System definitions.
  */
 
 #ifdef NETBSD
-#define STDLIB_MALLOC
-#define NO_PWAGE
 #define CONST_SYSERRLIST
-#define VOIDSIG
 #endif
 
 #ifdef AIX
 
-/* 
+/*
  * The only way to properly compile BSD stuff on AIX is to define a
  * "bsdcc" compiler on your system. See /usr/lpp/bos/bsdport on your
  * system for details. People who do NOT do this tell me that the code
 #define _BSD 1
 #define _BSD_INCLUDES
 #define UNIONWAIT
-#define NO_PWAGE
 #endif /* AIX */
 
 #ifdef LINUX
-#define VOIDSIG
-#define NO_PWAGE
 #define REAPCHILD
-#include <unistd.h>
-#define REARMSIGNAL
 #ifdef GLIBC
 #define CONST_SYSERRLIST
 #endif
 #define SYSV
 #define GETDTABLESIZE
 #define REAPCHILD
-#define SHADOW_PASSWORDS
 #define NEED_BZERO
-#define REARMSIGNAL
 #endif /* SOLARIS */
 
 #ifdef HPUX
 #define SYSV
 #define GETDTABLESIZE
 #define REAPCHILD
-#define SYSLOG_IN_SYS
-#define REARMSIGNAL
 #endif /* HPUX */
 
 #ifdef FREEBSD
 #define CONST_SYSERRLIST
-#define STDLIB_MALLOC
-#define VOIDSIG
-#define NO_PWAGE
-#endif
-
-#ifdef BSDI
-#define VOIDSIG
-#define STDLIB_MALLOC
-#define NO_PWAGE
 #endif
 
 #define MD5_LEN           16
 #define MSCHAP_DIGEST_LEN 49
 #endif /* MSCHAP */
 
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/file.h>
-#include <sys/time.h>
-#include <netinet/in.h>
-
-#include <stdio.h>
-#include <errno.h>
-#include <pwd.h>
-#include <netdb.h>
-
-#ifdef SYSLOG_IN_SYS
-#include <syslog.h>
-#else
-#include <sys/syslog.h>
-#endif
-
-#include <utmp.h>
-
-#include <unistd.h>
-
 #ifdef SYSV
+#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
+#endif
 #define index strchr
-#else /* ! SYSV */
-#include <strings.h>
 #endif /* SYSV */
 
+/* Sometimes are bzero/bcopy/bcmp declared as prototypes with non-void argument
+ * pointers. In such case we would generate too much warnings.
+ */
+#include <string.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#define bzero(s, n) bzero((void *)(s), (size_t)(n))
+#define bcopy(src, dest, n) bcopy((const void *)(src), (void *)(dest), (size_t)(n))
+#define bcmp(s1, s2, n) bcmp((const void *)(s1), (const void *)(s2), (size_t)(n))
+
+
 #ifndef TACPLUS_PIDFILE
 #define TACPLUS_PIDFILE "/var/run/tac_plus.pid"
 #endif
 
 
-/* 
+/*
  * You probably shouldn't be changing much below this line unless you really
  * know what you are doing.
  */
 
-#define DOLLARSIGN '$'
-
-/*
- * XTACACSP protocol defintions
- */
-
-/*
- * This structure describes an authentication method.
- *   authen_name     contains the name of the authentication method.
- *   authen_func     is a pointer to the authentication function.
- *   authen_method   numeric value of authentication method
- */
+/* Stolen from pbmplus.h of netpbm: */
 
-#define AUTHEN_NAME_SIZE 128
+#if __STDC__
+#define TAC_ARGS(alist) alist
+#else /*__STDC__*/
+#define TAC_ARGS(alist) ()
+#endif /*__STDC__*/
 
-struct authen_type {
-    char authen_name[AUTHEN_NAME_SIZE];
-    int (*authen_func)();
-    int authen_type;
-};
+/* Stolen from glib of Gnome/GTK+ environment: */
 
-/*
- * This structure describes a principal that is to be authenticated.
- *   username        is the principals name (ASCII, null terminated)
- *   NAS_name        is the name of the NAS where the user is
- *   NAS_port        is the port on the NAS where the user is
- *   NAC_address     is the remote user location.  This may be
- *                   a remote IP address or a caller-ID or ...
- *   priv_lvl        user's requested privilege level.
+/* Provide macros to feature the GCC function attribute.
  */
-
-struct identity {
-    char *username;
-    char *NAS_name;
-    char *NAS_port;
-    char *NAC_address;
-    int priv_lvl;
-};
-
-/*
- * The authen_data structure is the data structure for passing
- * information to and from the authentication function
- * (authen_type.authen_func).
+#if    __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
+#define G_GNUC_PRINTF( format_idx, arg_idx )   \
+       __attribute__((format (printf, format_idx, arg_idx)))
+#define G_GNUC_NORETURN                                \
+       __attribute__((noreturn))
+#define G_GNUC_CONST                           \
+       __attribute__((const))
+#define G_GNUC_UNUSED                          \
+       __attribute__((unused))
+#else  /* !__GNUC__ */
+#define G_GNUC_PRINTF( format_idx, arg_idx )
+#define G_GNUC_NORETURN
+#define G_GNUC_CONST
+#define        G_GNUC_UNUSED
+#endif /* !__GNUC__ */
+
+/* Provide convenience macros for handling structure
+ * fields through their offsets.
+ * Project tac_plus changed "gulong" to "glong" to be able to recover
+ * original structure base from pointer to its member.
  */
+#define G_STRUCT_OFFSET(struct_type, member)                   \
+       ((long) ((char*) &((struct_type*) 0)->member))
+#define G_STRUCT_MEMBER_P(struct_p, struct_offset)             \
+       ((void*) ((char*) (struct_p) + (long) (struct_offset)))
+#define G_STRUCT_MEMBER(member_type, struct_p, struct_offset)  \
+       (*(member_type*) G_STRUCT_MEMBER_P ((struct_p), (struct_offset)))
 
-struct authen_data {
-    struct identity *NAS_id;   /* user identity */
-    char *server_msg;          /* null-terminated output msg */
-
-    int server_dlen;           /* output data length */
-    char *server_data;         /* output data */
-
-    char *client_msg;          /* null-terminated input msg a user typed */
-
-    int client_dlen;           /* input data length */
-    char *client_data;         /* input data */
-
-    void *method_data;         /* opaque private method data */
-    int action;                        /* what's to be done */
-    int service;               /* calling service */
-    int status;                        /* Authen status */
-    int type;                  /* Authen type */
-    u_char flags;               /* input & output flags fields */
-};
-
+/* reversed, in fact: for inside "member_p" calculate "struct" address */
+#define TAC_MEMBER_STRUCT(struct_type, member_p, member)       \
+       (G_STRUCT_MEMBER(struct_type,member_p,-G_STRUCT_OFFSET(struct_type,member)))
 
-/* return values for  choose_authen(); */
 
-#define CHOOSE_FAILED -1     /* failed to choose an authentication function */
-#define CHOOSE_OK      0     /* successfully chose an authentication function */
-#define CHOOSE_GETUSER 1     /* need a username before choosing */
-#define CHOOSE_BADTYPE 2     /* Invalid preferred authen function specified */
-
-
-/*
- * This structure is the data structure for passing information to
- * and from the authorization function (do_author()).
+/* <sys/param.h> may define MAX & MIN without checking whether they
+ * were previously already defined:
  */
-struct author_data {
-    struct identity *id;       /* user id */
-    int authen_method;         /* authentication method */
-
-#define AUTHEN_METH_NONE             0x01
-#define AUTHEN_METH_KRB5             0x02
-#define AUTHEN_METH_LINE             0x03
-#define AUTHEN_METH_ENABLE           0x04
-#define AUTHEN_METH_LOCAL            0x05
-#define AUTHEN_METH_TACACSPLUS       0x06
-#define AUTHEN_METH_RCMD             0x20
-
-    int authen_type;           /* authentication type see authen_type */
-    int service;               /* calling service */
-    char *msg;                 /* optional NULL-terminated return message */
-    char *admin_msg;           /* optional NULL-terminated admin message */
-    int status;                        /* return status */
-
-#define AUTHOR_STATUS_PASS_ADD       0x01
-#define AUTHOR_STATUS_PASS_REPL      0x02
-#define AUTHOR_STATUS_FAIL           0x10
-#define AUTHOR_STATUS_ERROR          0x11
-
-    int num_in_args;           /* input arg count */
-    char **input_args;         /* input arguments */
-    int num_out_args;          /* output arg cnt */
-    char **output_args;                /* output arguments */
-
-};
-
-/* An API accounting record structure */
-struct acct_rec {
-    int acct_type;             /* start, stop, update */
-
-#define ACCT_TYPE_START      1
-#define ACCT_TYPE_STOP       2
-#define ACCT_TYPE_UPDATE     3
-
-    struct identity *identity;
-    int authen_method;
-    int authen_type;
-    int authen_service;
-    char *msg;       /* output field */
-    char *admin_msg; /* output field */
-    int num_args;
-    char **args;
-};
-
-#ifndef TAC_PLUS_PORT
-#define        TAC_PLUS_PORT                   49
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
 #endif
 
-/* Define tac_plus name for hosts.* files */ 
-#ifdef TCPWRAPPER
-#define        TACNAME                         "tac_plus"
+/* Provide definitions for some commonly used macros.
+ *  Some of them are only provided if they haven't already
+ *  been defined. It is assumed that if they are already
+ *  defined then the current definition is correct.
+ */
+#ifndef        NULL
+#define        NULL    ((void*) 0)
 #endif
 
-#define TAC_PLUS_READ_TIMEOUT          180     /* seconds */
-#define TAC_PLUS_WRITE_TIMEOUT         180     /* seconds */
-
-#define NAS_PORT_MAX_LEN                255
-
-struct session {
-    int session_id;                /* host specific unique session id */
-    int aborted;                   /* have we received an abort flag? */
-    int seq_no;                    /* seq. no. of last packet exchanged */
-    time_t last_exch;              /* time of last packet exchange */
-    int sock;                      /* socket for this connection */
-    char *key;                     /* the key */
-    int keyline;                   /* line number key was found on */
-    char *peer;                    /* name of connected peer */
-    char *cfgfile;                 /* config file name */
-    char *acctfile;                /* name of accounting file */
-    char *db_acct;                        /* name of db accounting string */
-    char port[NAS_PORT_MAX_LEN+1]; /* For error reporting */
-    u_char version;                /* version of last packet read */
-};
-
-extern struct session session;     /* the session */
-
-/* Global variables */
-
-extern int debug;                  /* debugging flag */
-extern int logging;                /* syslog logging flag */
-extern int single;                 /* do not fork (for debugging) */
-extern int console;                /* log to console */
-extern FILE *ostream;              /* for logging to console */
-extern int parse_only;             /* exit after parsing verbosely */
-extern int sendauth_only;          /* don't do sendauth */
-
-/* All tacacs+ packets have the same header format */
-
-struct tac_plus_pak_hdr {
-    u_char version;
-
-#define TAC_PLUS_MAJOR_VER_MASK 0xf0
-#define TAC_PLUS_MAJOR_VER      0xc0
-
-#define TAC_PLUS_MINOR_VER_0    0x0
-#define TAC_PLUS_VER_0  (TAC_PLUS_MAJOR_VER | TAC_PLUS_MINOR_VER_0)
-
-#define TAC_PLUS_MINOR_VER_1    0x01
-#define TAC_PLUS_VER_1  (TAC_PLUS_MAJOR_VER | TAC_PLUS_MINOR_VER_1)
-
-    u_char type;
-
-#define TAC_PLUS_AUTHEN                        1
-#define TAC_PLUS_AUTHOR                        2
-#define TAC_PLUS_ACCT                  3
-
-    u_char seq_no;             /* packet sequence number */
-    u_char encryption;         /* packet is encrypted or cleartext */
-
-#define TAC_PLUS_ENCRYPTED 0x0         /* packet is encrypted */
-#define TAC_PLUS_CLEAR     0x1         /* packet is not encrypted */
-
-    int session_id;            /* session identifier FIXME: Is this needed? */
-    int datalength;            /* length of encrypted data following this
-                                * header */
-    /* datalength bytes of encrypted data */
-};
-
-#define HASH_TAB_SIZE 157        /* user and group hash table sizes */
-
-#define TAC_PLUS_HDR_SIZE 12
-
-typedef struct tac_plus_pak_hdr HDR;
-
-/* Authentication packet NAS sends to us */ 
-
-struct authen_start {
-    u_char action;
+#undef MAX
+#define MAX(a, b)  (((a) > (b)) ? (a) : (b))
 
-#define TAC_PLUS_AUTHEN_LOGIN    0x1
-#define TAC_PLUS_AUTHEN_CHPASS   0x2
-#define TAC_PLUS_AUTHEN_SENDPASS 0x3 /* deprecated */
-#define TAC_PLUS_AUTHEN_SENDAUTH 0x4
+#undef MIN
+#define MIN(a, b)  (((a) < (b)) ? (a) : (b))
 
-    u_char priv_lvl;
 
-#define TAC_PLUS_PRIV_LVL_MIN 0x0
-#define TAC_PLUS_PRIV_LVL_MAX 0xf
+/* The following code is not needed or used. It exists solely to
+   prevent compilers from "helpfully" complaining that this source
+   file is empty, which upsets novices building the software */
 
-    u_char authen_type;
+#define TAC_SOURCEFILE_EMPTY \
+       static int dummy_unused G_GNUC_UNUSED = 0;
 
-#define TAC_PLUS_AUTHEN_TYPE_ASCII  1
-#define TAC_PLUS_AUTHEN_TYPE_PAP    2
-#define TAC_PLUS_AUTHEN_TYPE_CHAP   3
-#define TAC_PLUS_AUTHEN_TYPE_ARAP   4
-#ifdef MSCHAP
-#define TAC_PLUS_AUTHEN_TYPE_MSCHAP 5
-#endif /* MSCHAP */
 
-    u_char service;
-
-#define TAC_PLUS_AUTHEN_SVC_LOGIN  1
-#define TAC_PLUS_AUTHEN_SVC_ENABLE 2
-#define TAC_PLUS_AUTHEN_SVC_PPP    3
-#define TAC_PLUS_AUTHEN_SVC_ARAP   4
-#define TAC_PLUS_AUTHEN_SVC_PT     5
-#define TAC_PLUS_AUTHEN_SVC_RCMD   6
-#define TAC_PLUS_AUTHEN_SVC_X25    7
-#define TAC_PLUS_AUTHEN_SVC_NASI   8
-
-    u_char user_len;
-    u_char port_len;
-    u_char rem_addr_len;
-    u_char data_len;
-    /* <user_len bytes of char data> */
-    /* <port_len bytes of char data> */
-    /* <rem_addr_len bytes of u_char data> */
-    /* <data_len bytes of u_char data> */
-};
-
-#define TAC_AUTHEN_START_FIXED_FIELDS_SIZE 8
-
-/* Authentication continue packet NAS sends to us */ 
-struct authen_cont {
-    u_short user_msg_len;
-    u_short user_data_len;
-    u_char flags;
-
-#define TAC_PLUS_CONTINUE_FLAG_ABORT 0x1
-
-    /* <user_msg_len bytes of u_char data> */
-    /* <user_data_len bytes of u_char data> */
-};
-
-#define TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE 5
-
-/* Authentication reply packet we send to NAS */ 
-struct authen_reply {
-    u_char status;
-
-#define TAC_PLUS_AUTHEN_STATUS_PASS     1
-#define TAC_PLUS_AUTHEN_STATUS_FAIL     2
-#define TAC_PLUS_AUTHEN_STATUS_GETDATA  3
-#define TAC_PLUS_AUTHEN_STATUS_GETUSER  4
-#define TAC_PLUS_AUTHEN_STATUS_GETPASS  5
-#define TAC_PLUS_AUTHEN_STATUS_RESTART  6
-#define TAC_PLUS_AUTHEN_STATUS_ERROR    7 
-#define TAC_PLUS_AUTHEN_STATUS_FOLLOW   0x21
-
-    u_char flags;
-
-#define TAC_PLUS_AUTHEN_FLAG_NOECHO     0x1
-
-    u_short msg_len;
-    u_short data_len;
-
-    /* <msg_len bytes of char data> */
-    /* <data_len bytes of u_char data> */
-};
-
-#define TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE 6
-
-/* An authorization request packet */
-struct author {
-    u_char authen_method;
-    u_char priv_lvl;
-    u_char authen_type;
-    u_char service;
-
-    u_char user_len;
-    u_char port_len;
-    u_char rem_addr_len;
-    u_char arg_cnt;            /* the number of args */
-
-    /* <arg_cnt u_chars containing the lengths of args 1 to arg n> */
-    /* <user_len bytes of char data> */
-    /* <port_len bytes of char data> */
-    /* <rem_addr_len bytes of u_char data> */
-    /* <char data for each arg> */
-};
-
-#define TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE 8
-
-/* An authorization reply packet */
-struct author_reply {
-    u_char status;
-    u_char arg_cnt;
-    u_short msg_len;
-    u_short data_len;
-
-    /* <arg_cnt u_chars containing the lengths of arg 1 to arg n> */
-    /* <msg_len bytes of char data> */
-    /* <data_len bytes of char data> */
-    /* <char data for each arg> */
-};
-
-#define TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE 6
-
-struct acct {
-    u_char flags;
-
-#define TAC_PLUS_ACCT_FLAG_MORE     0x1
-#define TAC_PLUS_ACCT_FLAG_START    0x2
-#define TAC_PLUS_ACCT_FLAG_STOP     0x4
-#define TAC_PLUS_ACCT_FLAG_WATCHDOG 0x8
-           
-    u_char authen_method;
-    u_char priv_lvl;
-    u_char authen_type;
-    u_char authen_service;
-    u_char user_len;
-    u_char port_len;
-    u_char rem_addr_len;
-    u_char arg_cnt; /* the number of cmd args */
-    /* one u_char containing size for each arg */
-    /* <user_len bytes of char data> */
-    /* <port_len bytes of char data> */
-    /* <rem_addr_len bytes of u_char data> */
-    /* char data for args 1 ... n */
-};
-
-#define TAC_ACCT_REQ_FIXED_FIELDS_SIZE 9
-
-struct acct_reply {
-    u_short msg_len;
-    u_short data_len;
-    u_char status;
-
-#define TAC_PLUS_ACCT_STATUS_SUCCESS 0x1
-#define TAC_PLUS_ACCT_STATUS_ERROR   0x2
-#define TAC_PLUS_ACCT_STATUS_FOLLOW  0x21
-
-};
-
-#define TAC_ACCT_REPLY_FIXED_FIELDS_SIZE 5
+#define DOLLARSIGN '$'
 
 /* Odds and ends */
-#define TAC_PLUS_MAX_ITERATIONS 50
-#undef MIN
-#define MIN(a,b) ((a)<(b)?(a):(b))
 #define STREQ(a,b) (strcmp(a,b)==0)
 #define MAX_INPUT_LINE_LEN 255
 
-/* Debugging flags */
-
-#define DEBUG_PARSE_FLAG     2
-#define DEBUG_FORK_FLAG      4
-#define DEBUG_AUTHOR_FLAG    8
-#define DEBUG_AUTHEN_FLAG    16
-#define DEBUG_PASSWD_FLAG    32
-#define DEBUG_ACCT_FLAG      64
-#define DEBUG_CONFIG_FLAG    128
-#define DEBUG_PACKET_FLAG    256
-#define DEBUG_HEX_FLAG       512
-#define DEBUG_MD5_HASH_FLAG  1024
-#define DEBUG_XOR_FLAG       2048
-#define DEBUG_CLEAN_FLAG     4096
-#define DEBUG_SUBST_FLAG     8192
-#define DEBUG_PROXY_FLAG     16384
-#define DEBUG_MAXSESS_FLAG   32768
-#define DEBUG_LOCK_FLAG      65536
-
-extern char *codestring();
-extern int keycode();
-
-#define TAC_IS_USER           1
-#define TAC_PLUS_RECURSE      1
-#define TAC_PLUS_NORECURSE    0
-
-#define DEFAULT_USERNAME "DEFAULT"
-
-#include "parse.h"
-
-/* Node types */
-
-#define N_arg           50
-#define N_optarg        51
-#define N_svc_exec      52
-#define N_svc_slip      53
-#define N_svc_ppp       54
-#define N_svc_arap      55
-#define N_svc_cmd       56
-#define N_permit        57
-#define N_deny          58
-#define N_svc           59
-
-/* A parse tree node */
-struct node {
-    int type;     /* node type (arg, svc, proto) */
-    void *next;   /* pointer to next node in chain */
-    void *value;  /* node value */
-    void *value1; /* node value */
-    int dflt;     /* default value for node */
-    int line;     /* line number declared on */
-};
-
-typedef struct node NODE;
-
-union v {
-    int intval;
-    void *pval;
-};
-
-typedef union v VALUE;
-
-/* acct.c */
-extern void accounting();
-
-/* report.c */
-extern void report_string();
-extern void report_hex();
-#ifdef __STDC__
-extern void report(int priority, char *fmt,...);
-#else
-extern void report();
-#endif
-
-/* packet.c */
-extern u_char *get_authen_continue();
-extern int send_authen_reply();
-
-/* utils.c */
-extern char *tac_malloc();
-extern char *tac_strdup();
-extern char *tac_make_string();
-extern char *tac_find_substring();
-extern char *tac_realloc();
-
-/* dump.c */
-extern char *summarise_outgoing_packet_type();
-extern char *summarise_incoming_packet_type();
-
-/* author.c */
-extern void author();
-
-/* hash.c */
-extern void *hash_add_entry();
-extern void **hash_get_entries();
-extern void *hash_lookup();
-
-/* config.c */
-extern int cfg_get_intvalue();
-extern char * cfg_get_pvalue();
-extern char *cfg_get_authen_default();
-extern int cfg_get_authen_default_method();
-extern char **cfg_get_svc_attrs();
-extern NODE *cfg_get_cmd_node();
-extern NODE *cfg_get_svc_node();
-extern char *cfg_get_expires();
-extern char *cfg_get_login_secret();
-extern int cfg_get_user_nopasswd();
-extern char *cfg_get_arap_secret();
-extern char *cfg_get_chap_secret();
-#ifdef MSCHAP
-extern char *cfg_get_mschap_secret();
-#endif /* MSCHAP */
-extern char *cfg_get_pap_secret();
-extern char *cfg_get_opap_secret();
-extern char *cfg_get_global_secret();
-#ifdef USE_PAM
-extern char *cfg_get_pam_service();
-#endif / *PAM */ 
-extern void cfg_clean_config();
-extern char *cfg_nodestring();
-
-/* pw.c */
-extern struct passwd *tac_passwd_lookup();
-
-/* parse.c */
-extern void parser_init();
-
-/* pwlib.c */
-extern void set_expiration_status();
-
 /* miscellaneous */
 #ifdef CONST_SYSERRLIST
 extern const char *const sys_errlist[];
 #else
 extern char *sys_errlist[];
 #endif
-extern int errno;
-extern int sendauth_fn();
-extern int sendpass_fn();
-extern int enable_fn();
-extern int default_fn();
-extern int default_v0_fn();
-extern int skey_fn();
-#ifdef MSCHAP
-extern void mschap_lmchallengeresponse();
-extern void mschap_ntchallengeresponse();
-#endif /* MSCHAP */
-
-#ifdef MAXSESS
-
-extern void maxsess_loginit();
-extern int maxsess_check_count();
-
-/*
- * This is a shared file used to maintain a record of who's on
- */
-#define WHOLOG_DEFAULT "/var/log/tac_who.log"
-extern char *wholog;
-/*
- * This is state kept per user/session
- */
-struct peruser {
-    char username[64];         /* User name */
-    char NAS_name[32];         /* NAS user logged into */
-    char NAS_port[32];         /*  ...port on that NAS */
-    char NAC_address[32];      /*  ...IP address of NAS */
-};
-
-#endif /* MAXSESS */
-
-#ifdef USE_PAM
-extern int tac_pam_authorization();
-#endif
 
-#define LOGFILE_DEFAULT "/var/log/tac_plus.log"
 
-extern struct timeval started_at;
-extern char *logfile;
-extern char *wtmpfile;
-extern int wtmpfd;
+#endif /* TAC_PLUS_H */
index 681786e..93b749b 100644 (file)
@@ -53,14 +53,14 @@ case "$1" in
         echo
         ;;
   status)
-       status tac_plus 
+       status tac_plus
        exit $?
        ;;
   restart)
        $0 stop
-       $0 start  
+       $0 start
        ;;
-  
+
   reload)
        echo "TACACS+ now reloading......"
        kill -SIGUSR1 `cat /var/run/tac_plus.pid`
diff --git a/tac_plus.pam b/tac_plus.pam
new file mode 100644 (file)
index 0000000..fc135fb
--- /dev/null
@@ -0,0 +1,5 @@
+#%PAM-1.0
+auth       required    /lib/security/pam_pwdb.so shadow
+account    required    /lib/security/pam_pwdb.so
+password   required    /lib/security/pam_pwdb.so nullok use_authtok shadow
+session    required    /lib/security/pam_pwdb.so
index 14f972e..638f7a6 100644 (file)
@@ -14,7 +14,7 @@
         size 5M
        missingok
         errors root@localhost
-       nocompress      
+       nocompress
        postrotate
                 /usr/bin/killall -HUP tac_plus 2> /dev/null || true
         endscript
diff --git a/tac_plus.spec.in b/tac_plus.spec.in
new file mode 100644 (file)
index 0000000..53d73f9
--- /dev/null
@@ -0,0 +1,125 @@
+# This is tac_plus rpm spec file
+
+%define ver    @VERSION@
+%define rel    1
+%define prefix /usr
+
+Summary:       Cisco Tacacs+ Daemon
+Name:          tac_plus
+Version:       %ver
+Release:       %rel
+Copyright:     Cisco systems, Inc.
+Group:         Networking/Daemons
+Source:                http://www.gazi.edu.tr/tacacs/src/tac_plus-%{ver}.tar.gz
+Url:           http://www.gazi.edu.tr/tacacs/
+Packager:      Jan Kratochvil <short@ucw.cz>
+BuildRoot:     /var/tmp/@PACKAGE@-%{ver}-%{rel}-root
+#Docdir:               %{prefix}/doc
+
+%define __libtoolize true      # we don't need it, is is otherwise run automatically
+                               # don't %undefine it, there is expansion bug at least in rpm-4.0-4
+
+%description
+TACACS+ daemon using with Cisco's NASs (Or other vendors) for AAA (Authentication , Authorization and Accounting) propose. 
+
+
+%prep
+%setup
+
+%build
+# configure script have some options describe below 
+# --with-pam  : For PAM support
+# --with-db   : If you like to use db feature you must enable it
+# --with-mysql: For MySQL database support
+# --with-mysql-prefix: If you install MySQL libs other than /usr/lib
+# --enable-maxsess: For check concurrent logins (It's uses finger!!) 
+# --with-pgsql          With PgSQL Support   
+# --with-pgsql-prefix=PREFIX  PgSQL prefix [default=/usr]
+# --with-tacuid: If you like to run tac_plus specify UID
+# --with-tacgid: If you like to run tac_plus specify GID
+# --with-tacplus_pid=PREFIX  Tac_plus pid file location [default=/var/run] 
+# --with-libwrap[=PATH]   Compile in libwrap (tcp_wrappers) support
+
+%configure --with-pam --with-db 
+make
+
+%install
+rm -rf "$RPM_BUILD_ROOT"
+%makeinstall
+install -d "$RPM_BUILD_ROOT"/%{_sysconfdir}/{tacacs,logrotate.d,pam.d,rc.d/{init.d,rc{0,1,2,3,4,5,6}.d}}
+install    -c -m 0755 tac_plus.init   "$RPM_BUILD_ROOT"/etc/rc.d/init.d/tac_plus
+install -b -c -m 0644 tac_plus.pam    "$RPM_BUILD_ROOT"/etc/pam.d/pap
+install -b -c -m 0644 tac_plus.rotate "$RPM_BUILD_ROOT"/etc/logrotate.d/tac_plus
+
+%clean
+rm -rf "$RPM_BUILD_ROOT"
+
+%post
+/sbin/chkconfig --add tac_plus
+
+%preun
+if [ $1 = 0 ]; then
+   if [ -f /var/lock/subsys/tac_plus ]; then
+      %{_sysconfdir}/rc.d/init.d/tac_plus stop
+   fi
+   /sbin/chkconfig --del tac_plus 
+fi
+
+%files
+%defattr(-, root, root)
+%config %{_sysconfdir}/tacacs/tac_plus.cfg
+%config %{_sysconfdir}/pam.d/pap
+%config %{_sysconfdir}/logrotate.d/tac_plus
+%doc users_guide CHANGES convert.pl
+%doc README.LDAP README.PAM tac_plus.sql 
+%dir %{_sysconfdir}/tacacs
+%attr(750,root,root)           %{_sysconfdir}/rc.d/init.d/tac_plus
+%attr(750,root,root)           %{_bindir}/generate_passwd      
+%attr(750,root,root)           %{_sbindir}/tac_plus    
+%attr(644,root,root)           %{_mandir}/man1/*                       
+
+%changelog
+* Sun Mar 25 2001 Devrim SERAL<devrim@gazi.edu.tr>
+- Added PostgreSQL authentication and accounting function
+- Added tcpwrapper feature
+- Added LDAP Authentication from Harpes Patrick (patrick.harpes@tudor.lu)
+- Added more options to configure script
+- Added time_limit function for control user loging time
+- And more control for buffer overflow
+
+* Fri Nov 17 2000 Devrim SERAL<devrim@tef.gazi.edu.tr>
+- packet.c is pached for overflow problem
+- Fix some log files name
+- Add new config parameters for database accounting
+- MySQL authentication code is functional
+- MySQL accounting code ready but not well tested
+
+* Mon Mar 10 2000 Devrim SERAL<devrim@tef.gazi.edu.tr>
+- I am add PAM patch from  Max Liccardo <ravel@tiscalinet.it>
+- Change PAM code to authorize user
+- Add db support from fil@artelecom.ru 
+- I am write MySQL authentication code
+- MySQL code is still experimental 
+
+* Tue Nov 15 1999 Devrim SERAL<devrim@tef.gazi.edu.tr>
+- Take out documentation
+- Add more functional parameters tac_plus script 
+- Change some code to authenticate with /etc/shadow
+- Fix some file permissions (Like accounting logs file)
+
+* Sun Oct 24 1999 D'mon <dimone@ikar.ugol.ru>
+- I moved to RedHat 6.0 =)
+- changes of the package internals!
+
+* Mon Oct 18 1999 D'mon <dimone@ikar.ugol.ru>
+- massive remake to suit RedHat 5.2 standard
+- patch for RedHat 5.2
+
+* Wed Aug 4 1999 Erhan Bilgili <erhan@altay.adm.deu.edu.tr>
+- fixes for the RPM_OPT_FLAGS
+- change the buildroot to /var/tmp/tacacsd
+
+* Wed Aug 4 1999 Devrim SERAL<devrim@tef.gazi.edu.tr>
+- I just re-did the spec file
+- And added Tacac FAQ
+
index 46003af..41caeea 100644 (file)
@@ -5,10 +5,10 @@ CREATE DATABASE tacacs;
 USE tacacs;
 
 # id table fields are:
-# name | surname | usern | tel | address 
+# name | surname | usern | tel | address
 # name : Real name
 # surname : Surname
-# usern : Account name 
+# usern : Account name
 # tel: Tel number
 # address: Address
 
@@ -18,11 +18,11 @@ CREATE TABLE id ( name char(40) NOT NULL, surname char(40) NOT NULL,usern char(1
 # usern | passwd | exp_time | time_limit | lck
 # usern : Account name
 # passwd : usern password
-# exp_time : Expire date 
+# exp_time : Expire date
 # time_limit : Time limiting
-# lck : Adminstrative lock 
+# lck : Adminstrative lock
 
-CREATE TABLE auth( usern CHAR(15) NOT NULL, passwd CHAR(15) NOT NULL, exp_time TIMESTAMP(8) NOT NULL ,time_limit CHAR(30) DEFAULT "*",lck ENUM("T","F") DEFAULT "F",PRIMARY KEY(usern) ); 
+CREATE TABLE auth( usern CHAR(15) NOT NULL, passwd CHAR(15) NOT NULL, exp_time TIMESTAMP(8) NOT NULL ,time_limit CHAR(30) DEFAULT "*",lck ENUM("T","F") DEFAULT "F",PRIMARY KEY(usern) );
 
 # acct tables fields are:
 # usern | s_name | c_name | elapsed_time | bytes_in | bytes_out | fin_t
@@ -33,5 +33,5 @@ CREATE TABLE auth( usern CHAR(15) NOT NULL, passwd CHAR(15) NOT NULL, exp_time T
 # bytes_in : Incoming bytes to port
 # bytes_out : Outgoing bytes from port
 # fin_t :  When the accounting is finished
+
 CREATE TABLE acct( usern CHAR(15) NOT NULL, s_name CHAR(30) NOT NULL, c_name CHAR(30) NOT NULL, elapsed_time INT NOT NULL, bytes_in INT DEFAULT 0, bytes_out INT  DEFAULT 0,fin_t TIMESTAMP(14) NOT NULL,INDEX acct_index(usern(10)));
index 9c0357a..390c5f8 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
  * precedence is structured in regular expressions.  Serious changes in
  * regular-expression syntax might require a total rethink.
  */
+
+
+#include "tac_plus.h"
+
+#ifdef WITH_INCLUDED_REGEX
+
 #include <stdio.h>
-#include "regexp.h"
-#include "regmagic.h"
+#include <string.h>
+#include <stdlib.h>    /* malloc() can be found in <stdlib.h> OR <malloc.h> */
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#include "tac_regexp.h"
+#include "tac_regmagic.h"
+#include "report.h"                    /* for regerror() */
+
 
 /*
  * The "internal use only" fields in regexp.h are present to pass info from
 #define        UCHARAT(p)      ((int)*(p)&CHARBITS)
 #endif
 
-#define        FAIL(m) { regerror(m); return(NULL); }
+#define        FAIL(m) { tac_regerror(m); return(NULL); }
 #define        ISMULT(c)       ((c) == '*' || (c) == '+' || (c) == '?')
 #define        META    "^$.[()|?+*\\"
 
 /*
  * Global work variables for regcomp().
  */
-static char *regparse;         /* Input-scan pointer. */
+static const char *regparse;   /* Input-scan pointer. */
 static int regnpar;            /* () count. */
 static char regdummy;
 static char *regcode;          /* Code-emit pointer; &regdummy = don't. */
@@ -173,23 +187,24 @@ static long regsize;              /* Code size. */
 /*
  * Forward declarations for regcomp()'s friends.
  */
-#ifndef STATIC
-#define        STATIC  static
-#endif
-STATIC char *reg();
-STATIC char *regbranch();
-STATIC char *regpiece();
-STATIC char *regatom();
-STATIC char *regnode();
-STATIC char *regnext();
-STATIC void regc();
-STATIC void reginsert();
-STATIC void regtail();
-STATIC void regoptail();
-#ifdef STRCSPN
-STATIC int strcspn();
+static char *reg TAC_ARGS((int paren, int *flagp));
+static char *regbranch TAC_ARGS((int *flagp));
+static char *regpiece TAC_ARGS((int *flagp));
+static char *regatom TAC_ARGS((int *flagp));
+static char *regnode TAC_ARGS((int op));
+static void regc TAC_ARGS((int b));
+static void reginsert TAC_ARGS((int op, char *opnd));
+static void regtail TAC_ARGS((char *p, char *val));
+static void regoptail TAC_ARGS((char *p, char *val));
+static int regtry TAC_ARGS((tac_regexp *prog, const char *string));
+static int regmatch TAC_ARGS((char *prog));
+static int regrepeat TAC_ARGS((char *p));
+static char *regnext TAC_ARGS((register char *p));
+#ifndef HAVE_STRCSPN
+static int strcspn TAC_ARGS((char *s1, char *s2));
 #endif
 
+
 /*
  - regcomp - compile a regular expression into internal code
  *
@@ -205,16 +220,18 @@ STATIC int strcspn();
  * Beware that the optimization-preparation code in here knows about some
  * of the structure of the compiled regexp.
  */
-regexp *
-regcomp(exp)
-char *exp;
+
+tac_regexp *tac_regcomp TAC_ARGS((const char *exp));
+
+tac_regexp *
+tac_regcomp(exp)
+const char *exp;
 {
-       register regexp *r;
+       register tac_regexp *r;
        register char *scan;
        register char *longest;
        register int len;
        int flags;
-       extern char *malloc();
 
        if (exp == NULL)
                FAIL("NULL argument");
@@ -233,7 +250,7 @@ char *exp;
                FAIL("regexp too big");
 
        /* Allocate space. */
-       r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
+       r = (tac_regexp *)malloc(sizeof(tac_regexp) + (unsigned)regsize);
        if (r == NULL)
                FAIL("out of space");
 
@@ -272,7 +289,7 @@ char *exp;
                        longest = NULL;
                        len = 0;
                        for (; scan != NULL; scan = regnext(scan))
-                               if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
+                               if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= (unsigned)len) {
                                        longest = OPERAND(scan);
                                        len = strlen(OPERAND(scan));
                                }
@@ -293,6 +310,9 @@ char *exp;
  * is a trifle forced, but the need to tie the tails of the branches to what
  * follows makes it hard to avoid.
  */
+
+static char *reg TAC_ARGS((int paren, int *flagp));
+
 static char *
 reg(paren, flagp)
 int paren;                     /* Parenthesized? */
@@ -301,7 +321,7 @@ int *flagp;
        register char *ret;
        register char *br;
        register char *ender;
-       register int parno;
+       register int parno = 0 /* GCC paranoia */;
        int flags;
 
        *flagp = HASWIDTH;      /* Tentatively. */
@@ -339,7 +359,7 @@ int *flagp;
        }
 
        /* Make a closing node, and hook it on the end. */
-       ender = regnode((paren) ? CLOSE+parno : END);   
+       ender = regnode((paren) ? CLOSE+parno : END);
        regtail(ret, ender);
 
        /* Hook the tails of the branches to the closing node. */
@@ -365,6 +385,9 @@ int *flagp;
  *
  * Implements the concatenation operator.
  */
+
+static char *regbranch TAC_ARGS((int *flagp));
+
 static char *
 regbranch(flagp)
 int *flagp;
@@ -404,6 +427,9 @@ int *flagp;
  * It might seem that this node could be dispensed with entirely, but the
  * endmarker role is not redundant.
  */
+
+static char *regpiece TAC_ARGS((int *flagp));
+
 static char *
 regpiece(flagp)
 int *flagp;
@@ -468,6 +494,9 @@ int *flagp;
  * faster to run.  Backslashed characters are exceptions, each becoming a
  * separate node; the code is simpler that way and it's not worth fixing.
  */
+
+static char *regatom TAC_ARGS((int *flagp));
+
 static char *
 regatom(flagp)
 int *flagp;
@@ -577,9 +606,12 @@ int *flagp;
 /*
  - regnode - emit a node
  */
+
+static char *regnode TAC_ARGS((int op));
+
 static char *                  /* Location. */
 regnode(op)
-char op;
+int op;                                /* promoted "char" type */
 {
        register char *ret;
        register char *ptr;
@@ -602,9 +634,12 @@ char op;
 /*
  - regc - emit (if appropriate) a byte of code
  */
+
+static void regc TAC_ARGS((int b));
+
 static void
 regc(b)
-char b;
+int b;                         /* promoted "char" type */
 {
        if (regcode != &regdummy)
                *regcode++ = b;
@@ -617,9 +652,12 @@ char b;
  *
  * Means relocating the operand.
  */
+
+static void reginsert TAC_ARGS((int op, char *opnd));
+
 static void
 reginsert(op, opnd)
-char op;
+int op;                                /* promoted "char" type */
 char *opnd;
 {
        register char *src;
@@ -646,6 +684,9 @@ char *opnd;
 /*
  - regtail - set the next-pointer at the end of a node chain
  */
+
+static void regtail TAC_ARGS((char *p, char *val));
+
 static void
 regtail(p, val)
 char *p;
@@ -678,6 +719,9 @@ char *val;
 /*
  - regoptail - regtail on operand of first argument; nop if operandless
  */
+
+static void regoptail TAC_ARGS((char *p, char *val));
+
 static void
 regoptail(p, val)
 char *p;
@@ -696,44 +740,40 @@ char *val;
 /*
  * Global work variables for regexec().
  */
-static char *reginput;         /* String-input pointer. */
-static char *regbol;           /* Beginning of input, for ^ check. */
-static char **regstartp;       /* Pointer to startp array. */
-static char **regendp;         /* Ditto for endp. */
+static const char *reginput;   /* String-input pointer. */
+static const char *regbol;     /* Beginning of input, for ^ check. */
+static const char **regstartp; /* Pointer to startp array. */
+static const char **regendp;   /* Ditto for endp. */
 
-/*
- * Forwards.
- */
-STATIC int regtry();
-STATIC int regmatch();
-STATIC int regrepeat();
 
 #ifdef DEBUG
 int regnarrate = 0;
-void regdump();
-STATIC char *regprop();
+static char *regprop TAC_ARGS((char *op));
+static void regdump TAC_ARGS((tac_regexp *r));
 #endif
 
 /*
  - regexec - match a regexp against a string
  */
+
+int tac_regexec TAC_ARGS((register tac_regexp *prog, register const char *string));
+
 int
-regexec(prog, string)
-register regexp *prog;
-register char *string;
+tac_regexec(prog, string)
+register tac_regexp *prog;
+register const char *string;
 {
-       register char *s;
-       extern char *strchr();
+       register const char *s;
 
        /* Be paranoid... */
        if (prog == NULL || string == NULL) {
-               regerror("NULL parameter");
+               tac_regerror("NULL parameter");
                return(0);
        }
 
        /* Check validity of program. */
        if (UCHARAT(prog->program) != MAGIC) {
-               regerror("corrupted program");
+               tac_regerror("corrupted program");
                return(0);
        }
 
@@ -779,14 +819,17 @@ register char *string;
 /*
  - regtry - try match at specific point
  */
+
+static int regtry TAC_ARGS((tac_regexp *prog, const char *string));
+
 static int                     /* 0 failure, 1 success */
 regtry(prog, string)
-regexp *prog;
-char *string;
+tac_regexp *prog;
+const char *string;
 {
        register int i;
-       register char **sp;
-       register char **ep;
+       register const char **sp;
+       register const char **ep;
 
        reginput = string;
        regstartp = prog->startp;
@@ -816,13 +859,15 @@ char *string;
  * need to know whether the rest of the match failed) by a loop instead of
  * by recursion.
  */
+
+static int regmatch TAC_ARGS((char *prog));
+
 static int                     /* 0 failure, 1 success */
 regmatch(prog)
 char *prog;
 {
        register char *scan;    /* Current node. */
        char *next;             /* Next node. */
-       extern char *strchr();
 
        scan = prog;
 #ifdef DEBUG
@@ -888,7 +933,7 @@ char *prog;
                case OPEN+8:
                case OPEN+9: {
                                register int no;
-                               register char *save;
+                               register const char *save;
 
                                no = OP(scan) - OPEN;
                                save = reginput;
@@ -916,7 +961,7 @@ char *prog;
                case CLOSE+8:
                case CLOSE+9: {
                                register int no;
-                               register char *save;
+                               register const char *save;
 
                                no = OP(scan) - CLOSE;
                                save = reginput;
@@ -935,7 +980,7 @@ char *prog;
                        }
                        break;
                case BRANCH: {
-                               register char *save;
+                               register const char *save;
 
                                if (OP(next) != BRANCH)         /* No choice. */
                                        next = OPERAND(scan);   /* Avoid recursion. */
@@ -956,7 +1001,7 @@ char *prog;
                case PLUS: {
                                register char nextch;
                                register int no;
-                               register char *save;
+                               register const char *save;
                                register int min;
 
                                /*
@@ -985,7 +1030,7 @@ char *prog;
                        return(1);      /* Success! */
                        break;
                default:
-                       regerror("memory corruption");
+                       tac_regerror("memory corruption");
                        return(0);
                        break;
                }
@@ -997,21 +1042,23 @@ char *prog;
         * We get here only if there's trouble -- normally "case END" is
         * the terminating point.
         */
-       regerror("corrupted pointers");
+       tac_regerror("corrupted pointers");
        return(0);
 }
 
 /*
  - regrepeat - repeatedly match something simple, report how many
  */
+
+static int regrepeat TAC_ARGS((char *p));
+
 static int
 regrepeat(p)
 char *p;
 {
        register int count = 0;
-       register char *scan;
+       register const char *scan;
        register char *opnd;
-       extern char *strchr();
 
        scan = reginput;
        opnd = OPERAND(p);
@@ -1039,7 +1086,7 @@ char *p;
                }
                break;
        default:                /* Oh dear.  Called inappropriately. */
-               regerror("internal foulup");
+               tac_regerror("internal foulup");
                count = 0;      /* Best compromise. */
                break;
        }
@@ -1051,6 +1098,9 @@ char *p;
 /*
  - regnext - dig the "next" pointer out of a node
  */
+
+static char *regnext TAC_ARGS((register char *p));
+
 static char *
 regnext(p)
 register char *p;
@@ -1072,19 +1122,19 @@ register char *p;
 
 #ifdef DEBUG
 
-STATIC char *regprop();
-
 /*
  - regdump - dump a regexp onto stdout in vaguely comprehensible form
  */
-void
+
+static void regdump TAC_ARGS((tac_regexp *r));
+
+static void
 regdump(r)
-regexp *r;
+tac_regexp *r;
 {
        register char *s;
        register char op = EXACTLY;     /* Arbitrary non-END op. */
        register char *next;
-       extern char *strchr();
 
 
        s = r->program + 1;
@@ -1094,7 +1144,7 @@ regexp *r;
                next = regnext(s);
                if (next == NULL)               /* Next ptr. */
                        printf("(0)");
-               else 
+               else
                        printf("(%d)", (s-r->program)+(next-s));
                s += 3;
                if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
@@ -1121,6 +1171,9 @@ regexp *r;
 /*
  - regprop - printable representation of opcode
  */
+
+static char *regprop TAC_ARGS((char *op));
+
 static char *
 regprop(op)
 char *op;
@@ -1192,7 +1245,7 @@ char *op;
                p = "PLUS";
                break;
        default:
-               regerror("corrupted opcode");
+               tac_regerror("corrupted opcode");
                break;
        }
        if (p != NULL)
@@ -1207,12 +1260,14 @@ char *op;
  * about it; at least one public-domain implementation of those (highly
  * useful) string routines has been published on Usenet.
  */
-#ifdef STRCSPN
+#ifndef HAVE_STRCSPN
 /*
  * strcspn - find length of initial segment of s1 consisting entirely
  * of characters not from s2
  */
 
+static int strcspn TAC_ARGS((char *s1, char *s2));
+
 static int
 strcspn(s1, s2)
 char *s1;
@@ -1231,4 +1286,10 @@ char *s2;
        }
        return(count);
 }
-#endif
+#endif /* HAVE_STRCSPN */
+
+#else /* WITH_INCLUDED_REGEX */
+
+TAC_SOURCEFILE_EMPTY
+
+#endif /* WITH_INCLUDED_REGEX */
index b23d97e..7a1a884 100644 (file)
@@ -1,4 +1,11 @@
-/* 
+#ifndef TAC_REGEXP_H
+#define TAC_REGEXP_H 1
+
+#include "tac_plus.h"
+
+#ifdef WITH_INCLUDED_REGEX
+
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
@@ -17,6 +24,7 @@
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 /*
  * Definitions etc. for regexp(3) routines.
  *
  * not the System V one.
  */
 #define NSUBEXP  10
-typedef struct regexp {
-       char *startp[NSUBEXP];
-       char *endp[NSUBEXP];
+typedef struct tac_regexp {
+       const char *startp[NSUBEXP];
+       const char *endp[NSUBEXP];
        char regstart;          /* Internal use only. */
        char reganch;           /* Internal use only. */
        char *regmust;          /* Internal use only. */
        int regmlen;            /* Internal use only. */
        char program[1];        /* Unwarranted chumminess with compiler. */
-} regexp;
+} tac_regexp;
+
+
+extern tac_regexp *tac_regcomp TAC_ARGS((const char *exp));
+extern int tac_regexec TAC_ARGS((register tac_regexp *prog, register const char *string));
+
+
+#endif /* WITH_INCLUDED_REGEX */
 
-extern regexp *regcomp();
-extern int regexec();
-extern void regsub();
-extern void regerror();
+#endif /* TAC_REGEXP_H */
index 0b18b0a..ff321df 100644 (file)
@@ -1,4 +1,9 @@
-/* 
+#ifndef REGMAGIC_H
+#define REGMAGIC_H 1
+
+#include "tac_plus.h"
+
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 /*
  * The first byte of the regexp internal "program" is actually this magic
  * number; the start node begins in the second byte.
  */
 #define        MAGIC   0234
+
+
+#endif /* REGMAGIC_H */
index ef3d3ad..744a1df 100644 (file)
--- a/tcpwrap.c
+++ b/tcpwrap.c
@@ -1,24 +1,44 @@
-/* 
+/*
    This function  use for check access control rules from hosts.deny and
-   hosts.access file. 
-   Writen by Devrim SERAL<devrim@gazi.edu.tr>. This file protected by 
-   GNU Copyright agreement. 
+   hosts.access file.
+   Writen by Devrim SERAL<devrim@gazi.edu.tr>. This file protected by
+   GNU Copyright agreement.
 */
+
+
+#include "tac_plus.h"
+
 #ifdef TCPWRAPPER
+
 #include <tcpd.h>
-#include "tac_plus.h"
 
-int allow_severity = LOG_INFO;
+#include "tcpwrap.h"
+#include "report.h"
+#include "packet.h"
+#include "do_author.h"                 /* for "struct identity" */
+#include "main.h"
+
+
+int allow_severity = LOG_INFO;         /* *_severity accessed from libwrap */
 int deny_severity = LOG_WARNING;
 
 
+/* Configurable:
+ */
+
+/* Define tac_plus name for hosts.* files */
+#define        TACNAME                         "tac_plus"
+
+
+int check_from_wrap TAC_ARGS((struct identity *datap));
+
 int
 check_from_wrap(datap)
 struct identity *datap;
 {
     struct request_info req;
 
-    request_init(&req, RQ_DAEMON,TACNAME,RQ_CLIENT_ADDR,datap->NAS_name , NULL);
+    request_init(&req, RQ_FILE,session.sock,RQ_DAEMON,TACNAME,RQ_CLIENT_ADDR,datap->NAS_name , NULL);
     fromhost(&req); /* validate client host info */
     if (!hosts_access(&req))
       {
@@ -27,11 +47,16 @@ struct identity *datap;
         send_authen_error("You are not allowed to access here");
         refuse(&req); /* If connection is not allowed, clean up and exit. */
         return 0;
-      } 
-    
+      }
+
     if (debug & DEBUG_AUTHEN_FLAG )
                 report(LOG_DEBUG, "Access permited for NAS=%s",datap->NAS_name);
-return 1;     
+return 1;
 
 }
+
+#else /* TCPWRAPPER */
+
+TAC_SOURCEFILE_EMPTY
+
 #endif /* TCPWRAPPER */
diff --git a/tcpwrap.h b/tcpwrap.h
new file mode 100644 (file)
index 0000000..e8e9455
--- /dev/null
+++ b/tcpwrap.h
@@ -0,0 +1,16 @@
+#ifndef TCPWRAP_H
+#define TCPWRAP_H 1
+
+#include "tac_plus.h"
+
+#ifdef TCPWRAPPER
+
+
+struct identity;
+
+extern int check_from_wrap TAC_ARGS((struct identity *datap));
+
+
+#endif /* TCPWRAPPER */
+
+#endif /* TCPWRAP_H */
index 08f6c55..75062f2 100644 (file)
@@ -1,7 +1,7 @@
-/*             
+/*
        These functions writen by Devrim SERAL <devrim@gazi.edu.tr>
 
-Applicable format is  : <day str><time str> [,|] <day str><time str> [,|] and so on  
+Applicable format is  : <day str><time str> [,|] <day str><time str> [,|] and so on
 
 The accept parameter for day str is:
 SU = Sunday
@@ -16,189 +16,233 @@ WD = For Week and
 AL = For All days
 
 And time str must be:
-Hourminute-Hourminute  
+Hourminute-Hourminute
 For example it's to be -> 0000-1200 or 1600-1700 or 1600-0800
 
-License: This code is free software; you can redistribute it and/or modify it 
-under the terms of the GNU General Public License as published by the Free 
+License: This code is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the Free
 Software Foundation; either version 2, or (at your option) any later version.
-               
-*/     
 
-#include"time_limit.h"
+*/
+
+
 #include "tac_plus.h"
 
-int problem=0;
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
 
-int 
-time_limit_process(str) 
-char *str;
+#include "time_limit.h"
+#include "report.h"
+#include "main.h"
+#include "utils.h"
+
+
+static int str_token_proc TAC_ARGS((char *str));
+static int process TAC_ARGS((char *str));
+static int time_calc TAC_ARGS((char *str, int lct));
+static int antoi TAC_ARGS((char *str, int n));
+
+
+static char* week_days[] = {"SU","MO","TU","WE","TH","FR","SA","WK","WD","AL"};
+static long week_day_val[] = {1, 2, 4, 8, 16, 32, 64, 62, 65, 127};
+
+static int problem = 0;
+
+
+int time_limit_process TAC_ARGS((const char *str));
+
+int
+time_limit_process(str)
+const char *str;
 {
-int ret=0;
-char *tmp_str;
-
-tmp_str=(char *)strtok(str,",|");
-while ( tmp_str != NULL) {
-       ret|=str_token_proc(tmp_str);
-       tmp_str=(char *)strtok(NULL,",");
-       }
-return (ret); 
+    int ret=0;
+    char *tmp_str, *str_copy;
+
+    str_copy = tac_strdup(str);
+    tmp_str = (char *) strtok(str_copy,",|");
+
+    while ( tmp_str != NULL) {
+       ret |= str_token_proc(tmp_str);
+       tmp_str = (char *) strtok(NULL,",");
+    }
+    free(str_copy);
+
+    return (ret);
 }
 
-int 
+static int str_token_proc TAC_ARGS((char *str));
+
+static int
 str_token_proc(str)
 char *str;
 {
-int inv=0,ret;
+    int inv = 0, ret;
 
-/* Pass space characters */ 
-while (isspace(*str)) str++;
+    /* Pass space characters */
+    while (isspace((int) *str))
+       str++;
 
-if (*str=='!') { 
-               inv=1;str++; 
-}
+    if (*str=='!') {
+       inv=1;
+       str++;
+    }
 
-ret=process(str);
+    ret=process(str);
 
-if (problem) {
+    if (problem) {
        if ( debug & DEBUG_AUTHEN_FLAG )
-               report(LOG_DEBUG,"Timestamp format incorrect");
+           report(LOG_DEBUG,"Timestamp format incorrect");
        problem=0;
        return(0);
-} 
+    }
 
-if (inv) 
+    if (inv)
        ret=!ret;
-return(ret);   
+
+    return(ret);
 }
 
 
-int
+static void str_up TAC_ARGS((char *str));
+
+static void
+str_up(str)
+char *str;
+{
+    while (*str) {
+       if (islower((int) *str))
+           *str = toupper((int) *str);
+       str++;
+    }
+}
+
+
+static int process TAC_ARGS((char *str));
+
+static int
 process(str)
 char *str;
 {
-int count=0,ret=0,i,j,localtm;
-char *head,*buf,*gec;
-long sec;
-struct tm *tms;
+    int count = 0, ret = 0, i, j, localtm;
+    char *head, *buf, *gec;
+    time_t sec;
+    struct tm *tms;
 
-/* Pass space characters  */
-while (isspace(*str)) str++;
+    /* Pass space characters  */
+    while (isspace((int) *str))
+       str++;
 
-head=str;
+    head=str;
 
-/* Count alphanumeric char */
-while (isalpha(*str)) { 
+    /* Count alphanumeric char */
+    while (isalpha((int) *str)) {
        count++;
        str++;
-}
+    }
 
-if ( count==0 || count%2 ) { 
+    if ( count==0 || count%2 ) {
        problem++;
        return 0;
+    }
+
+    buf = (char *) tac_malloc(count+1);
+    strncpy(buf, head, count);
+    gec = buf;
+    str_up(buf);
+
+    for (i=1; i<=(count/2); i++) {
+       for (j=0; j<NUM; j++)
+           if(!strncmp(gec,week_days[j],2))
+               ret ^= week_day_val[j];
+       gec += 2;
+    }
+
+    /* We finished to use buffer so free it */
+    free(buf);
+
+    sec = time(NULL);
+    tms = localtime(&sec);
+    localtm = (tms->tm_hour)*60 + tms->tm_min;
+    ret = ( week_day_val[tms->tm_wday] & ret ) && time_calc(str,localtm);
+
+    if (ret>0)
+       return (1);
+    else
+       return (0);
 }
 
-buf=(char *)malloc(count+1);
-strncpy(buf,head,count);
-gec=buf;
-str_up(buf);
-
-for(i=1;i<=(count/2);i++) {
-       for (j=0;j<NUM;j++) {
-                if(!strncmp(gec,week_days[j],2)) {
-                        ret=ret^week_day_val[j];
-                }
-        }
-       gec+=2;
-}
-
-/* We finished to use buffer so free it */
-free(buf);
-
-sec=time(0);
-tms=localtime(&sec);
-localtm=(tms->tm_hour)*60+tms->tm_min;
-ret=( week_day_val[tms->tm_wday] & ret ) && time_calc(str,localtm);
-
-if (ret>0) 
-       return (1); 
-else 
-       return(0); 
-}
 
-str_up(str)
-char *str;
-{
-  while(*str) {
-       if(islower(*str)) *str=toupper(*str);
-       str++;
-  }
-}
+static int time_calc TAC_ARGS((char *str, int lct));
 
-int 
-time_calc(str,lct)
+static int
+time_calc(str, lct)
 char *str;
 int lct;
 {
-char *t1,*t2,*head;
-int say1,say2,count=0;
+    char *t1, *t2, *head;
+    int say1, say2, count=0;
 
-head=str;
+    head = str;
 
while (isdigit(*head) || *head=='-') {
   while (isdigit((int) *head) || *head=='-') {
         count++;
-       head++; 
- }
+       head++;
   }
 
-if (*str=='\0' || count!= TPL ) {
-       problem++;      
+    if ( *str=='\0' || count!= TPL ) {
+       problem++;
        return (0);
-}
+    }
 
-  t1=(char *) malloc(count);
-  strncpy(t1,str,count);       /*Put str value to t1*/
+    t1 = (char *) tac_malloc(count);
+    strncpy(t1, str, count);                   /* Put str value to t1 */
 
-  t2=(char *) strstr(t1,"-"); /* Find next time part */
+    t2 = (char *) strstr(t1,"-");              /* Find next time part */
 
-if (t2==NULL) {
-   free(t1);
-   problem++;
-   return(0);
-}
-       
-*t2='\0';t2++;
-       
-if ( strlen(t1)<4 || strlen(t2)<4 ) {
+    if (t2==NULL) {
        free(t1);
        problem++;
        return(0);
-}
-       say1=antoi(t1,2)*60+antoi(t1+2,2);
-       say2=antoi(t2,2)*60+antoi(t2+2,2);
+    }
 
-free(t1);
+    *t2++ = '\0';
 
-if (say1<=say2) { 
-       if( (lct>=say1) && (lct<=say2) ) return(1); 
-}
-else {
-       if( (lct>=say1) || (lct<=say2) ) return(1); 
+    if ( strlen(t1)<4 || strlen(t2)<4 ) {
+       free(t1);
+       problem++;
+       return(0);
+    }
+    say1 = antoi(t1,2)*60 + antoi(t1+2,2);
+    say2 = antoi(t2,2)*60 + antoi(t2+2,2);
+
+    free(t1);
+
+    if (say1 <= say2) {
+       if( (lct>=say1) && (lct<=say2) )
+           return(1);
+    } else {
+       if( (lct>=say1) || (lct<=say2) )
+           return(1);
+    }
+    return(0);
 }
-return(0);
 
-}
+static int antoi TAC_ARGS((char *str, int n));
 
-int 
-antoi(str,n)
-char *str;int n;
+static int
+antoi(str, n)
+char *str;
+int n;
 {
-char *buf;
-int ret;
+    char *buf;
+    int ret;
 
-  buf=(char *) malloc(n);
-  strncpy(buf,str,n);
-  ret=atoi(buf);
-  free(buf);
+    buf = (char *) tac_malloc(n);
+    strncpy(buf, str, n);
+    ret = atoi(buf);
+    free(buf);
 
-return(ret);
+    return(ret);
 }
index e8bb6fb..eac2096 100644 (file)
@@ -1,13 +1,14 @@
-#include<stdlib.h>
-#include<ctype.h>
-#include<stdio.h>
-#include<time.h>
-#include<string.h>
+#ifndef TIME_LIMIT_H
+#define TIME_LIMIT_H 1
+
+#include "tac_plus.h"
+
+
 #define NUM 10
 #define TPL  9 /* time part len */
 
-/*Global variables */
-static char* week_days[]={"SU","MO","TU","WE","TH","FR","SA","WK","WD","AL"};
-static long week_day_val[]={1,2,4,8,16,32,64,62,65,127};
 
-extern int time_limit_process();
+extern int time_limit_process TAC_ARGS((const char *str));
+
+
+#endif /* TIME_LIMIT_H */
index 2626115..cc9aac4 100644 (file)
@@ -113,12 +113,12 @@ TACACS, XTACACS and TACACS+
 ---------------------------
 
 Note that there are now at least 3 versions of authentication protocol
-that people commonly refer to as "TACACS".  
+that people commonly refer to as "TACACS".
 
 The first is ordinary tacacs, which was the first one offered on Cisco
 boxes and has been in use for many years. The second is an extension
 to the first, commonly called Extended Tacacs or XTACACS, introduced
-in 1990. 
+in 1990.
 
 The third one is TACACS+ (or T+ or tac_plus) which is what is documented
 here. TACACS+ is NOT COMPATIBLE with any previous versions of tacacs.
@@ -230,7 +230,7 @@ version of tacacs, use the convert.pl perl script as follows:
 
 convert.pl <passwd file> [-g] [<supplementary file>]
 
-1). If you have no supplementary file, simply omit it. 
+1). If you have no supplementary file, simply omit it.
 
 2). If the groupid field of your passwd file does NOT represent a
 valid acl number (e.g if it's really a unix passwd file this field is
@@ -267,7 +267,7 @@ Confusingly, even if your key does contain spaces, you should NEVER
 use double quotes when you configure the matching key on the NAS.
 
 During debugging, it may be convenient to temporarily switch off
-encryption by not specifying any key.  Be careful to remember to 
+encryption by not specifying any key.  Be careful to remember to
 switch encryption back on again after you've finished debugging.
 
 The current code does not support host-specific keys (left as an
@@ -294,7 +294,7 @@ Each user may belong to a group (but only one group).  Each group may
 in turn belong to one other group and so on ad infinitum.
 
 Users and groups are declared as follows. Here we declare two users
-"fred" and "lily", and two groups, "admin" and "staff". 
+"fred" and "lily", and two groups, "admin" and "staff".
 
 Fred is a member of group "admin", and group "admin" is in turn a
 member of group "staff". Lily is not a member of any group.
@@ -505,7 +505,7 @@ vty and console lines)
 NOTE: As soon as you issue this command, you will no longer be able to
 create new logins to your NAS without a functioning tacacs+ daemon
 appropriately configured with usernames and password, so make sure you
-have this ready. 
+have this ready.
 
 As a safety measure while setting up, we suggest you configure an
 enable secret and make it the last resort authentication method, so
@@ -621,7 +621,7 @@ the command:
 
 and permit all other arguments, since the last line will match any
 argument list. All other commands and services are permitted due to
-the "default service = permit" clause. 
+the "default service = permit" clause.
 
 Note: the default statement must be the first in the user clause
 
@@ -770,7 +770,7 @@ differently from command authorization.
 When authorizing these services, the NAS sends a request containing a
 number of attribute-value (AV) pairs, each having the form
 
-       attribute=value 
+       attribute=value
 
 (Note: during debugging, you may see AV pairs whose separator
 character is a "*" instead of a "=" sign. This is to signify that the
@@ -854,9 +854,9 @@ aaa authentication ppp default if-needed
 explicit login step if you do this (so it's the only possibility if
 you are using autoselect). This authentication gets done before you
 see the first LCP authorization request of course.  Typically you
-configure this by doing: 
+configure this by doing:
 
-aaa authentication ppp default tacacs+ 
+aaa authentication ppp default tacacs+
 int async 1
 ppp authentication chap
 
@@ -918,7 +918,7 @@ for each AV pair sent from the NAS:
        deny, or
 
        j). If the default is permit add the NAS AV pair to the output.
+
     k). After all AV pairs have been processed, for each mandatory
     DAEMON AV pair, if there is no attribute match already in the
     output list, add the AV pair (but add only ONE AV pair for each
@@ -963,7 +963,7 @@ user=fred {
     }
 
     service = ppp protocol = ip {
-       # Fred can run ip over ppp only if he uses one 
+       # Fred can run ip over ppp only if he uses one
         # of the following mandatory addresses. If he supplies no
        # address, the first one here will be mandated
 
@@ -1079,7 +1079,7 @@ follows (consult the API specification for more details).
     service -- (a digit, 1 to 7)
     status  -- (pass, fail, error, unknown)
 
-Unrecognized variables will appear as the string "unknown". 
+Unrecognized variables will appear as the string "unknown".
 
 If the program returns a status of 0, authorization is unconditionally
 permitted. No further processing is done on this request and no AV
@@ -1119,14 +1119,14 @@ NAS and change the authorization status if required.
 
 group = auth1 {
     # call /usr/bin/post_authorize passing it the username, port
-    # and current authorization status. 
+    # and current authorization status.
     after authorization "/usr/bin/post_authorize $user $port $status"
 }
 
 The AV pairs resulting from the authorization algorithm that the
 daemon proposes to return to the NAS, are supplied to the program on
 standard input, one AV pair per line, so they can be modified if
-required. 
+required.
 
 Fields from the incoming authorization packet which the NAS sent to
 the daemon can also be passed to the program on its command line by
@@ -1202,9 +1202,9 @@ daemon, where anything not explicitly permitted is denied by default.
 To configure command authorization on the NAS, issue the following NAS
 configuration commands:
 
-    aaa authorization commands 1 tacacs+ 
-    aaa authorization commands 15 tacacs+ 
-   
+    aaa authorization commands 1 tacacs+
+    aaa authorization commands 15 tacacs+
+
 
 This will make the NAS send tacacs+ requests for all level 1 (ordinary
 user) and level 15 (privileged level) commands on all lines/interfaces.
@@ -1213,12 +1213,12 @@ NOTE: As soon as you configure the above on your NAS, you will only be
 permitted to execute NAS commands which are permitted by your tacacs+
 daemon. So make sure you have configured, on the daemon, an
 authenticated user who is authorized to run commands, or you will be
-unable to do much on the NAS after turning on authorization. 
+unable to do much on the NAS after turning on authorization.
 
 Alternatively, or in addition, you may also want to configure the
 following:
 
-    aaa authorization commands 1 tacacs+ if-authenticated 
+    aaa authorization commands 1 tacacs+ if-authenticated
 
 This will use tacacs+ authorization for level 1 (user-level commands)
 but if problems arise, you can just switch off the tacacs+ server and
@@ -1260,7 +1260,7 @@ To get accounting records equivalent to previous versions of tacacs,
 the following is sufficient. "Stop" records contain elapsed time for
 connections and exec sessions.
 
-aaa accounting network stop-only tacacs+ 
+aaa accounting network stop-only tacacs+
 aaa accounting exec stop-only tacacs+
 
 
@@ -1273,7 +1273,7 @@ configured on the NAS but cannot be controlled via AAA.
 
 Here is an example of AAA configuration (with exec and network
 accounting enabled):
+
 NAS configuration:
 
 aaa new-model
@@ -1283,7 +1283,7 @@ aaa accounting exec wait-start tacacs+
 aaa accounting network wait-start tacacs+
 
 ! Example of AAA configuration for Exec:
-aaa authentication login execcheck tacacs+ 
+aaa authentication login execcheck tacacs+
 aaa authorization network tacacs+
 service exec-callback
 :
@@ -1291,7 +1291,7 @@ line 4
 login authentication execcheck
 
 ! Example of AAA configuration for ARAP:
-aaa authentication arap arapcheck tacacs+ 
+aaa authentication arap arapcheck tacacs+
 aaa authorization network tacacs+
 arap callback
 :
@@ -1300,7 +1300,7 @@ arap authentication arapcheck
 
 ! Example of AAA-specific configuration for PPP callback:
 aaa new-model
-aaa authentication ppp pppcheck tacacs+ 
+aaa authentication ppp pppcheck tacacs+
 aaa authorization network tacacs+
 :
 int async 6
@@ -1323,19 +1323,19 @@ user = foobar {
    service = arap {
         callback-dialstring=2345678
    }
-   service = exec { 
+   service = exec {
         callback-dialstring=3456789
         callback-line=7
         nocallback-verify=1
    }
-}  
+}
 
 
 
 
 DEBUGGING CONFIGURATION FILES
 -----------------------------
-       
+
 When creating configuration files, it is convenient to check their
 syntax using the -P flag to tac_plus e.g.
 
@@ -1350,7 +1350,7 @@ DEBUGGING A RUNNING SERVER
 There is a myriad of debugging values that can be used in conjunction
 with the -d flag to produce debugging output in /var/log/tac_plus.log.
 
-For example, starting the daemon with 
+For example, starting the daemon with
 
        tac_plus -C CONFIG -d 16
 
@@ -1479,10 +1479,10 @@ Q). How is the typical login authentication sequence done?
 A).    NAS sends START packet to daemon
        Daemon send GETUSER containing login prompt to NAS
        NAS prompts user for username
-       NAS sends pkt to daemon 
+       NAS sends pkt to daemon
        Daemon sends GETPASS containing password prompt to the NAS
        NAS prompts user for password
-       NAS sends pkt to daemon 
+       NAS sends pkt to daemon
        Daemon sends accept, reject or error to NAS
 
 
@@ -1545,7 +1545,7 @@ A).  The best way to restrict telnet access is by applying an outbound
 access list via the access class command (or equivalently, via the
 "acl" avpair). The NAS configuration command "access-class <n> out"
 for example applies a pre-defined standard IP access list (where n is
-a number from 1 through 99) that governs telnet access from a NAS. 
+a number from 1 through 99) that governs telnet access from a NAS.
 
 E.g. the following configuration commands permit outgoing Telnet
 access from line 1 on the NAS *only* to hosts on network 192.85.55.0:
@@ -1710,7 +1710,7 @@ Current attributes are:
 "callback-line"
 "callback-rotary"
 
-I expect more will be added over time. 
+I expect more will be added over time.
 
 Example records are thus:
 
@@ -1727,7 +1727,7 @@ Q). How do I limit the number of sessions a user can have?
 
 A). The TACACS+ daemon can enforce how many simultaneous sessions a
 given user is allowed to have.  You must compile the daemon with the
-MAXSESS symbol defined (see the Makefile).  
+MAXSESS symbol defined (see the Makefile).
 
 Maximum sessions are configured on the daemon for a user as follows:
 
@@ -1889,7 +1889,7 @@ source-ip: (This is now deprecated. It began in release 11.2(1.4),
 
 Tacacs+ syntax
 --------------
-               
+
 The following syntax is used on the public domain Tacacs+ server.
 
 username = domain {
@@ -1955,7 +1955,7 @@ A). Most attributes are mandatory i.e. if the daemon sends them to the
 NAS, the NAS must obey them or deny the authorization. This is the
 default. It is possible to mark attributes as optional, in which case
 a NAS which cannot support the attribute is free to simply ignore it
-without causing the authorization to fail. 
+without causing the authorization to fail.
 
 This was intended to be useful in cutover situations where you have
 multiple NASes running different versions of IOS, some of which
@@ -2058,7 +2058,7 @@ tacacs-server key <some key>
 2). A canned configuration for command authorization. This will allow
 user fred to login with password abcdef and to run the privileged
 (level 15) commands 'write terminal' and 'configure'. All other
-privileged commands will be denied. 
+privileged commands will be denied.
 
 The "none" keyword in the NAS configuration line means that if the
 tacacs+ server dies, any command will be allowed.
@@ -2112,7 +2112,7 @@ aaa authentication login default tacacs+
 ! authorize network services via tacacs+
 aaa authorization network tacacs+
 ! use tacacs+ for authenticating ppp users
-aaa authentication ppp default tacacs+ 
+aaa authentication ppp default tacacs+
 tacacs-server host <some host ip address>
 tacacs-server key <some key>
 interface Async1
@@ -2173,16 +2173,16 @@ The following AV pairs specify which service is being authorized. They
 are typically accompanied by protocol AV pairs and other, additional
 pairs from the lists below.
 
-service=arap 
+service=arap
 service=shell (for exec startup, and also for command authorizations)
-service=ppp 
+service=ppp
 service=slip
 
 service=system (not used).
 
 service=raccess
        Used for managing reverse telnet connections e.g.
+
        user = jim {
            login = cleartext lab
            service = raccess {
@@ -2191,7 +2191,7 @@ service=raccess
            }
        }
 
-       Requires IOS configuration 
+       Requires IOS configuration
 
                aaa authorization reverse-access tacacs+
 
@@ -2227,14 +2227,14 @@ protocol=cdp
 protocol=multilink
        Authorization of multilink PPP. See 'max-links' and 'load-threshold'.
 
-protocol=unknown 
+protocol=unknown
        For undefined/unsupported conditions. Should not occur under
        normal circumstances.
 
-cmd (EXEC) 
+cmd (EXEC)
        If the value of cmd is NULL e.g. the AV pair is cmd=, then
        this is an authorization request for starting an exec.
-       
+
        If cmd is non-null, this is a command authorization request,
        It contains the name of the command being authorized
        e.g. cmd=telnet
@@ -2248,7 +2248,7 @@ cmd-arg (EXEC)
        It is used internally by the daemon to construct a string
        which is then matched against the regular expressions which appear
        in a cmd clause in the configuration file.
-       
+
 acl (ARAP, EXEC)
        For ARAP this contains an access-list number.  For EXEC
        authorization it contains an access-class number, e.g. acl=2.
@@ -2261,7 +2261,7 @@ acl (ARAP, EXEC)
        An outbound access-class is the best way to restrict outgoing telnet
        connections. Note that a suitable access list (in this case,
        numbered 2) must be predefined on the NAS.
-               
+
 inacl (PPP/IP/IPX)
        This AV pair contains an IP or IPX input access list number
        for slip or PPP e.g. inacl=2. The access list itself must be
@@ -2290,7 +2290,7 @@ inacl#<n> (PPP/IP, PPP/IPX, 11.2(4)F)
        See also:
        sho ip access-lists
        sho ip interface
-       sho ipx access-lists 
+       sho ipx access-lists
        sho ipx interface
        debug aaa author
        debug aaa per-user
@@ -2323,7 +2323,7 @@ outacl#<n> (PPP/IP, PPP/IPX, 11.2(4)F)
        See also:
        sho ip access-lists
        sho ip interface
-       sho ipx access-lists 
+       sho ipx access-lists
        sho ipx interface
        debug aaa author
        debug aaa per-user
@@ -2336,7 +2336,7 @@ routing (SLIP, PPP/IP)
        Equivalent to the /routing flag in slip and ppp commands. Can
        have as its value the string "true" or "false".
 
-timeout (11.0 onwards, ARAP, EXEC) 
+timeout (11.0 onwards, ARAP, EXEC)
        Sets the time until an arap or exec session disconnects
        unconditionally (in minutes), e.g. timeout=60
 
@@ -2350,20 +2350,20 @@ noescape (EXEC)
        noescape option to the username configuration command.  Can
        have as its value the string "true" or "false",
        e.g. noescape=true
-       
+
 nohangup (EXEC)
        During exec startup, this specifies "nohangup", like the
        nohangup option to the username configuration command.  Can
        have as its value the string "true" or "false",
        e.g. nohangup=true
-       
+
 priv-lvl (EXEC)
        Specifies the current privilege level for command
        authorizations, a number from zero to 15 e.g. priv_lvl=5.
 
-       Note: in 10.3 this attribute was priv_lvl i.e. 
+       Note: in 10.3 this attribute was priv_lvl i.e.
        it contained an underscore instead of a hyphen.
-       
+
 zonelist (ARAP)
        An Appletalk zonelist for arap equivalent to the line
        configuration command "arap zonelist" e.g. zonelist=5
@@ -2423,7 +2423,7 @@ route#<n> (PPP/IP/IPX, 11.2(4)F)
        route#2="4.0.0.0 255.0.0.0"
 
 
-       or, for IPX, 
+       or, for IPX,
 
        route#1="4C000000 ff000000 30.12.3.4"
        route#2="5C000000 ff000000 30.12.3.5"
@@ -2439,7 +2439,7 @@ callback-rotary (11.1 onwards, valid for ARAP, EXEC, SLIP or PPP)
        to use for callback e.g. callback-rotary=34. Not valid for ISDN.
 
 callback-dialstring (11.1 onwards, valid for ARAP, EXEC, SLIP or PPP)
-       sets the telephone number for a callback e.g. 
+       sets the telephone number for a callback e.g.
        callback-dialstring=408-555-1212. Not valid for ISDN.
 
 callback-line (11.1 onwards, valid for ARAP, EXEC, SLIP or PPP)
@@ -2455,7 +2455,7 @@ idletime (11.1 onwards, EXEC)
        Sets a value, in minutes, after which an IDLE session will be
        terminated. N.B. Does NOT work for PPP.
 
-tunnel-id (11.2 onwards, PPP/VPDN) 
+tunnel-id (11.2 onwards, PPP/VPDN)
        This AV pair specifies the username that will be used to
        authenticate the tunnel over which the individual user MID
        will be projected.  This is analogous to the "NAS name" in the
@@ -2463,7 +2463,7 @@ tunnel-id (11.2 onwards, PPP/VPDN)
 
 ip-addresses (11.2 onwards, PPP/VPDN)
        This is a space separated list of possible IP addresses that
-       can be used for the end-point of the tunnel.  
+       can be used for the end-point of the tunnel.
 
        In 11.2(5.4)F, this attribute was extended as follows:
 
@@ -2471,7 +2471,7 @@ ip-addresses (11.2 onwards, PPP/VPDN)
        For example the avpair can now be written as
 
        ip-addresses = 172.21.9.26,172.21.9.15,172.21.9.4
+
        2) '/' is considered a priority delimiter. When you have a
        number of Home Gateway routers, it is desirable to consider some
        as the primary routers and some as backup routers.
@@ -2483,11 +2483,11 @@ ip-addresses (11.2 onwards, PPP/VPDN)
        For example in the following avpair:
 
        ip-addresses = "172.21.9.26 / 172.21.9.15 / 172.21.9.4"
+
        172.21.9.26 is considered to be priority 1
        172.21.9.15 is considered to be priority 2
        172.21.9.4  is considered to be priority 3
+
        The NAS will try to forward the users to 172.21.9.26, before
        trying 172.21.9.15.  If the NAS can't forward users to
        172.21.9.26, it will try 172.21.9.15 next. If it fails with
@@ -2510,7 +2510,7 @@ gw-password (PPP/VPDN, 11.2(3.4)F, 11.2(4.0.2)F)
 rte-ftr-in#<n> (PPP -- IP/IPX, 11.2(4)F)
        This AV pair specifies an input access list definition to be
        installed and applied to routing updates on the current
-       interface, for the duration of the current connection. 
+       interface, for the duration of the current connection.
 
        For IP, both standard and extended Cisco access list syntax is
        recognised, but it is an error to mix the two within a given
@@ -2536,11 +2536,11 @@ rte-ftr-in#<n> (PPP -- IP/IPX, 11.2(4)F)
 
        show ip access-lists
        show ip protocols
-       sho ipx access-lists 
+       sho ipx access-lists
        sho ipx interface
        debug aaa author
        debug aaa per-user
-       
+
        Related IOS commands:
        IP:
                router <routing process identifier>
@@ -2553,7 +2553,7 @@ rte-ftr-in#<n> (PPP -- IP/IPX, 11.2(4)F)
 rte-ftr-out#<n> (PPP/IP, 11.2(4)F)
        This AV pair specifies an input access list definition to be
        installed and applied to routing updates on the current
-       interface, for the duration of the current connection. 
+       interface, for the duration of the current connection.
 
        For IP, both standard and extended Cisco access list syntax is
        recognised, but it is an error to mix the two within a given
@@ -2575,13 +2575,13 @@ rte-ftr-out#<n> (PPP/IP, 11.2(4)F)
 
        See also:
 
-       sho ipx access-lists 
+       sho ipx access-lists
        sho ipx interface
        show ip access-lists
        show ip protocols
        debug aaa author
        debug aaa per-user
-       
+
        Related IOS commands:
        IP:
                router <routing process identifier>
@@ -2620,7 +2620,7 @@ route#<n> (PPP/IP/IPX, 11.2(4)F)
        route#2="4.0.0.0 255.0.0.0"
 
 
-       or, for IPX, 
+       or, for IPX,
 
        route#1="4C000000 ff000000 30.12.3.4"
        route#2="5C000000 ff000000 30.12.3.5"
@@ -2630,7 +2630,7 @@ route#<n> (PPP/IP/IPX, 11.2(4)F)
        sho ipx route
        debug aaa author
        debug aaa per-user
-       
+
 
 sap-fltr-in#<n> (PPP/IPX, 11.2(4)F)
        This AV pair specifies an input sap filter access list
@@ -2644,7 +2644,7 @@ sap-fltr-in#<n> (PPP/IPX, 11.2(4)F)
 
        Attributes are sorted numerically before being applied.
 
-       sho ipx access-lists 
+       sho ipx access-lists
        sho ipx interface
        debug aaa author
        debug aaa per-user
@@ -2664,7 +2664,7 @@ sap-fltr-out#<n> (PPP/IPX 11.2(4)F)
 
        Attributes are sorted numerically before being applied.
 
-       sho ipx access-lists 
+       sho ipx access-lists
        sho ipx interface
        debug aaa author
        debug aaa per-user
@@ -2778,24 +2778,24 @@ old-prompts (PPP/SLIP)
        appear identical to those of earlier systems (tacacs and
        xtacacs). This will allow administrators to upgrade from
        tacacs/xtacacs to T+ transparently to users.
+
        The difference between the prompts is as follows:
+
        In xtacacs, when the user types "slip" or "ppp" the system
        prompts for an address followed by a password, whereas T+
        prompts only for an address.
+
        In xtacacs, if the user types "slip host" or "ppp host", the
        system prompts for a password. In T+, there is no prompt.
+
        Using this attribute, T+ can be made to mimic the prompting
        behaviour of xtacacs, by configuring network authorization on
        IOS, and using the "old-prompts=true" attribute value pair for
        slip and ppp/ip, viz:
+
        user = joe {
            global = cleartext foo
+
            service = exec {
            }
            service = slip {
@@ -2806,7 +2806,7 @@ old-prompts (PPP/SLIP)
                default attribute = permit
                old-prompts=true
            }
-       }        
+       }
 
        i.e. the prompts are controlled by the addition of the
        "old-prompts=true" attribute.
diff --git a/utils.c b/utils.c
index b597e70..43b50f3 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (c) 1995-1998 by Cisco systems, Inc.
 
    Permission to use, copy, modify, and distribute this software for
    FITNESS FOR A PARTICULAR PURPOSE.
 */
 
-#include "tac_plus.h"
 
-#ifdef STDLIB_MALLOC
+#include "tac_plus.h"
 
-#include <stdlib.h>
+#include <stdlib.h>    /* malloc() can be found in <stdlib.h> OR <malloc.h> */
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include <string.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>     /* for "struct flock" */
+#endif
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+#ifdef HAVE_SYS_SYSLOG_H
+#include <sys/syslog.h>
+#endif
 
-#else /* !STDLIB_MALLOC */
+#include "utils.h"
+#include "report.h"
+#include "main.h"
 
-#include <malloc.h>
 
-#endif /* STDLIB_MALLOC */
+void *tac_malloc TAC_ARGS((int size));
 
-char *
+void *
 tac_malloc(size)
 int size;
 {
@@ -49,9 +66,11 @@ int size;
     return (p);
 }
 
-char *
+void *tac_realloc TAC_ARGS((void *ptr, int size));
+
+void *
 tac_realloc(ptr, size)
-char *ptr;
+void *ptr;
 int size;
 {
     char *p;
@@ -70,6 +89,9 @@ int size;
     return (p);
 }
 
+void tac_exit TAC_ARGS((int status)) G_GNUC_NORETURN;
+
+void
 tac_exit(status)
 int status;
 {
@@ -78,9 +100,11 @@ int status;
     exit(status);
 }
 
+char *tac_strdup TAC_ARGS((const char *p));
+
 char *
 tac_strdup(p)
-char *p;
+const char *p;
 {
     char *n = strdup(p);
 
@@ -91,6 +115,8 @@ char *p;
     return (n);
 }
 
+char *tac_make_string TAC_ARGS((u_char *p, int len));
+
 char *
 tac_make_string(p, len)
 u_char *p;
@@ -99,7 +125,7 @@ int len;
     char *string;
     int new_len = len;
 
-    /* 
+    /*
      * Add space for a null terminator if needed. Also, no telling
      * what various mallocs will do when asked for a length of zero.
      */
@@ -113,12 +139,16 @@ int len;
     return (string);
 }
 
-/* return a pointer to the end of substring in string, or NULL. Substring 
+/* return a pointer to the end of substring in string, or NULL. Substring
    must begin at start of string.
 */
-char *
+
+const char *tac_find_substring TAC_ARGS((const char *substring, const char *string));
+
+const char *
 tac_find_substring(substring, string)
-char *substring, *string;
+const char *substring;
+const char *string;
 {
     int len;
 
@@ -131,7 +161,7 @@ char *substring, *string;
     if (len > (int) strlen(string)) {
        return(NULL);
     }
-       
+
     if (strncmp(substring, string, len)) {
        /* no match */
        return(NULL);
@@ -169,11 +199,11 @@ bcopy(s1, s2, len)
     while (--n);
 }
 
-int 
+int
 bcmp(s1,s2,n)
     char *s1,*s2;
     int n;
-{     
+{
     while (n-- > 0) {
        if (*s1++ != *s2++) {
            return(1);
@@ -187,9 +217,11 @@ bcmp(s1,s2,n)
    acquiring the lock. The lock disappears when we close the file.
 
    Note that if the locked file is on an NFS-mounted partition, you
-   are at the mercy of SUN's lockd, which is probably a bad idea 
+   are at the mercy of SUN's lockd, which is probably a bad idea
 */
 
+int tac_lockfd TAC_ARGS((char *filename, int lockfd));
+
 int
 tac_lockfd (filename, lockfd)
 char *filename;
@@ -216,7 +248,7 @@ int lockfd;
                sleep(1);
                continue;
            } else {
-               syslog(LOG_ERR, "fcntl lock error status %d on %s %d %s", 
+               syslog(LOG_ERR, "fcntl lock error status %d on %s %d %s",
                       status, filename, lockfd, sys_errlist[errno]);
                return(0);
            }
@@ -226,7 +258,7 @@ int lockfd;
     }
 
     if (errno != 0) {
-       syslog(LOG_ERR, "Cannot lock %s fd %d in %d tries %s", 
+       syslog(LOG_ERR, "Cannot lock %s fd %d in %d tries %s",
               filename, lockfd, tries+1, sys_errlist[errno]);
 
        /* who is hogging this lock */
@@ -248,9 +280,9 @@ int lockfd;
 
        if (debug & DEBUG_LOCK_FLAG) {
            syslog(LOG_ERR, "Lock on %s is being held by sys=%u pid=%d",
-                  filename, 
+                  filename,
 #ifdef HAS_FLOCK_SYSID
-                  flock.l_sysid, 
+                  flock.l_sysid,
 #else
                   0,
 #endif
@@ -260,7 +292,7 @@ int lockfd;
     }
 
     if (debug & DEBUG_LOCK_FLAG) {
-       syslog(LOG_ERR, "Successfully locked %s fd %d after %d tries", 
+       syslog(LOG_ERR, "Successfully locked %s fd %d after %d tries",
               filename, lockfd, tries+1);
     }
     return(1);
@@ -270,10 +302,11 @@ int lockfd;
    releasing a lock. The lock dies when we close the file.
 
    Note that if the locked file is on an NFS-mounted partition, you
-   are at the mercy of SUN's lockd, which is probably a bad idea 
+   are at the mercy of SUN's lockd, which is probably a bad idea
 */
 
-int
+#if 0 /* unused */
+static int
 tac_unlockfd (filename,lockfd)
 char *filename;
 int lockfd;
@@ -292,14 +325,195 @@ int lockfd;
 
     status = fcntl(lockfd, F_UNLCK, &flock);
     if (status == -1) {
-       syslog(LOG_ERR, "fcntl unlock error status %d on %s %d %s", 
+       syslog(LOG_ERR, "fcntl unlock error status %d on %s %d %s",
               status, filename, lockfd, sys_errlist[errno]);
        return(1);
     }
 
     if (debug & DEBUG_LOCK_FLAG) {
-       syslog(LOG_ERR, "Successfully unlocked %s fd %d", 
+       syslog(LOG_ERR, "Successfully unlocked %s fd %d",
               filename, lockfd);
     }
     return(0);
 }
+#endif /* unused */
+
+/* Management of bidirectional lists.
+*/
+
+#ifdef TAC_LIST_PARANOIA
+
+static void tac_list_check_magic TAC_ARGS((const struct tac_list *list));
+
+static void
+tac_list_check_magic(list)
+const struct tac_list *list;
+{
+   if (list->_magic != TAC_LIST_MAGIC)
+       report(LOG_ERR, "MAGIC fail for tac_list");
+}
+
+static void tac_list_node_check_magic TAC_ARGS((const struct tac_list_node *node));
+
+static void
+tac_list_node_check_magic(node)
+const struct tac_list_node *node;
+{
+   if (node->_magic != TAC_LIST_NODE_MAGIC)
+       report(LOG_ERR, "MAGIC fail for tac_list_node");
+}
+#else /* TAC_LIST_PARANOIA */
+
+#define tac_list_check_magic(list)
+#define tac_list_node_check_magic(node)
+
+#endif /* TAC_LIST_PARANOIA */
+
+
+void tac_list_init TAC_ARGS((struct tac_list *list));
+
+void
+tac_list_init(list)
+struct tac_list *list;
+{
+#ifdef TAC_LIST_PARANOIA
+    list->_magic = TAC_LIST_MAGIC;
+#endif
+    list->_head = NULL;
+    list->_tail = NULL;
+
+    tac_list_check_magic(list);
+}
+
+void tac_list_node_init TAC_ARGS((struct tac_list_node *node));
+
+void
+tac_list_node_init(node)
+struct tac_list_node *node;
+{
+#ifdef TAC_LIST_PARANOIA
+    node->_magic = TAC_LIST_NODE_MAGIC;
+#endif
+    node->_list = NULL;
+
+    tac_list_node_check_magic(node);
+}
+
+struct tac_list *tac_list_node_get_list TAC_ARGS((struct tac_list_node *node));
+
+struct tac_list *
+tac_list_node_get_list(node)
+struct tac_list_node *node;
+{
+    tac_list_node_check_magic(node);
+
+    return (node->_list);
+}
+
+struct tac_list_node *tac_list_first_node TAC_ARGS((struct tac_list *list));
+
+struct tac_list_node *
+tac_list_first_node(list)
+struct tac_list *list;
+{
+    tac_list_check_magic(list);
+
+    return (list->_head);
+}
+
+#if 0 /* unused */
+struct tac_list_node *tac_list_last_node TAC_ARGS((struct tac_list *list));
+
+struct tac_list_node *
+tac_list_last_node(list)
+struct tac_list *list;
+{
+    tac_list_check_magic(list);
+
+    return (list->_tail);
+}
+#endif /* unused */
+
+void tac_list_addhead TAC_ARGS((struct tac_list *list, struct tac_list_node *node));
+
+void
+tac_list_addhead(list, node)
+struct tac_list *list;
+struct tac_list_node *node;
+{
+    tac_list_check_magic(list);
+    tac_list_node_check_magic(node);
+
+    if ((node->_next = list->_head))
+       node->_next->_prev = node;
+    list->_head = node;
+    node->_prev = NULL;
+    if (!list->_tail)
+       list->_tail = node;
+    node->_list = list;
+}
+
+void tac_list_addtail TAC_ARGS((struct tac_list *list, struct tac_list_node *node));
+
+void
+tac_list_addtail(list, node)
+struct tac_list *list;
+struct tac_list_node *node;
+{
+    tac_list_check_magic(list);
+    tac_list_node_check_magic(node);
+
+    if ((node->_prev = list->_tail))
+       node->_prev->_next = node;
+    list->_tail = node;
+    node->_next = NULL;
+    if (!list->_head)
+       list->_head = node;
+    node->_list = list;
+}
+
+struct tac_list_node *tac_list_node_next TAC_ARGS((struct tac_list_node *node));
+
+struct tac_list_node *
+tac_list_node_next(node)
+struct tac_list_node *node;
+{
+    tac_list_node_check_magic(node);
+
+    return (node->_next);
+}
+    
+#if 0 /* unused */
+struct tac_list_node *tac_list_node_prev TAC_ARGS((struct tac_list_node *node));
+
+struct tac_list_node *
+tac_list_node_prev(node)
+struct tac_list_node *node;
+{
+    tac_list_node_check_magic(node);
+
+    return (node->_prev);
+}
+#endif /* unused */
+
+void tac_list_node_remove TAC_ARGS((struct tac_list_node *node));
+
+void
+tac_list_node_remove(node)
+struct tac_list_node *node;
+{
+    tac_list_node_check_magic(node);
+    tac_list_check_magic(node->_list);
+
+    if (node->_next)
+       node->_next->_prev = node->_prev;
+    else
+       node->_list->_tail = node->_prev;
+
+    if (node->_prev)
+       node->_prev->_next = node->_next;
+    else
+       node->_list->_head = node->_next;
+
+    node->_list = NULL;
+}
diff --git a/utils.h b/utils.h
new file mode 100644 (file)
index 0000000..f8c39e8
--- /dev/null
+++ b/utils.h
@@ -0,0 +1,59 @@
+#ifndef UTILS_H
+#define UTILS_H 1
+
+#include "tac_plus.h"
+
+#include <sys/types.h>         /* for u_* */
+
+
+/* Configurable:
+ */
+#define TAC_LIST_PARANOIA 1
+
+
+/* Bidirectional lists */
+
+#ifdef TAC_LIST_PARANOIA
+#define TAC_LIST_MAGIC      (0xBEF78147U)
+#define TAC_LIST_NODE_MAGIC (0x297DA735U)
+#endif
+
+struct tac_list {
+#ifdef TAC_LIST_PARANOIA
+    unsigned _magic;
+#endif
+    struct tac_list_node *_head, *_tail;
+};
+
+struct tac_list_node {
+#ifdef TAC_LIST_PARANOIA
+    unsigned _magic;
+#endif
+    struct tac_list_node *_next, *_prev;
+    struct tac_list *_list;
+};
+
+
+extern void *tac_malloc TAC_ARGS((int size));
+extern void *tac_realloc TAC_ARGS((void *ptr, int size));
+extern void tac_exit TAC_ARGS((int status)) G_GNUC_NORETURN;
+extern char *tac_strdup TAC_ARGS((const char *p));
+extern char *tac_make_string TAC_ARGS((u_char *p, int len));
+extern const char *tac_find_substring TAC_ARGS((const char *substring, const char *string));
+extern int tac_lockfd TAC_ARGS((char *filename, int lockfd));
+
+/* Bidirectional lists: */
+
+extern void tac_list_init TAC_ARGS((struct tac_list *list));
+extern void tac_list_node_init TAC_ARGS((struct tac_list_node *node));
+extern struct tac_list *tac_list_node_get_list TAC_ARGS((struct tac_list_node *node));
+struct tac_list_node *tac_list_first_node TAC_ARGS((struct tac_list *list));
+struct tac_list_node *tac_list_last_node TAC_ARGS((struct tac_list *list));
+extern void tac_list_addhead TAC_ARGS((struct tac_list *list, struct tac_list_node *node));
+extern void tac_list_addtail TAC_ARGS((struct tac_list *list, struct tac_list_node *node));
+extern struct tac_list_node *tac_list_node_next TAC_ARGS((struct tac_list_node *node));
+extern struct tac_list_node *tac_list_node_prev TAC_ARGS((struct tac_list_node *node));
+extern void tac_list_node_remove TAC_ARGS((struct tac_list_node *node));
+
+
+#endif /* UTILS_H */