1 diff --git a/.exrc b/.exrc
9 diff --git a/Makefile.am b/Makefile.am
11 index 0000000..8d609b1
15 +# Please NOTE: None of the TACACS code available here comes with any
16 +# warranty or support.
17 +# Copyright (c) 1995-1998 by Cisco systems, Inc.
19 +# Permission to use, copy, modify, and distribute this software for any
20 +# purpose and without fee is hereby granted, provided that this
21 +# copyright and permission notice appear on all copies of the software and
22 +# supporting documentation, the name of Cisco Systems, Inc. not be used
23 +# in advertising or publicity pertaining to distribution of the
24 +# program without specific prior permission, and notice be given
25 +# in supporting documentation that modification, copying and distribution is by
26 +# permission of Cisco Systems, Inc.
28 +# Cisco Systems, Inc. makes no representations about the suitability of this
29 +# software for any purpose. THIS SOFTWARE IS PROVIDED ``AS IS''
30 +# AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
31 +# LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
32 +# FOR A PARTICULAR PURPOSE.
35 +AUTOMAKE_OPTIONS = foreign
37 +sbin_PROGRAMS = tac_plus
38 +bin_PROGRAMS = generate_passwd
39 +man_MANS = tac_plus.1
40 +noinst_MANS = tac_regexp.3
41 +tacacssysconfdir = $(sysconfdir)/tacacs
42 +tacacssysconf_DATA = tac_plus.cfg
55 + $(tacacssysconf_DATA) \
59 +generate_passwd_SOURCES = generate_passwd.c
65 + cfgfile.c cfgfile.h \
66 + cfgeval.c cfgeval.h \
67 + choose_authen.c choose_authen.h \
68 + default_fn.c default_fn.h \
69 + default_v0_fn.c default_v0_fn.h \
70 + do_acct.c do_acct.h \
71 + do_author.c do_author.h \
74 + encrypt.c encrypt.h \
81 + programs.c programs.h \
85 + sendauth.c sendauth.h \
86 + sendpass.c sendpass.h \
87 + time_limit.c time_limit.h \
93 +EXTRA_tac_plus_SOURCES = $(cond)
94 +tac_plus_LDFLAGS = $(conf_LDFLAGS)
95 +# $(use_o) has to be BEFORE $(conf_LDADD)! (for library dependencies)
96 +tac_plus_LDADD = $(use_o) $(conf_LDADD)
97 +tac_plus_DEPENDENCIES = $(use_o)
99 +use_o = $(filter %.o,$(use:.c=.o))
102 +cond_DB_MYSQL = db_mysql.c db_mysql.h
103 +cond_DB_NULL = db_null.c db_null.h
104 +cond_DB_PGSQL = db_pgsql.c db_pgsql.h
105 +cond_USE_LDAP = ldap_author.c ldap_author.h
106 +cond_MAXSESS = maxsess.c maxsess.h
107 +cond_MSCHAP = md4.c md4.h
108 +cond_SKEY = skey_fn.c skey_fn.h
109 +cond_USE_PAM = tac_pam.c tac_pam.h
110 +cond_TCPWRAPPER = tcpwrap.c tcpwrap.h
111 +cond_WITH_INCLUDED_REGEX = \
112 + tac_regexp.c tac_regexp.h
124 + $(cond_TCPWRAPPER) \
125 + $(cond_WITH_INCLUDED_REGEX)
128 +# These rules were not migrated from Makefile.in as I don't have
129 +# (and I don't know) 'purify' tool:
131 +# purecov: $(OBJS) $(LIBS)
132 +# purecov -follow-child-processes -handle-signals=SIGTERM \
133 +# -append-logfile -log-file=purecov.log \
134 +# -cache-dir=`pwd` \
135 +# $(CC) -o tac_plus $(CFLAGS) $(OBJS) $(LIBS) $(OSLIBS)
137 +# purify: $(OBJS) $(LIBS)
138 +# purify -follow-child-processes=yes -log-file=./tac_plus_purify.log \
139 +# -handle-signals=SIGTERM -cache-dir=. \
140 +# $(CC) -o tac_plus $(CFLAGS) $(OBJS) $(LIBS) $(OSLIBS)
141 diff --git a/README.LDAP b/README.LDAP
143 index 0000000..755b19e
147 + LDAP Authentification with Tacacs+
148 + ----------------------------------
151 +Author : Harpes Patrick (patrick.harpes@tudor.lu)
152 + Jahnen Andreas (andreas.jahnen@tudor.lu)
158 + tac_ldap is free software; you can redistribute it
159 + and/or modify it under the terms of the GNU General Public License
160 + as published by the Free Software Foundation; either version 2,
161 + or (at your option) any later version.
164 +This document aim to describe how to perform LDAP authentification for tacacs+.
170 +1) tac_plus.F4.0.3-v8.alpha.tar.gz
171 + This package includes the original CISCO tacacs+ package from http://www.gazi.edu.tr/tacacs/
173 + This package has been developped using the openldap libraries version 2.0.7
174 + OpenLDAP is available from www.openldap.org
175 +3) GCC and other GNU developpment tools (make...)
176 +4) A running LDAP server (test has been made using Lotus Domino LDAP server version 5.0.x and
181 + ------------ ----------------
182 + - Server - - Notes DOMINO -
183 + ---------------- - running -____LDAP____- LDAP Server -
184 + - CISCO Dialup -__tacacs+_____- tacacs+ - - or -
185 + - Router - - - - other LDAP -
186 + ---------------- ------------ - Server -
189 +The CISCO router sends tacacs+ request to the tacacs+ server. This one uses the LDAP
190 +server to authentificate the user.
193 +HowTo configure the CISCO router?
194 +---------------------------------
196 +There are good documentations available on how to set up the CISCO router for using
197 +tacacs+. This documents can be found on the tacacs+ homepage http://www.gazi.edu.tr/tacacs/
199 +HowTo install the tacacs+ package with LDAP support?
200 +----------------------------------------------------
202 +To enable the LDAP support on the tacacs+ package, you have to perform the following steps:
204 + 1. Install the Open LDAP package (version 2.0.7) (www.openldap.org)
205 + Refer to the INSTALL document to build this package.
207 + 2. Unpack the tacacs+ package in /usr/local/src
208 + # tar -zxvf tac_plus.F4.0.3-v8.alpha.tar.gz
210 + 3. Use the configure script to create the Makefiles
212 + # cd /usr/local/src/tac_plus.F5.0.0.alpha/
213 + # ./configure --with-ldap
215 + You can use ./configure --help to get more options
217 + 4. Compile the package
221 + 5. Set your LD_LIBRARY_PATH to include the LDAP libraries
223 + # LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH
226 +HowTo configure tacacs+ for using the LDAP support
227 +--------------------------------------------------
229 +To use the LDAP authentification, use the following simple tacacs+ configuration file
231 + key = "your tacacs key"
232 + accounting file = /var/log/tac-plus/tac_plus.log
233 + default authentification = ldap "ldap://<Hostname of your LDAP server>"
235 + service = ppp protocol = ip {
240 +For more information on the configuration file please use the complete tacacs+ documentation.
243 +How to start the tacacs+ daemon
244 +-------------------------------
246 +Make sure your LD_LIBRARY_PATH includes the LDAP libraries.
247 +As root, start the tacacs daemon:
248 + # /usr/local/src/tac_plus.F4.0.3-v8.alpha/tac_plus -C tac_plus.cfg
251 +How to configure the LDAP server
252 +--------------------------------
254 +a) Notes Domino LDAP server
255 +---------------------------
257 +You have to enable the Domino server task "LDAP" with the Administration Tool. You
258 +can do this with the command "laod ldap" at the server console or with the help of
259 +the Tools Menu of the server tab (Tools -> Task -> Start "LDAP Server").
261 +You can define which attributes of your Domino Directory are accessible by
262 +anonymous users and if it is allowed to write to your Domino Directory using LDAP in
263 +a Configuration document. You have to specify "Use these settings as the default
264 +settings for all servers" in the Basic tab of the Configuration document to display
265 +the LDAP options tab. There you are able to adjust the settings for a your LDAP server.
267 +For additional information see the IBM Red Book "Getting the most from your Domino
268 +Directory" (11/2000), which you can downlaod from http://www.redbooks.ibm.com.
274 +It is also possible to use OpenLDAP for this kind of authentification. Please look at
275 +the documentation at http://www.openldap.org for details how to install the server.
281 +The here described tacacs+ queries are not quering any of the fields stored in your LDAP
282 +server. We only try to log in and this is the "test" we perform here.
284 +Pleae note that the passwords are not send encrypted. You have to make sure that it is
285 +not possible to sniff them. In general is there no support from tacacs+ to support encrypted
287 +It is maybe possible to use OpenLDAP with TLS support to encrypt the passwords and use a
288 +secure LDAP server. This is also supported by Domino and OpenLDAP. But this is not implemented.
292 + Harpes Patrick (patrick.harpes@tudor.lu) and Jahnen Andreas (andreas.jahnen@tudor.lu)
293 diff --git a/README.PAM b/README.PAM
294 index 0c1d468..7cbd4b4 100644
297 @@ -36,5 +36,3 @@ into tac_plus.conf.
300 Max Liccardo <ravel@tiscalinet.it>
303 diff --git a/acconfig.h b/acconfig.h
305 index 0000000..72e7998
314 +#ifndef TAC_PLUS_CONFIG_H
315 +#define TAC_PLUS_CONFIG_H 1
320 +/* --maintainer-mode
321 + * Sets "/etc/tacacs/tac_plus.cfg" as default config file
323 +#undef MAINTAINER_MODE
325 +/* Missing socklen_t in <sys/socket.h>
326 + * We don't use 'typedef' to not to yet require <stddef.h> included here.
330 +/* Define this if you have shadow passwords in /etc/passwd and
331 + * /etc/shadow. Note that you usually need to be root to read
333 +#undef SHADOW_PASSWORDS
335 +/* Check for some fields in <pwd.h>/struct passwd and <utmp.h>/struct utmp
337 +#undef HAVE_PASSWD_PW_AGE
338 +#undef HAVE_PASSWD_PW_COMMENT
339 +#undef HAVE_UTMP_UT_HOST
341 +/* All OSes detected by configure.in:
363 +/* --enable-maxsess */
365 +/* --with-libwrap */
369 +/* --with-mschap[=des] */
372 +/* --with-tac[ug]id */
373 +#undef TACPLUS_USERID
374 +#undef TACPLUS_GROUPID
375 +/* --with-tacplus_pid */
376 +#undef TACPLUS_PIDFILE
377 +/* --with-included-regex */
378 +#undef WITH_INCLUDED_REGEX
383 +/* Keep in sync with configure.in */
384 +#define _XOPEN_SOURCE 1 /* for unistd.h/crypt() */
385 +#define _XOPEN_SOURCE_EXTENDED 1 /* for pwd.h/{set,end}pwent(), sys/wait.h/wait3() */
386 +#define _BSD_SOURCE 1 /* for u_{char,short,int} & string.h/bcopy() */
387 +#define _OSF_SOURCE 1 /* for u_{char,short,int} (on Alpha OSF1) */
388 +#define __EXTENSIONS__ 1 /* for u_{char,short,int} (on Sparc Solaris) */
390 +#if SIZEOF_UNSIGNED_SHORT == 4
391 +typedef unsigned short tac_uint32;
393 +#if SIZEOF_UNSIGNED_INT == 4
394 +typedef unsigned int tac_uint32;
396 +#if SIZEOF_UNSIGNED_LONG == 4
397 +typedef unsigned long tac_uint32;
399 +#error "Unable to find 32-bit unsigned int for TAC_UINT32 type"
400 +#endif /* SIZEOF_UNSIGNED_LONG */
401 +#endif /* SIZEOF_UNSIGNED_INT */
402 +#endif /* SIZEOF_UNSIGNED_SHORT */
405 +#endif /* TAC_PLUS_CONFIG_H */
406 diff --git a/acct.c b/acct.c
407 index 315064f..2145cef 100644
411 FITNESS FOR A PARTICULAR PURPOSE.
415 #include "tac_plus.h"
418 +#include <netinet/in.h> /* for ntohl() */
424 +#include "do_acct.h"
426 +#include "do_author.h" /* for "struct identity" */
427 +#include "cfgfile.h"
430 +#include "maxsess.h"
437 +static void account TAC_ARGS((u_char *pak));
441 * Come here when we receive an Start Accounting packet
446 -/* For DB accounting */
450 +void accounting TAC_ARGS((u_char *pak));
454 @@ -37,8 +56,8 @@ u_char *pak;
455 struct acct *acct_pak;
458 - u_char *read_packet();
463 if (debug & DEBUG_ACCT_FLAG)
464 report(LOG_DEBUG, "Start accounting request");
465 @@ -59,7 +78,7 @@ u_char *pak;
469 - if (len != ntohl(hdr->datalength)) {
470 + if (len != (unsigned long) ntohl(hdr->datalength)) {
471 send_error_reply(TAC_PLUS_ACCT, NULL);
474 @@ -69,7 +88,9 @@ u_char *pak;
479 +static void account TAC_ARGS((u_char *pak));
485 @@ -123,6 +144,8 @@ u_char *pak;
487 identity.priv_lvl = acct_pak->priv_lvl;
489 + cfg_request_identity(&identity);
491 rec.identity = &identity;
493 /* Now process cmd args */
494 diff --git a/acct.h b/acct.h
496 index 0000000..0640ae6
503 +#include "tac_plus.h"
505 +#include <sys/types.h> /* for u_* */
508 +extern void accounting TAC_ARGS((u_char *pak));
512 diff --git a/authen.c b/authen.c
513 index a12745e..7c873fe 100644
517 FITNESS FOR A PARTICULAR PURPOSE.
521 #include "tac_plus.h"
523 -static int choose();
524 -static void authenticate();
525 -static void do_start();
527 +#include <netinet/in.h> /* for ntohl() */
533 +#include "choose_authen.h"
534 +#include "do_author.h" /* for "struct identity" */
536 +#include "cfgfile.h"
539 +#include "tcpwrap.h"
543 +static void do_start TAC_ARGS((u_char *pak));
544 +static int choose TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
545 +static void authenticate TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
551 +#define TAC_PLUS_MAX_ITERATIONS 50
555 * Come here when we receive an authentication START packet
558 +void authen TAC_ARGS((u_char *pak));
563 @@ -39,9 +66,9 @@ u_char *pak;
564 start = (struct authen_start *) (pak + TAC_PLUS_HDR_SIZE);
566 if ((hdr->seq_no != 1) ||
567 - (ntohl(hdr->datalength) != TAC_AUTHEN_START_FIXED_FIELDS_SIZE +
568 + ((unsigned long) ntohl(hdr->datalength) != (unsigned long)(TAC_AUTHEN_START_FIXED_FIELDS_SIZE +
569 start->user_len + start->port_len + start->rem_addr_len +
570 - start->data_len)) {
571 + start->data_len))) {
572 send_authen_error("Invalid AUTHEN/START packet (check keys)");
575 @@ -65,6 +92,8 @@ u_char *pak;
576 * attempt to authenticate.
579 +static void do_start TAC_ARGS((u_char *pak));
584 @@ -109,6 +138,8 @@ u_char *pak;
586 identity.priv_lvl = start->priv_lvl;
588 + cfg_request_identity(&identity);
590 /* The authen_data structure */
592 bzero(&authen_data, sizeof(struct authen_data));
593 @@ -184,6 +215,8 @@ send_authen_error("You are not allowed to access here");
594 /* Choose an authentication function. Return 1 if we successfully
595 chose a function. 0 if we couldn't make a choice for some reason */
597 +static int choose TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
601 struct authen_data *datap;
602 @@ -293,6 +326,8 @@ struct authen_type *typep;
606 +static void authenticate TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
608 /* Perform authentication assuming we have successfully chosen an
609 authentication method */
611 @@ -303,7 +338,7 @@ struct authen_type *typep;
614 struct authen_cont *cont;
616 + int (*func) TAC_ARGS((struct authen_data *data));
618 if (debug & DEBUG_PACKET_FLAG)
619 report(LOG_DEBUG, "Calling authentication function");
620 @@ -469,4 +504,3 @@ struct authen_type *typep;
625 diff --git a/authen.h b/authen.h
627 index 0000000..d89d9cc
634 +#include "tac_plus.h"
636 +#include <sys/types.h> /* for u_* */
639 +extern void authen TAC_ARGS((u_char *pak));
642 +#endif /* AUTHEN_H */
643 diff --git a/author.c b/author.c
644 index a9f2277..7a05db5 100644
648 FITNESS FOR A PARTICULAR PURPOSE.
652 #include "tac_plus.h"
655 +#include <netinet/in.h> /* for ntohl() */
661 +#include "do_author.h"
663 +#include "cfgfile.h"
667 * Come here when we receive an authorization START packet
670 +void author TAC_ARGS((u_char *pak));
675 @@ -34,7 +49,8 @@ u_char *pak;
683 if (debug & DEBUG_AUTHOR_FLAG)
684 report(LOG_DEBUG, "Start authorization request");
685 @@ -58,7 +74,7 @@ u_char *pak;
689 - if (len != ntohl(hdr->datalength)) {
690 + if (len != (unsigned long) ntohl(hdr->datalength)) {
691 send_error_reply(TAC_PLUS_AUTHOR, NULL);
694 @@ -95,6 +111,8 @@ u_char *pak;
696 identity.priv_lvl = apak->priv_lvl;
698 + cfg_request_identity(&identity);
700 /* The author_data structure */
702 author_data.id = &identity; /* user id */
703 diff --git a/author.h b/author.h
705 index 0000000..0e3a2ce
712 +#include "tac_plus.h"
714 +#include <sys/types.h> /* for u_* */
717 +extern void author TAC_ARGS((u_char *pak));
720 +#endif /* AUTHOR_H */
721 diff --git a/autogen b/autogen
723 index 0000000..83862fd
731 +# Copyright (C) 1999, 2000, 2001
732 +# Partition Surprise Team <surprise-dev@lists.sourceforge.net>
738 +# Run this to generate all the initial makefiles, etc.
741 +if test "x$1" = "xBASH" ;then
743 +else if test "x$BASH" = "x" ;then
744 + for trypath in `echo "$PATH"|tr : ' '` /usr/local/bin;do
745 + if test -x "$trypath/bash";then
746 + "$trypath/bash" "$0" BASH "$@"
750 + echo "ERROR: Unable to find 'bash' interpreter needed for self-execution!"
754 +defaultCONFDEFS="" # --enable-debug --without-efence
760 +#upload="vellum.cz:WWW/sw/"
773 +source ./autogen-body
774 diff --git a/autogen-body b/autogen-body
776 index 0000000..6856444
783 +# Placed into the public domain by
784 +# Partition Surprise Team <surprise-dev@lists.sourceforge.net>
790 +# Executable code to be included from ./autogen script
792 +# Expected variables:
793 +# defaultCONFDEFS, project, want_tarZ, upload, docdir, subdirs, CLEAN_LOCAL
794 +# function PREP_LOCAL
805 + if $automake_gnu;then for i in $automake_reqd;do if [ '!' -s "$i" ];then rm -f "$i";fi;done;fi
810 + if $autogen_failed;then
811 + if $EXITmsg_do;then
812 + echo -e "\n$0 failed! Try the following command to debug it: set -x"
819 +if [ "$1" = help -o "$1" = -h -o "$1" = --help ];then cat <<EOHELP
820 +Beware!: "autogen" is a tool only for maintainers.
822 +Supported parameters:
823 + rpm: Build RPM packages locally (needs /usr/src/(redhat|packages)/ access)
824 + rpmtest: Build RPM like "rpm" but w/o gpg/pgp signing
825 + rpmup: Like rpm target but also uploads the result
826 + tar: Build tar file (its basename dir-based) with only vital files incl. CVS dirs
827 + clean: Standard cleanup method
828 + fullclean: Like clean but even the .cvsignore files are removed
829 + sym: Like clean but don't remove symbolic links, should be equal (check!)
830 + copy: Behave exactly like in default mode but copy all instead of symlinks
833 + autogen_failed=false
838 +if [ -f "$HOME/.$project.autogen" ];then
839 + . "$HOME/.$project.autogen"
841 +CONFDEFS="$defaultCONFDEFS $CONFDEFS"
848 + if declare -f "$func" >/dev/null;then
849 +local func_exit=false
852 + if $func_exit;then exit;fi
855 +funcdo ARGS_LOCAL "$@"
857 +if expr match "$1" "rpm" >/dev/null;then
858 + builds="/usr/src/redhat /usr/src/packages"
859 + for b in $builds X;do
860 + if test -d $b;then break;fi
863 + echo Build directory not reachable, searched: $builds
866 + rm -r -f /var/tmp/$project-*-root $b/BUILD/$project-*
867 + specsrc="$project.spec.m4.in"
868 + if [ '!' -f "$specsrc" ];then specsrc="$project.spec.in";fi
869 + CONFDEFS="`awk '/^(.*)\\$/{x=x$1" ";next}{print x$0;x=""}' <$specsrc \
870 + |sed -n 's/^.*\.\/configure \(.*\)$/\1/p'`" ./autogen copy
871 + make dist $project.spec
872 + cp $project-*.tar.gz $b/SOURCES
873 + if [ "$1" = "rpmtest" ];then SIGNIT=;else SIGNIT=--sign;fi
874 + rpm -ba $SIGNIT $project.spec
875 + if $want_tarZ;then make dist-tarZ;fi
876 + rm $b/SOURCES/$project-*.tar.gz
877 + mv $b/SRPMS/$project-*.src.rpm .
878 + mv $b/RPMS/i386/$project-*.i386.rpm .
880 + if [ "$1" = rpmup ];then
881 + echo "Uploading $[`cat $project-*|wc -c`] bytes..."
882 + if [ -n "$upload" ];then
883 + scp -v $project-* "$upload"
885 + echo "Upload not done."
888 + autogen_failed=false
894 + for i in _ $subdirs;do
897 + ./autogen $subdir_args
902 +subdir_args="${*:-dist}"
903 +if [ "$subdir_args" = "copy" ];then
904 + subdir_args="copy dist"
907 +# maintainer-clean hack is not safe, please list all files for 'rm'.
908 +# When the filename doesn't contain '/', it is applied to ALL directories.
909 +# Please note that files exactly in root dir MUST have ./ in the front
910 +# (to not to be considered as ALL-directories files).
916 + Makefile Makefile.in
923 + ./configure ./configure.scan
924 + ./config.guess ./config.status ./config.sub ./config.log ./config.cache
925 + ./config.h ./config.h.in
926 + ./confdefs.h ./conftest* ./autoh[0-9]* ./confcache
927 + ./stamp-h ./stamp-h.in
932 + ./libtool ./ltconfig ./ltmain.sh
934 + ./ABOUT-NLS ./COPYING
935 + ./$project-[0-9]* ./$project-devel-[0-9]*
936 + ./$project.spec ./$project.m4 ./$project.spec.m4
938 + 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
942 +if [ -n "$docdir" ];then
951 +if [ "$1" != sym ];then CLEANFILES="$CLEANFILES `find . -type l`";fi
952 +CLEANFILES="`echo "$CLEANFILES"|tr ' ' '\n'|sed 's,^\./\(.*/.*\)$,\1,'|sort|uniq|grep -v '^ *$'`"
955 +echo "$CLEANFILES"|while read -r fi;do
956 + if [ "$fi" != "${fi#*/}" ];then
957 + echo "$fi" >>"$t.discard"
958 + else echo "-o -name $fi" >>"$t.find"
960 +for dirpatt in `(find . -type d '!' \( -name CVS $(sed 's,[]*?[],\\&,g' <"$t.find") \)|sort|uniq;cat "$t.discard")|sort|uniq -u`;do
961 + for dir in $dirpatt;do if test -d $dir;then
963 + (echo "$CLEANFILES" #ALL-dir files
964 + echo "$CLEANFILES"|sed -n "s,^\\$(echo $dir|sed 's,^\./,,')/,,p" #THIS-dir files
965 + echo .cvsignore #MUST be last!
966 + )|grep -v / >.cvsignore
967 + if [ "$1" = "${1#tar}" ];then
969 + if [ "$1" = fullclean ];then cat .cvsignore
970 + else grep -v '^\.cvsignore' <.cvsignore
976 +rm -f "$t.find" "$t.discard"
977 +if [ "$1" = tarprep ];then
978 + autogen_failed=false
981 +if [ "$1" = tar ];then
982 + subdir_args=tarprep
984 + mydir="$(basename `pwd`)"
987 + $(for fi in `find "$mydir" -name .cvsignore`;do sed "s,^,--exclude=`dirname $fi`/," <$fi;done) \
989 + autogen_failed=false
992 +if [ "$1" != "${1#*clean}" ];then
994 + autogen_failed=false
998 +funcdo PREP_LOCAL "$@"
1001 +if [ "$1" = copy ];then COPY=--copy;shift
1002 +else unset COPY|cat # |cat construction is used to not fail in "set -e" state
1006 + touch po/POTFILES.in
1009 +if test -d macros;then
1010 + aclocal_opts="-I macros $aclocal_opts"
1012 +aclocal $aclocal_opts
1013 +if $want_gettext;then
1015 + rm -f aclocal.m4 # We delete created aclocal.m4 as it's just bug in gettextize. It shouldn't link that file here
1016 + aclocal $aclocal_opts # gettextize made some changes of files which need to be reflected
1018 +if $want_libtool;then
1023 +if $automake_gnu;then
1024 + automake_reqd="$automake_reqd ChangeLog README"
1025 + automake_opts="$automake_opts --gnu"
1026 + for i in $automake_reqd;do if [ '!' -f "$i" ];then touch "$i";fi;done
1028 +automake --add-missing $COPY $automake_opts
1033 +if [ "$1" != dist ];then
1034 + # shared/static switching cannot be based on maintainer-mode in configure
1035 + ./configure --enable-maintainer-mode --enable-shared --disable-static $CONFDEFS
1038 +autogen_failed=false
1039 diff --git a/cfgeval.c b/cfgeval.c
1040 new file mode 100644
1041 index 0000000..f0aed72
1047 + * If you belong to the group where do you belong only in the case you belong
1048 + * in that group, do you in fact belong to that group or don't?
1049 + * I've decided it is safer to decide that you DON'T belong to such group.
1051 + * expr_eval_notify_expr_remove():
1052 + * If someone was interested in what am I like but she is no longer
1053 + * interested in what am I like, because she already knows what is she like,
1054 + * then she should tell it me, as although I still may not know what am I
1055 + * like then in the case she was the last who wanted to know what am I like,
1056 + * I should tell everyone who I didn't know what they are like and I wanted
1057 + * to know what they are like that I no longer want to know what they are
1058 + * like, because it is no longer needed to know what am I like about myself.
1060 + * membership_eval_immediate():
1061 + * It is important to not only know, what do you want to know, but it is also
1062 + * important to know what do you now know but you still didn't utilize it.
1066 +#include "tac_plus.h"
1068 +#include <stdlib.h>
1070 +#include "cfgeval.h"
1071 +#include "cfgfile.h"
1074 +#include "report.h"
1081 +/* Whether to do sanity checks */
1082 +#define SCAN_PARANOIA 1
1084 +/* report even no-op scan up-to-date checks */
1085 +#define REPORT_CHECK_SCAN_VERBOSE 0
1088 +static void check_request_scan_membership TAC_ARGS((struct membership *membership, int flush));
1089 +static void check_eval_scan_membership TAC_ARGS((struct membership *membership, int flush));
1090 +static void check_eval_scan_entity TAC_ARGS((ENTITY *entity, int flush));
1091 +static void check_request_scan_expr TAC_ARGS((struct expr *expr, int flush));
1092 +static void check_eval_scan_expr TAC_ARGS((struct expr *expr, int flush));
1095 +static unsigned request_scan_seq = 0;
1096 +static unsigned value_scan_seq = 0;
1097 +static unsigned eval_scan_seq = 0;
1098 +int request_scan_user_known;
1099 +static struct tac_list eval_kicked_entity_list;
1100 +static struct tac_list eval_destroy_entity_list;
1101 +static struct tac_list eval_notified_expr_list;
1102 +static struct tac_list request_virtual_membership_list;
1105 +/* 'P[FA]_*' object printing section:
1108 +static const char *eval_result_to_string TAC_ARGS((int valid, enum eval_result er));
1111 +eval_result_to_string(valid, er)
1113 +enum eval_result er;
1116 + return ("!UPDATED");
1119 + case ER_TRUE: return ("ER_TRUE" );
1120 + case ER_FALSE: return ("ER_FALSE" );
1121 + case ER_UNKNOWN: return ("ER_UNKNOWN" );
1122 + default: return ("*** INVALID ***");
1127 +static const char *value_scan_func_result_to_string TAC_ARGS((enum value_scan_func_result vsfr));
1130 +value_scan_func_result_to_string(vsfr)
1131 +enum value_scan_func_result vsfr;
1134 + case VSFR_CONTINUE: return ("VSFR_CONTINUE");
1135 + case VSFR_FOUND: return ("VSFR_FOUND" );
1136 + case VSFR_STOP: return ("VSFR_STOP" );
1137 + default: return ("*** INVALID ***");
1142 +/* These macros are VERY big overhead but it's primary negative effect
1143 + * is the size of executable. I've considered it as not much interesting,
1144 + * CPU overhead is hit only when DEBUG_CFGEVAL_FLAG (also not interesting).
1147 +#define PF_VSFR "%s"
1148 +#define PA_VSFR(vsfr) (value_scan_func_result_to_string((vsfr)))
1150 +#define PF_RESULT "%s"
1151 +#define PA_RESULT(result) (eval_result_to_string(1 /* valid */, (result)))
1153 +#define PF_ERESULT_struct PF_RESULT
1154 +#define PA_ERESULT_struct(entity, field) \
1155 + (!(entity) ? "*NULL*(=ER_TRUE)" : \
1156 + (eval_result_to_string((entity)->request_scan.seq == request_scan_seq, (entity)->request_scan.field)))
1157 +#define PA_ERESULT_struct_NULL "*NULL*"
1159 +#define PF_ERESULT_EXPR PF_ERESULT_struct
1160 +#define PA_ERESULT_EXPR(expr) PA_ERESULT_struct((expr), result)
1161 +#define PF_ERESULT_ENTITY PF_ERESULT_struct
1162 +#define PA_ERESULT_ENTITY(entity) PA_ERESULT_struct((entity), belongs)
1163 +#define PF_ERESULT_MEMBERSHIP PF_ERESULT_struct
1164 +#define PA_ERESULT_MEMBERSHIP(membership) (!(membership) ? PA_ERESULT_struct_NULL : PA_ERESULT_EXPR((membership)->when))
1166 +#define PF_EXPR_ "expr@%d{%s " PF_MEMBERSHIP "}"
1167 +#define PA_EXPR_(expr) (!(expr) ? 0 : (expr)->line), \
1168 + (!(expr) ? "*NULL*" : "of"), \
1169 + PA_MEMBERSHIP((!(expr) ? NULL : (expr)->membership))
1171 +#define PF_MEMBERSHIP_ "membership{child=" PF_ENTITY ",parent=" PF_ENTITY "}"
1172 +#define PA_MEMBERSHIP_(membership) PA_ENTITY((!(membership) ? NULL : MEMBERSHIP_TO_CHILD_ENTITY( (membership)))), \
1173 + PA_ENTITY((!(membership) ? NULL : MEMBERSHIP_TO_PARENT_ENTITY((membership))))
1175 +#define PF_ENTITY_ "{%s@%d \"%s\"}"
1176 +#define PA_ENTITY_(entity) (!(entity) ? "*NULL* entity" : entity_type_to_string((entity)->type)), \
1177 + (!(entity) ? 0 : (entity)->line), \
1178 + (!(entity) ? "*NULL*" : (entity)->name)
1180 +#define PF_EXPR PF_EXPR_ "=" PF_ERESULT_EXPR
1181 +#define PA_EXPR(expr) PA_EXPR_(expr), PA_ERESULT_EXPR(expr)
1182 +#define PF_MEMBERSHIP PF_MEMBERSHIP_ "=" PF_ERESULT_MEMBERSHIP
1183 +#define PA_MEMBERSHIP(membership) PA_MEMBERSHIP_(membership), PA_ERESULT_MEMBERSHIP(membership)
1184 +#define PF_ENTITY PF_ENTITY_ "=" PF_ERESULT_ENTITY
1185 +#define PA_ENTITY(entity) PA_ENTITY_(entity), PA_ERESULT_ENTITY(entity)
1188 +/* '{unlink,free}_*()' section:
1191 +void unlink_expr TAC_ARGS((struct expr *expr));
1193 +/* never depend on "->parent" as it may not yet been filled! */
1199 + return; /* prevent possible DEBUG_CLEAN_FLAG report */
1201 + if (debug & DEBUG_CLEAN_FLAG) {
1202 + if (expr->membership)
1203 + report(LOG_DEBUG, "unlink_expr: (of membership): " PF_EXPR,
1206 + report(LOG_DEBUG, "unlink_expr: (standalone)");
1211 + /* We need to at least unlink "eval_scan->u.entity.notify_expr_node": */
1212 + check_request_scan_expr(expr, 1); /* invalidate */
1213 + check_eval_scan_expr(expr, 1); /* invalidate */
1215 + switch (expr->type) {
1218 + unlink_expr(expr->u.not.child);
1223 + unlink_expr(expr->u.and_or.child_first);
1232 + report(LOG_ERR, "Illegal node type %d for unlink_expr", expr->type);
1236 + expr = expr->next;
1240 +void free_expr TAC_ARGS((struct expr *expr));
1242 +/* given 'expr' memory WILL be freed! */
1243 +/* never depend on "->parent" as it may not yet been filled! */
1248 +struct expr *expr_next;
1251 + return; /* prevent possible DEBUG_CLEAN_FLAG report */
1253 + if (debug & DEBUG_CLEAN_FLAG)
1254 + report(LOG_DEBUG, "free_expr: (may be unlinked)");
1257 + expr_next = expr->next;
1258 + switch (expr->type) {
1261 + free_expr(expr->u.not.child);
1266 + free_expr(expr->u.and_or.child_first);
1272 + if (expr->u.entity.name)
1273 + free((/* de-const */ char *)expr->u.entity.name);
1274 + /* "expr->u.entity.entity" will be freed from elsewhere */
1278 + report(LOG_ERR, "Illegal node type %d for free_expr", expr->type);
1287 +static void unlink_membership TAC_ARGS((struct membership *membership));
1290 +unlink_membership(membership)
1291 +struct membership *membership;
1293 + ENTITY *parent_entity;
1295 + if (debug & DEBUG_CFGEVAL_FLAG)
1296 + report(LOG_DEBUG, "unlink_membership: " PF_MEMBERSHIP,
1297 + PA_MEMBERSHIP(membership));
1299 + parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1301 + /* 'unlink_expr()' may want a lot of existing (linked) resources */
1302 + unlink_expr(membership->when);
1304 + check_request_scan_membership(membership, 1); /* invalidate */
1305 + check_eval_scan_membership(membership, 1); /* invalidate */
1307 +#ifdef SCAN_PARANOIA
1308 + if (!parent_entity->to_child_membership_num) {
1309 + report(LOG_ERR, "INTERNAL: to_child_membership_num-- == 0 in unlink_membership");
1310 + parent_entity->to_child_membership_num++;
1313 + parent_entity->to_child_membership_num--;
1315 + tac_list_node_remove(&membership->parent_node);
1316 + tac_list_node_remove(&membership-> child_node);
1319 +/* given 'membership' memory WILL be freed! */
1321 +static void free_membership TAC_ARGS((struct membership *membership));
1324 +free_membership(membership)
1325 +struct membership *membership;
1327 + if (debug & DEBUG_CLEAN_FLAG)
1328 + report(LOG_DEBUG, "free_membership: (may be unlinked)");
1330 + free_expr(membership->when);
1334 +/* we are not allowed to free memory here, we are only 'scan_' additional 'free' */
1336 +void scan_free_entity TAC_ARGS((ENTITY *entity));
1339 +scan_free_entity(entity)
1342 + struct tac_list_node *parent_membership_node, *next_parent_membership_node;
1343 + struct membership *parent_membership;
1344 + struct tac_list_node *child_membership_node, *next_child_membership_node;
1345 + struct membership *child_membership;
1347 + if (debug & DEBUG_CLEAN_FLAG)
1348 + report(LOG_DEBUG, "scan_free_entity: " PF_ENTITY,
1349 + PA_ENTITY(entity));
1351 + /* Be careful to keep '->next' ptr before we destroy the structure! */
1354 + parent_membership_node = tac_list_first_node(&entity->to_child_membership_list);
1355 + parent_membership_node;
1356 + parent_membership_node = next_parent_membership_node
1358 + parent_membership = PARENT_NODE_TO_MEMBERSHIP(parent_membership_node);
1359 + next_parent_membership_node = tac_list_node_next(parent_membership_node);
1360 + unlink_membership(parent_membership);
1361 + free_membership(parent_membership);
1364 + child_membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1365 + child_membership_node;
1366 + child_membership_node = next_child_membership_node
1368 + child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
1369 + next_child_membership_node = tac_list_node_next(child_membership_node);
1370 + unlink_membership(child_membership);
1371 + free_membership(child_membership);
1375 +struct expr *new_expr TAC_ARGS((int type));
1381 + struct expr *expr;
1383 + expr = (struct expr *) tac_malloc(sizeof(struct expr));
1384 + expr->next = NULL;
1385 + expr->type = type;
1386 + switch (expr->type) {
1389 + expr->u.not.child = NULL;
1394 + expr->u.and_or.child_first = NULL;
1400 + expr->u.entity.entity = NULL;
1404 + report(LOG_ERR, "Illegal node type %d for new_expr", expr->type);
1405 + return (expr); /* it would be probably lethal to return NULL */
1410 +static int expr_sink_internal TAC_ARGS((struct expr *expr, struct membership *membership, struct expr *parent));
1413 +expr_sink_internal(expr, membership, parent)
1415 +struct membership *membership;
1416 +struct expr *parent;
1418 + for (;expr; expr=expr->next) {
1419 + expr->membership = membership;
1420 + expr->parent = parent;
1421 + expr->request_scan.seq = request_scan_seq-1;
1422 + expr-> eval_scan.seq = eval_scan_seq-1;
1423 + switch (expr->type) {
1426 + if (expr_sink_internal(expr->u.not.child, membership, expr /* parent */))
1432 + if (expr_sink_internal(expr->u.and_or.child_first, membership, expr /* parent */))
1439 + tac_list_node_init(&expr->eval_scan.u.entity.notify_expr_node);
1440 + expr->u.entity.entity = entity_lookup(expr->type, expr->u.entity.name);
1441 + if (!expr->u.entity.entity && expr->type == S_host) {
1442 + expr->u.entity.entity = new_entity(expr->type, (char *)expr->u.entity.name, expr->line);
1443 + if (!expr->u.entity.entity)
1445 + expr->u.entity.name = NULL;
1447 + if (!expr->u.entity.entity) {
1448 + report(LOG_ERR, "referenced entity %s %s not found on line %d",
1449 + entity_type_to_string(expr->type), expr->u.entity.name, expr->line);
1452 + /* already NULLed for not-yet-existing S_host */
1453 + free((char *) expr->u.entity.name);
1454 + expr->u.entity.name = NULL;
1458 + report(LOG_ERR, "Illegal node type %d for expr_sink", expr->type);
1465 +static int expr_sink TAC_ARGS((struct expr *expr, struct membership *membership));
1468 +expr_sink(expr, membership)
1470 +struct membership *membership;
1472 + return (expr_sink_internal(expr, membership, NULL /* parent */));
1475 +static struct expr *expr_sink_register_head = NULL;
1477 +void expr_sink_register TAC_ARGS((struct expr *expr));
1480 +expr_sink_register(expr)
1486 + expr->parent = expr_sink_register_head;
1487 + expr_sink_register_head = expr;
1490 +int expr_sink_commit TAC_ARGS((void));
1495 + struct expr *expr;
1497 + while ((expr = expr_sink_register_head)) {
1498 + expr_sink_register_head = expr->parent;
1499 + /* 'expr->parent' not defined for 'expr_sink()' */
1501 + if (expr_sink(expr, NULL /* membership */))
1502 + return (1); /* failure */
1504 + return (0); /* success */
1507 +struct expr *dupl_expr TAC_ARGS((const struct expr *in));
1511 +const struct expr *in;
1513 + struct expr *expr_root = NULL;
1514 + struct expr **succ_exprp = &expr_root;
1515 + struct expr *expr;
1517 + for (;in; in=in->next) {
1518 + expr = (struct expr *) tac_malloc(sizeof(struct expr));
1519 + expr->line = in->line;
1520 + expr->next = NULL;
1521 + expr->type = in->type;
1522 + switch (in->type) {
1525 + if (in->u.not.child && in->u.not.child->type==S_not) {
1527 + expr = dupl_expr(in->u.not.child->u.not.child);
1529 + expr->u.not.child = dupl_expr(in->u.not.child);
1534 + if (!in->u.and_or.child_first) {
1537 + } else if (!in->u.and_or.child_first->next) {
1539 + expr = dupl_expr(in->u.and_or.child_first);
1541 + expr->u.and_or.child_first = dupl_expr(in->u.and_or.child_first);
1547 + if (in->u.entity.name)
1548 + expr->u.entity.name = tac_strdup(in->u.entity.name);
1550 + expr->u.entity.name = NULL;
1551 + expr->u.entity.entity = in->u.entity.entity;
1555 + report(LOG_ERR, "Illegal node type %d for dupl_expr", in->type);
1556 + free_expr(expr_root);
1560 + *succ_exprp = expr;
1561 + succ_exprp = &expr->next;
1563 + return (expr_root);
1567 +/* 'check_*_scan_*()' section:
1570 +static void check_request_scan_expr TAC_ARGS((struct expr *expr, int flush));
1573 +check_request_scan_expr(expr, flush)
1577 +#if REPORT_CHECK_SCAN_VERBOSE
1578 + if (debug & DEBUG_CFGEVAL_FLAG)
1579 + report(LOG_DEBUG, "check_request_scan_expr: " PF_EXPR " (" PF_ERESULT_EXPR ")",
1580 + PA_EXPR(expr), PA_ERESULT_EXPR(expr));
1583 + if (!flush && expr->request_scan.seq == request_scan_seq)
1584 + return; /* up to date */
1586 + expr->request_scan.result = ER_UNKNOWN;
1587 + expr->request_scan.loop_reported = 0;
1588 + expr->request_scan.seq = request_scan_seq;
1590 + if (debug & DEBUG_CFGEVAL_FLAG)
1591 + report(LOG_DEBUG, "check_request_scan_expr: done: " PF_EXPR,
1595 +static void check_eval_scan_expr TAC_ARGS((struct expr *expr, int flush));
1598 +check_eval_scan_expr(expr, flush)
1602 +#if REPORT_CHECK_SCAN_VERBOSE
1603 + if (debug & DEBUG_CFGEVAL_FLAG)
1604 + report(LOG_DEBUG, "check_eval_scan_expr: " PF_EXPR,
1608 + if (!flush && expr->eval_scan.seq == eval_scan_seq)
1609 + return; /* up to date */
1610 + check_request_scan_expr(expr, 0);
1612 + switch (expr->type) {
1617 +#ifdef SCAN_PARANOIA
1618 + if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node) == &eval_notified_expr_list) {
1619 + report(LOG_ERR, "INTERNAL: expr still connected to eval_notified_expr_list in check_eval_scan_expr");
1620 + } else if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node)) {
1621 + ENTITY *notifying_entity = EXPR_ENTITY_TO_NOTIFYING_ENTITY(expr);
1623 + if (notifying_entity != expr->u.entity.entity)
1624 + report(LOG_ERR, "INTERNAL: expr->notify_expr_node->list != expr->entity");
1625 + if (notifying_entity->eval_scan.seq != expr->eval_scan.seq)
1626 + report(LOG_ERR, "INTERNAL: entity seq != expr node seq");
1627 + tac_list_node_remove(&expr->eval_scan.u.entity.notify_expr_node);
1629 +#else /* SCAN_PARANOIA */
1630 + tac_list_node_init(&expr->eval_scan.u.entity.notify_expr_node);
1631 +#endif /* SCAN_PARANOIA */
1635 + expr->eval_scan.seq = eval_scan_seq; /* used above, keep as LAST! */
1637 + if (debug & DEBUG_CFGEVAL_FLAG)
1638 + report(LOG_DEBUG, "check_eval_scan_expr: done: " PF_EXPR,
1642 +static void check_request_scan_membership TAC_ARGS((struct membership *membership, int flush));
1645 +check_request_scan_membership(membership, flush)
1646 +struct membership *membership;
1649 +#if REPORT_CHECK_SCAN_VERBOSE
1650 + if (debug & DEBUG_CFGEVAL_FLAG)
1651 + report(LOG_DEBUG, "check_request_scan_membership: " PF_MEMBERSHIP " (" PF_ERESULT_MEMBERSHIP ")",
1652 + PA_MEMBERSHIP(membership), PA_ERESULT_MEMBERSHIP(membership));
1655 + if (!flush && membership->request_scan.seq == request_scan_seq)
1656 + return; /* up to date */
1658 +#ifdef SCAN_PARANOIA
1660 + struct tac_list *virtual_list = tac_list_node_get_list(&membership->request_scan.virtual_membership_node);
1662 + if (virtual_list && virtual_list != &request_virtual_membership_list)
1663 + report(LOG_ERR, "Illegal list in membership->virtual_membership_node.list");
1665 + tac_list_node_remove(&membership->request_scan.virtual_membership_node);
1667 +#else /* SCAN_PARANOIA */
1668 + tac_list_node_init(&membership->request_scan.virtual_membership_node);
1669 +#endif /* SCAN_PARANOIA */
1671 + membership->request_scan.seq = request_scan_seq; /* used above, keep as LAST! */
1673 + if (debug & DEBUG_CFGEVAL_FLAG)
1674 + report(LOG_DEBUG, "check_request_scan_membership: done: " PF_MEMBERSHIP,
1675 + PA_MEMBERSHIP(membership));
1678 +/* we are cross-checking (membership<->parent entity)! */
1680 +static void check_eval_scan_membership TAC_ARGS((struct membership *membership, int flush));
1683 +check_eval_scan_membership(membership, flush)
1684 +struct membership *membership;
1687 +#if REPORT_CHECK_SCAN_VERBOSE
1688 + if (debug & DEBUG_CFGEVAL_FLAG)
1689 + report(LOG_DEBUG, "check_eval_scan_membership: " PF_MEMBERSHIP,
1690 + PA_MEMBERSHIP(membership));
1693 + if (!flush && membership->eval_scan.seq == eval_scan_seq)
1694 + return; /* up to date */
1695 + check_request_scan_membership(membership, 0);
1697 + membership->eval_scan.unsolved = 1;
1698 + membership->eval_scan.seq = eval_scan_seq;
1700 + if (debug & DEBUG_CFGEVAL_FLAG)
1701 + report(LOG_DEBUG, "check_eval_scan_membership: done: " PF_MEMBERSHIP,
1702 + PA_MEMBERSHIP(membership));
1705 +static void check_request_scan_entity TAC_ARGS((ENTITY *entity, int flush));
1708 +check_request_scan_entity(entity, flush)
1712 +#if REPORT_CHECK_SCAN_VERBOSE
1713 + if (debug & DEBUG_CFGEVAL_FLAG)
1714 + report(LOG_DEBUG, "check_request_scan_entity: " PF_ENTITY " (" PF_ERESULT_ENTITY ")",
1715 + PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
1718 + if (!flush && entity->request_scan.seq == request_scan_seq)
1721 + entity->request_scan.belongs = ER_UNKNOWN;
1722 + entity->request_scan.seq = request_scan_seq;
1724 + if (debug & DEBUG_CFGEVAL_FLAG)
1725 + report(LOG_DEBUG, "check_request_scan_entity: done: " PF_ENTITY,
1726 + PA_ENTITY(entity));
1729 +static void check_value_scan_entity TAC_ARGS((ENTITY *entity, int flush));
1732 +check_value_scan_entity(entity, flush)
1736 +#if REPORT_CHECK_SCAN_VERBOSE
1737 + if (debug & DEBUG_CFGEVAL_FLAG)
1738 + report(LOG_DEBUG, "check_value_scan_entity: " PF_ENTITY,
1739 + PA_ENTITY(entity));
1742 + if (!flush && entity->value_scan.seq == value_scan_seq)
1744 + check_request_scan_entity(entity, 0);
1746 + entity->value_scan.seen = 0;
1747 + entity->value_scan.from = NULL;
1748 + entity->value_scan.seq = value_scan_seq;
1750 + if (debug & DEBUG_CFGEVAL_FLAG)
1751 + report(LOG_DEBUG, "check_value_scan_entity: done: " PF_ENTITY,
1752 + PA_ENTITY(entity));
1755 +static void check_eval_scan_entity TAC_ARGS((ENTITY *entity, int flush));
1758 +check_eval_scan_entity(entity, flush)
1762 + struct tac_list_node *child_membership_parent_node;
1764 +#if REPORT_CHECK_SCAN_VERBOSE
1765 + if (debug & DEBUG_CFGEVAL_FLAG)
1766 + report(LOG_DEBUG, "check_eval_scan_entity: " PF_ENTITY,
1767 + PA_ENTITY(entity));
1770 + if (!flush && entity->eval_scan.seq == eval_scan_seq)
1771 + return; /* up to date */
1772 + check_value_scan_entity(entity, 0);
1774 + entity->eval_scan.unsolved_to_child_membership_num = entity->to_child_membership_num;
1776 + if ((child_membership_parent_node = tac_list_first_node(&entity->to_child_membership_list))) {
1777 + struct membership *child_membership = PARENT_NODE_TO_MEMBERSHIP(child_membership_parent_node);
1779 + entity->eval_scan.unsolved_to_child_membership_first = child_membership;
1781 + entity->eval_scan.unsolved_to_child_membership_first = NULL;
1783 +#ifdef SCAN_PARANOIA
1785 + struct tac_list_node *notify_expr_node;
1787 + while ((notify_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
1788 + struct expr *notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(notify_expr_node);
1790 + if (notify_expr->u.entity.entity != entity)
1791 + report(LOG_ERR, "INTERNAL: notify_expr->entity != entity");
1792 + if (notify_expr->eval_scan.seq != entity->eval_scan.seq)
1793 + report(LOG_ERR, "INTERNAL: notify_expr seq != entity seq");
1794 + tac_list_node_remove(notify_expr_node);
1797 + if (tac_list_node_get_list(&entity->eval_scan.pending_entity_node))
1798 + tac_list_node_remove(&entity->eval_scan.pending_entity_node);
1800 +#else /* SCAN_PARANOIA */
1801 + tac_list_init(&entity->eval_scan.notify_expr_list);
1802 + tac_list_node_init(&entity->eval_scan.pending_entity_node);
1803 +#endif /* SCAN_PARANOIA */
1805 + entity->eval_scan.seq = eval_scan_seq; /* used above, keep as LAST! */
1807 + if (debug & DEBUG_CFGEVAL_FLAG)
1808 + report(LOG_DEBUG, "check_eval_scan_entity: done: " PF_ENTITY,
1809 + PA_ENTITY(entity));
1813 +/* invalidation managing section (for '*_scan_begin()'):
1816 +/* this will happen once upon 'unsigned' overflow, ehm */
1818 +#define INVALIDATE_SEQ_PTR(object,ptr) \
1819 + (G_STRUCT_MEMBER(unsigned, ptr, invalidate_scan_##object##_table[what]) = (unsigned) -1)
1820 +#define INVALIDATE_SEQ(object) \
1821 + (INVALIDATE_SEQ_PTR(object,object))
1823 +static const long invalidate_scan_expr_table[IS_MAX]={
1824 + G_STRUCT_OFFSET(struct expr, request_scan.seq),
1826 + G_STRUCT_OFFSET(struct expr, eval_scan.seq)};
1828 +static void invalidate_scan_expr TAC_ARGS((struct expr *expr,enum invalidate_scan what));
1831 +invalidate_scan_expr(expr_single, what)
1832 +struct expr *expr_single;
1833 +enum invalidate_scan what;
1835 + struct expr *expr_parent, *expr_child;
1837 + if (!expr_single) {
1838 + report(LOG_ERR, "INTERNAL: NULL input expressions not support by invalidate_scan_expr");
1841 + if (expr_single->parent) {
1842 + report(LOG_ERR, "INTERNAL: non-root expressions not supported by invalidate_scan_expr");
1846 + /* TOP->DOWN scanner: */
1849 + INVALIDATE_SEQ_PTR(expr,expr_single);
1850 + expr_parent = expr_single;
1852 + switch (expr_parent->type) {
1855 + expr_child = expr_parent->u.not.child;
1860 + expr_child = expr_parent->u.and_or.child_first;
1866 + expr_child = NULL; /* no child exists */
1870 + report(LOG_ERR, "Illegal child node type %d for invalidate_scan_expr", expr_parent->type);
1873 + } while ((expr_single = expr_child));
1874 + /* expr_child==NULL, we have only expr_parent: */
1876 + expr_child = expr_parent;
1878 + /* we have only expr_child: */
1879 + /* BOTTOM->UP scanner */
1881 + if ((expr_single = expr_child->next))
1883 + expr_parent = expr_child->parent;
1884 + } while ((expr_child = expr_parent));
1887 +static const long invalidate_scan_membership_table[IS_MAX]={
1888 + G_STRUCT_OFFSET(struct membership, request_scan.seq),
1890 + G_STRUCT_OFFSET(struct membership, eval_scan.seq)};
1892 +static void invalidate_scan_membership TAC_ARGS((struct membership *membership,enum invalidate_scan what));
1895 +invalidate_scan_membership(membership, what)
1896 +struct membership *membership;
1897 +enum invalidate_scan what;
1899 + INVALIDATE_SEQ(membership);
1901 + if (membership->when)
1902 + invalidate_scan_expr(membership->when, what);
1905 +static const long invalidate_scan_entity_table[IS_MAX]={
1906 + G_STRUCT_OFFSET(ENTITY, request_scan.seq),
1907 + G_STRUCT_OFFSET(ENTITY, value_scan.seq),
1908 + G_STRUCT_OFFSET(ENTITY, eval_scan.seq)};
1910 +static void invalidate_scan_entity TAC_ARGS((ENTITY *entity,enum invalidate_scan what));
1913 +invalidate_scan_entity(entity, what)
1915 +enum invalidate_scan what;
1917 + struct tac_list_node *child_membership_node;
1918 + struct membership *child_membership;
1920 + INVALIDATE_SEQ(entity);
1922 + if (what==IS_VALUE) /* optimalization */
1926 + child_membership_node = tac_list_first_node(&entity->to_child_membership_list);
1927 + child_membership_node;
1928 + child_membership_node = tac_list_node_next(&child_membership->parent_node)
1930 + child_membership = PARENT_NODE_TO_MEMBERSHIP(child_membership_node);
1931 + invalidate_scan_membership(child_membership, what);
1935 +void scan_invalidate_entities_hashtable TAC_ARGS((void **hashtable, enum invalidate_scan what));
1938 +scan_invalidate_entities_hashtable(hashtable, what)
1940 +enum invalidate_scan what;
1945 + for (i = 0; i < HASH_TAB_SIZE; i++)
1946 + for (entity = (ENTITY *) hashtable[i]; entity; entity = entity->hash)
1947 + invalidate_scan_entity(entity, what);
1950 +/* '*_scan_begin()' section:
1953 +void request_scan_begin TAC_ARGS((void));
1956 +request_scan_begin()
1958 +#ifdef SCAN_PARANOIA
1959 + static int inited = 0;
1960 +#endif /* SCAN_PARANOIA */
1962 + if (debug & DEBUG_CFGEVAL_FLAG)
1963 + report(LOG_DEBUG, "request_scan_begin:");
1965 + request_scan_user_known = 0;
1967 + if (!++request_scan_seq)
1968 + scan_invalidate_entities(IS_REQUEST);
1970 +#ifdef SCAN_PARANOIA
1972 +#endif /* SCAN_PARANOIA */
1973 + tac_list_init(&request_virtual_membership_list);
1974 +#ifdef SCAN_PARANOIA
1977 + struct tac_list_node *virtual_membership_node;
1979 + while ((virtual_membership_node = tac_list_first_node(&request_virtual_membership_list))) {
1980 + struct membership *virtual_membership = VIRTUAL_MEMBERSHIP_NODE_TO_MEMBERSHIP(virtual_membership_node);
1982 + if (virtual_membership->request_scan.seq == request_scan_seq)
1983 + report(LOG_ERR, "INTERNAL: request_virtual_membership_list membership seq == ++request_scan_seq in request_scan_begin");
1984 + tac_list_node_remove(virtual_membership_node);
1985 + unlink_membership(virtual_membership);
1986 + free_membership(virtual_membership);
1989 +#endif /* SCAN_PARANOIA */
1992 +static void value_scan_begin TAC_ARGS((ENTITY *entity));
1995 +value_scan_begin(entity)
1998 + if (debug & DEBUG_CFGEVAL_FLAG)
1999 + report(LOG_DEBUG, "value_scan_begin:");
2001 + if (!++value_scan_seq)
2002 + scan_invalidate_entities(IS_VALUE);
2004 + check_value_scan_entity(entity, 0); /* sure as seq invalidated */
2005 + /* assumed (entity->value_scan.from == NULL) */
2008 +#ifdef SCAN_PARANOIA
2010 +static void eval_scan_begin_pending_entity_node TAC_ARGS((struct tac_list_node *pending_entity_node));
2013 +eval_scan_begin_pending_entity_node(pending_entity_node)
2014 +struct tac_list_node *pending_entity_node;
2016 + ENTITY *pending_entity = PENDING_ENTITY_NODE_TO_ENTITY(pending_entity_node);
2018 + if (pending_entity->eval_scan.seq == eval_scan_seq)
2019 + report(LOG_ERR, "INTERNAL: eval_{pending}_entity_list entity seq == ++eval_scan_seq in eval_scan_begin");
2021 + tac_list_node_remove(pending_entity_node);
2024 +#endif /* SCAN_PARANOIA */
2026 +static void eval_scan_begin TAC_ARGS((void));
2031 +#ifdef SCAN_PARANOIA
2032 + static int inited = 0;
2033 +#endif /* SCAN_PARANOIA */
2035 + if (debug & DEBUG_CFGEVAL_FLAG)
2036 + report(LOG_DEBUG, "eval_scan_begin:");
2038 + if (!++eval_scan_seq)
2039 + scan_invalidate_entities(IS_EVAL);
2041 +#ifdef SCAN_PARANOIA
2043 +#endif /* SCAN_PARANOIA */
2044 + tac_list_init(&eval_kicked_entity_list);
2045 + tac_list_init(&eval_destroy_entity_list);
2046 + tac_list_init(&eval_notified_expr_list);
2047 +#ifdef SCAN_PARANOIA
2050 + struct tac_list_node *pending_entity_node;
2051 + struct tac_list_node *notify_expr_node;
2053 + while ((pending_entity_node = tac_list_first_node(&eval_kicked_entity_list)))
2054 + eval_scan_begin_pending_entity_node(pending_entity_node);
2055 + while ((pending_entity_node = tac_list_first_node(&eval_destroy_entity_list)))
2056 + eval_scan_begin_pending_entity_node(pending_entity_node);
2058 + while ((notify_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
2059 + struct expr *notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(notify_expr_node);
2061 + if (notify_expr->eval_scan.seq == eval_scan_seq)
2062 + report(LOG_ERR, "INTERNAL: eval_notified_expr_list expr seq == ++eval_scan_seq in eval_scan_begin");
2064 + tac_list_node_remove(notify_expr_node);
2067 +#endif /* SCAN_PARANOIA */
2070 +/* 'priority=0' => addtail - used for WANTED entities
2071 + * 'priority=1' => addhead - used for SOLVED entities
2072 + * It may be better to do insert it AFTER all currently solved
2073 + * entities but may be not but who cares...
2076 +static void register_kicked_entity TAC_ARGS((ENTITY *entity, int priority));
2078 +static void register_kicked_entity(entity, priority)
2082 + struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
2084 + check_eval_scan_entity(entity, 0);
2086 + if (tac_list_node_get_list(pending_entity_node) == &eval_destroy_entity_list) {
2087 + tac_list_node_remove (pending_entity_node);
2088 + if (debug & DEBUG_CFGEVAL_FLAG)
2089 + report(LOG_DEBUG, "register_kicked_entity: REMOVED " PF_ENTITY " from eval_DESTROY_entity_list",
2090 + PA_ENTITY(entity));
2092 + if (tac_list_node_get_list(pending_entity_node) == NULL) {
2094 + tac_list_addhead(&eval_kicked_entity_list, pending_entity_node);
2096 + tac_list_addtail(&eval_kicked_entity_list, pending_entity_node);
2097 + if (debug & DEBUG_CFGEVAL_FLAG)
2098 + report(LOG_DEBUG, "register_kicked_entity: REGISTERED " PF_ENTITY " to eval_KICKED_entity_list (priority=%s)",
2099 + PA_ENTITY(entity), (priority ? "YES" : "NO"));
2101 +#ifdef SCAN_PARANOIA
2102 + if ((tac_list_node_get_list(pending_entity_node) != &eval_kicked_entity_list)) {
2103 + report(LOG_ERR, "Illegal list in entity->pending_entity_node.list");
2109 +/* check_eval_scan_*() is assumed both for "expr" and for "entity" ! */
2111 +static void expr_eval_notify_expr TAC_ARGS((struct expr *expr));
2114 +expr_eval_notify_expr(expr)
2117 + ENTITY *entity = expr->u.entity.entity;
2119 + if (debug & DEBUG_CFGEVAL_FLAG)
2120 + report(LOG_DEBUG, "expr_eval_notify_expr: REGISTERED notify " PF_EXPR " when " PF_ENTITY " is known",
2121 + PA_EXPR(expr), PA_ENTITY(entity));
2123 + if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node)) {
2124 +#ifdef SCAN_PARANOIA
2125 + if (&entity->eval_scan.notify_expr_list
2126 + != tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
2127 + report(LOG_ERR, "Another " PF_ENTITY " already registered in notify node of " PF_EXPR,
2128 + PA_ENTITY(EXPR_ENTITY_TO_NOTIFYING_ENTITY(expr)), PA_EXPR(expr));
2133 + tac_list_addtail(&entity->eval_scan.notify_expr_list,
2134 + &expr->eval_scan.u.entity.notify_expr_node);
2136 + register_kicked_entity(entity, 0 /* priority */);
2139 +/* check_eval_scan_*() is assumed for "expr" ! */
2141 +static void expr_eval_notify_expr_remove_internal TAC_ARGS((struct expr *expr));
2144 +expr_eval_notify_expr_remove_internal(expr)
2147 + if (debug & DEBUG_CFGEVAL_FLAG)
2148 + report(LOG_DEBUG, "expr_eval_notify_expr_remove_internal: no longer interested in " PF_EXPR,
2153 + if (expr->eval_scan.seq != eval_scan_seq)
2155 + if (expr->request_scan.result != ER_UNKNOWN)
2158 + switch (expr->type) {
2161 + expr_eval_notify_expr_remove_internal(expr->u.not.child);
2166 + struct expr *child;
2168 + for (child=expr->u.and_or.child_first; child; child=child->next)
2169 + expr_eval_notify_expr_remove_internal(child);
2175 + ENTITY *entity = expr->u.entity.entity;
2176 + struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
2178 + if (!tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
2181 + tac_list_node_remove(&expr->eval_scan.u.entity.notify_expr_node);
2182 + if (tac_list_first_node(&entity->eval_scan.notify_expr_list))
2184 + /* no one is further interested in "entity" */
2186 + if ((tac_list_node_get_list(pending_entity_node) == &eval_kicked_entity_list)) {
2187 + tac_list_node_remove (pending_entity_node);
2188 + if (debug & DEBUG_CFGEVAL_FLAG)
2189 + report(LOG_DEBUG, "expr_eval_notify_expr: REMOVED " PF_ENTITY " from eval_KICKED_entity_list",
2190 + PA_ENTITY(entity));
2192 + if (tac_list_node_get_list(pending_entity_node) == NULL) {
2193 + tac_list_addtail(&eval_destroy_entity_list, pending_entity_node);
2194 + if (debug & DEBUG_CFGEVAL_FLAG)
2195 + report(LOG_DEBUG, "expr_eval_notify_expr: REGISTERED " PF_ENTITY " to eval_DESTROY_entity_list",
2196 + PA_ENTITY(entity));
2198 +#ifdef SCAN_PARANOIA
2199 + if (tac_list_node_get_list(pending_entity_node) != &eval_destroy_entity_list) {
2200 + report(LOG_ERR, "Illegal list in entity->pending_entity_node.list");
2208 + report(LOG_ERR, "Illegal node type %d for expr_eval_notify_expr_remove", expr->type);
2213 +static void expr_eval_notify_expr_flush_destroy_entity_list TAC_ARGS((void));
2215 +static void expr_eval_notify_expr_flush_destroy_entity_list()
2217 +struct tac_list_node *destroy_entity_node;
2219 + while ((destroy_entity_node = tac_list_first_node(&eval_destroy_entity_list))) {
2220 + ENTITY *destroy_entity = PENDING_ENTITY_NODE_TO_ENTITY(destroy_entity_node);
2221 + struct tac_list_node *destroy_notify_expr_node;
2223 + if (debug & DEBUG_CFGEVAL_FLAG)
2224 + report(LOG_DEBUG, "expr_eval_notify_expr_flush_destroy_entity_list: PROCESSING " PF_ENTITY " from eval_DESTROY_entity_list",
2225 + PA_ENTITY(destroy_entity));
2227 + while ((destroy_notify_expr_node = tac_list_first_node(&destroy_entity->eval_scan.notify_expr_list))) {
2228 + struct expr *destroy_notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(destroy_notify_expr_node);
2230 + expr_eval_notify_expr_remove_internal(destroy_notify_expr);
2235 +static void expr_eval_notify_expr_remove TAC_ARGS((struct expr *expr));
2238 +expr_eval_notify_expr_remove(expr)
2241 + if (debug & DEBUG_CFGEVAL_FLAG)
2242 + report(LOG_DEBUG, "expr_eval_notify_expr_remove: no longer interested in " PF_EXPR,
2245 + expr_eval_notify_expr_remove_internal(expr);
2246 + expr_eval_notify_expr_flush_destroy_entity_list();
2249 +/* It would be very nice to try to optimize the expression before evaluation.
2251 + We are not interested in some CPU time complexity of the expression.
2252 + But we would be very happy to discard any user/host/group membership
2253 + dependencies (our 'variables'). Unfortunately such optimization is
2254 + NP problem (classification by courtesy of Daniel Kral) so it is considered
2255 + too expensive for us.
2257 + TODO in future: Full NP optimization for small number of variables and/or
2258 + heuristic optimizations for complex expressions.
2261 +static enum eval_result expr_eval_immediate TAC_ARGS((struct expr *expr_single));
2263 +static enum eval_result
2264 +expr_eval_immediate(expr_single)
2265 +struct expr *expr_single;
2267 + struct expr *expr_child, *expr_parent;
2268 + enum eval_result result_child, result_parent = 0 /* GCC paranoia */;
2270 + if (debug & DEBUG_CFGEVAL_FLAG)
2271 + report(LOG_DEBUG, "expr_eval_immediate: " PF_EXPR,
2272 + PA_EXPR(expr_single));
2277 + /* TOP->DOWN scanner: */
2280 + enum eval_result result_single;
2282 + if (debug & DEBUG_CFGEVAL_FLAG)
2283 + report(LOG_DEBUG, "expr_eval_immediate: top_down start: " PF_EXPR,
2284 + PA_EXPR(expr_single));
2286 + check_eval_scan_expr(expr_single, 0);
2287 + result_single = expr_single->request_scan.result;
2288 + if (result_single != ER_UNKNOWN)
2290 + switch (expr_single->type) {
2293 + expr_single = expr_single->u.not.child;
2298 + expr_single = expr_single->u.and_or.child_first;
2304 + ENTITY *entity = expr_single->u.entity.entity;
2306 + check_eval_scan_entity(entity, 0);
2308 + if (entity->request_scan.belongs == ER_UNKNOWN)
2309 + expr_eval_notify_expr(expr_single);
2311 + result_single = entity->request_scan.belongs;
2315 + report(LOG_ERR, "Illegal child node type %d for expr_eval", expr_single->type);
2316 + return (ER_UNKNOWN);
2319 + expr_single->request_scan.result = result_single;
2323 + /* BOTTOM->UP scanner: */
2325 + if (debug & DEBUG_CFGEVAL_FLAG)
2326 + report(LOG_DEBUG, "expr_eval_immediate: bottom_up start: " PF_EXPR,
2327 + PA_EXPR(expr_single));
2329 + expr_parent = expr_single->parent;
2332 + if (expr_parent->eval_scan.seq != eval_scan_seq) {
2333 + report(LOG_ERR, "INTERNAL: Parent expr node eval_scan NOT up-to-date");
2334 + return (ER_UNKNOWN);
2336 + if (expr_parent->request_scan.seq != request_scan_seq) {
2337 + report(LOG_ERR, "INTERNAL: Parent expr node request_scan NOT up-to-date");
2338 + return (ER_UNKNOWN);
2340 + if (expr_parent->request_scan.result != ER_UNKNOWN) {
2341 + report(LOG_WARNING, "INTERNAL-WARNING: Parent expr node already known, wasteful eval occured");
2342 + return (ER_UNKNOWN);
2345 + expr_child = expr_single;
2346 + result_child = expr_child->request_scan.result;
2348 + if (debug & DEBUG_CFGEVAL_FLAG)
2349 + report(LOG_DEBUG, "expr_eval_immediate: bottom_up switch: child=" PF_EXPR ",parent=" PF_EXPR,
2350 + PA_EXPR(expr_child), PA_EXPR(expr_parent));
2352 + switch (expr_parent->type) {
2355 + switch (result_child) {
2356 + case ER_UNKNOWN: result_parent = ER_UNKNOWN; break;
2357 + case ER_FALSE: result_parent = ER_TRUE; break;
2358 + case ER_TRUE: result_parent = ER_FALSE; break;
2364 + enum eval_result veto = (expr_parent->type==S_and ? ER_FALSE : ER_TRUE );
2365 + enum eval_result consent = (expr_parent->type==S_and ? ER_TRUE : ER_FALSE);
2367 + if (result_child == veto)
2368 + result_parent = veto;
2369 + else if (result_child == ER_UNKNOWN || result_child == consent) {
2370 + if (expr_child->next) {
2371 + expr_single = expr_child->next;
2372 + if (debug & DEBUG_CFGEVAL_FLAG)
2373 + report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: traversed to and_or next: " PF_EXPR,
2374 + PA_EXPR(expr_single));
2378 + if (debug & DEBUG_CFGEVAL_FLAG)
2379 + report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: full scan: " PF_EXPR,
2380 + PA_EXPR(expr_single));
2382 + /* It would be nice to pretend that all 'veto' decisions already made in the child
2383 + * had to set our 'result' to the correct value. But 'consent' decisions don't set
2384 + * us and the behaviour of auto-set from the child in 'veto' case may get changed
2385 + * in the future versions.
2386 + * So we rather don't depend on it.
2387 + * This overhead doesn't change altgorithmic complexity anyway.
2389 + result_parent = consent;
2390 + for (expr_child = expr_parent->u.and_or.child_first; expr_child; expr_child = expr_child->next)
2392 + check_eval_scan_expr(expr_child, 0); /* shouldn't be needed */
2393 + if (expr_child->request_scan.result == ER_UNKNOWN)
2394 + result_parent = ER_UNKNOWN; /* assumed (result_parent != veto) */
2395 + else if (expr_child->request_scan.result == veto) {
2396 + result_parent = veto;
2405 + report(LOG_ERR, "Illegal parent node type %d for expr_eval", expr_parent->type);
2406 + return (ER_UNKNOWN);
2409 + if (debug & DEBUG_CFGEVAL_FLAG)
2410 + report(LOG_DEBUG, "expr_eval_immediate: bottom_up end: child=" PF_EXPR ",parent=" PF_EXPR,
2411 + PA_EXPR(expr_child), PA_EXPR(expr_parent));
2413 + if (result_parent != ER_UNKNOWN) {
2414 + expr_parent->request_scan.result = result_parent;
2415 + /* we no longer need any notifications from entities to solve sub-expression */
2416 + expr_eval_notify_expr_remove(expr_parent);
2419 + expr_single = expr_parent;
2421 + /* The whole expression has been scanned to its root, we have "expr_single" */
2423 + if (debug & DEBUG_CFGEVAL_FLAG)
2424 + report(LOG_DEBUG, "expr_eval_immediate: done: " PF_EXPR,
2425 + PA_EXPR(expr_single));
2427 + return (expr_single->request_scan.result);
2430 +static void membership_solved TAC_ARGS((struct membership *membership));
2433 +membership_solved(membership)
2434 +struct membership *membership;
2436 + ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
2438 + check_request_scan_entity(parent_entity, 0);
2440 +#ifdef SCAN_PARANOIA
2441 + if (!membership->eval_scan.unsolved) {
2442 + report(LOG_ERR, "INTERNAL: membership already solved in membership_solved");
2447 + membership->eval_scan.unsolved = 0;
2449 +#ifdef SCAN_PARANOIA
2450 + if (!parent_entity->eval_scan.unsolved_to_child_membership_num) {
2451 + report(LOG_ERR, "INTERNAL: unsolved_to_child_membership_num-- == 0 in membership_solved");
2452 + parent_entity->eval_scan.unsolved_to_child_membership_num++;
2455 + parent_entity->eval_scan.unsolved_to_child_membership_num--;
2457 + if (!parent_entity->eval_scan.unsolved_to_child_membership_num
2458 + && parent_entity->request_scan.belongs == ER_UNKNOWN) {
2459 + parent_entity->request_scan.belongs = ER_FALSE;
2460 + register_kicked_entity(parent_entity, 1 /* priority */);
2464 +static void membership_parent_solve TAC_ARGS((struct membership *membership, enum eval_result how));
2467 +membership_parent_solve(membership, how)
2468 +struct membership *membership;
2469 +enum eval_result how;
2471 + enum eval_result negative = (how == ER_TRUE ? ER_FALSE : ER_TRUE);
2472 + ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
2474 + check_request_scan_entity(parent_entity, 0);
2476 + if (parent_entity->request_scan.belongs == negative)
2477 + report(LOG_ERR, "INTERNAL: parent " PF_ENTITY "already negative to what says membership " PF_MEMBERSHIP "in membership_eval_immediate",
2478 + PA_ENTITY(parent_entity), PA_MEMBERSHIP(membership));
2480 + parent_entity->request_scan.belongs = how;
2481 + register_kicked_entity(parent_entity, 1 /* priority */);
2483 + membership_solved(membership);
2485 + if (debug & DEBUG_CFGEVAL_FLAG)
2486 + report(LOG_DEBUG, "membership_parent_solve: " PF_MEMBERSHIP " marked parent " PF_ENTITY,
2487 + PA_MEMBERSHIP(membership), PA_ENTITY(parent_entity));
2490 +static void membership_eval_immediate TAC_ARGS((struct membership *membership));
2493 +membership_eval_immediate(membership)
2494 +struct membership *membership;
2496 + enum eval_result membership_valid;
2497 + ENTITY *child_entity, *parent_entity;
2499 + if (debug & DEBUG_CFGEVAL_FLAG)
2500 + report(LOG_DEBUG, "membership_eval_immediate: " PF_MEMBERSHIP,
2501 + PA_MEMBERSHIP(membership));
2503 + check_eval_scan_membership(membership, 0);
2505 + if (!membership->eval_scan.unsolved)
2507 + parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
2508 + check_request_scan_entity(parent_entity, 0);
2509 + if (parent_entity->request_scan.belongs != ER_UNKNOWN) /* why to solve this membership? */
2512 + membership_valid = expr_eval_immediate(membership->when);
2514 + child_entity = MEMBERSHIP_TO_CHILD_ENTITY( membership);
2515 + check_request_scan_entity( child_entity, 0);
2517 +#if 0 /* non-valid membership doesn't YET solve the parent! */
2518 + if (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE) {
2519 + membership_parent_solve(membership, ER_FALSE);
2524 + if (child_entity->request_scan.belongs == ER_TRUE && membership_valid == ER_TRUE ) {
2525 + membership_parent_solve(membership, ER_TRUE );
2529 + if ( child_entity->request_scan.belongs == ER_UNKNOWN)
2530 + register_kicked_entity( child_entity, 0 /* priority */);
2531 + if (parent_entity->request_scan.belongs == ER_UNKNOWN)
2532 + register_kicked_entity(parent_entity, 0 /* priority */);
2534 + if (parent_entity->request_scan.belongs != ER_UNKNOWN
2535 + || (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE))
2536 + membership_solved(membership);
2538 + if (debug & DEBUG_CFGEVAL_FLAG)
2539 + report(LOG_DEBUG, "membership_eval_immediate: done: " PF_MEMBERSHIP,
2540 + PA_MEMBERSHIP(membership));
2543 +static void entity_eval_immediate TAC_ARGS((ENTITY *entity));
2546 +entity_eval_immediate(entity)
2549 + struct tac_list_node *notified_expr_node;
2550 + struct tac_list_node *child_membership_node;
2552 + if (debug & DEBUG_CFGEVAL_FLAG)
2553 + report(LOG_DEBUG, "entity_eval_immediate: " PF_ENTITY,
2554 + PA_ENTITY(entity));
2556 + check_eval_scan_entity(entity, 0);
2558 + if (!request_scan_user_known) {
2559 +#ifdef SCAN_PARANOIA
2560 + if (entity->request_scan.belongs != ER_UNKNOWN)
2561 + report(LOG_ERR, "INTERNAL: belonging known while still !request_scan_user_known for " PF_ENTITY " in entity_eval_immediate",
2562 + PA_ENTITY(entity));
2567 + if (entity->request_scan.belongs == ER_UNKNOWN) {
2568 + if (entity->eval_scan.unsolved_to_child_membership_first) {
2569 + struct membership *order_membership = entity->eval_scan.unsolved_to_child_membership_first;
2570 + struct tac_list_node *next_membership_parent_node = tac_list_node_next(&order_membership->parent_node);
2572 + membership_eval_immediate(order_membership);
2573 + if (next_membership_parent_node)
2574 + entity->eval_scan.unsolved_to_child_membership_first = PARENT_NODE_TO_MEMBERSHIP(next_membership_parent_node);
2576 + entity->eval_scan.unsolved_to_child_membership_first = NULL;
2578 + register_kicked_entity(entity, 0 /* priority */);
2580 + if (debug & DEBUG_CFGEVAL_FLAG)
2581 + report(LOG_DEBUG, "entity_eval_immediate: finishing as we ordered child membership: " PF_MEMBERSHIP,
2582 + PA_MEMBERSHIP(order_membership));
2586 + if (!entity->eval_scan.unsolved_to_child_membership_num)
2587 + entity->request_scan.belongs = ER_FALSE;
2589 + if (debug & DEBUG_CFGEVAL_FLAG)
2590 + report(LOG_DEBUG, "entity_eval_immediate: finishing as unsolved child memberships still available and I'm still clueless");
2594 + /* belonging is known here */
2596 + /* recheck all memberships we may decide */
2598 + child_membership_node = tac_list_first_node(&entity->to_parent_membership_list);
2599 + child_membership_node;
2600 + child_membership_node = tac_list_node_next(child_membership_node)
2602 + struct membership *child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
2604 + membership_eval_immediate(child_membership);
2607 + /* notify all exprs which are interested in us */
2608 + while ((notified_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
2609 + tac_list_node_remove(notified_expr_node);
2610 + tac_list_addtail(&eval_notified_expr_list, notified_expr_node);
2613 + if (debug & DEBUG_CFGEVAL_FLAG)
2614 + report(LOG_DEBUG, "entity_eval_immediate: done: " PF_ENTITY,
2615 + PA_ENTITY(entity));
2619 +enum eval_result expr_eval TAC_ARGS((struct expr *expr));
2625 + if (debug & DEBUG_CFGEVAL_FLAG)
2626 + report(LOG_DEBUG, "expr_eval: top level order for " PF_EXPR,
2632 + eval_scan_begin();
2633 + if (expr_eval_immediate(expr) != ER_UNKNOWN)
2634 + return (expr->request_scan.result);
2636 + /* all 'solved' nodes MUST be removed BEFORE '*_immediate()' has been called,
2637 + * otherwise we may have no longer valid node!
2640 + struct tac_list_node *notified_expr_node, *kicked_entity_node;
2642 + /* check it rather always, checking just on notifications looks too complex.
2644 + if (expr->request_scan.result != ER_UNKNOWN) {
2645 + if (debug & DEBUG_CFGEVAL_FLAG)
2646 + report(LOG_DEBUG, "expr_eval: finishing as ordered " PF_EXPR " got known",
2648 + return (expr->request_scan.result);
2651 +#if 0 /* not needed as it is now always called after any destroy */
2652 + expr_eval_notify_expr_flush_destroy_entity_list(); /* eval_destroy_entity_list */
2653 +#endif /* not needed */
2655 + if ((notified_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
2656 + struct expr *notified_expr = NOTIFY_EXPR_NODE_TO_EXPR(notified_expr_node);
2658 + if (debug & DEBUG_CFGEVAL_FLAG)
2659 + report(LOG_DEBUG, "expr_eval: PROCESSING " PF_EXPR " from eval_NOTIFIED_expr_list",
2660 + PA_EXPR(notified_expr));
2662 + tac_list_node_remove(notified_expr_node);
2663 + expr_eval_immediate(notified_expr);
2665 + if (notified_expr->membership)
2666 + membership_eval_immediate(notified_expr->membership);
2668 + continue; /* shortcut */
2671 + if ((kicked_entity_node = tac_list_first_node(&eval_kicked_entity_list))) {
2672 + ENTITY *kicked_entity = PENDING_ENTITY_NODE_TO_ENTITY(kicked_entity_node);
2674 + if (debug & DEBUG_CFGEVAL_FLAG)
2675 + report(LOG_DEBUG, "expr_eval: PROCESSING " PF_ENTITY " from eval_KICKED_entity_list",
2676 + PA_ENTITY(kicked_entity));
2678 + tac_list_node_remove(kicked_entity_node);
2679 + entity_eval_immediate(kicked_entity);
2680 + continue; /* shortcut */
2683 + break; /* nothing done yet, all lists are empty! */
2686 + if (!expr->request_scan.loop_reported) {
2687 + report(LOG_WARNING, "Unable to resolve expression from line %d, some looping occured", expr->line);
2688 + expr->request_scan.loop_reported = 1;
2690 + return (ER_UNKNOWN);
2694 +void eval_force_belong_entity TAC_ARGS((ENTITY *entity));
2696 +void eval_force_belong_entity(entity)
2699 + if (debug & DEBUG_CFGEVAL_FLAG)
2700 + report(LOG_DEBUG, "eval_force_belong_entity: " PF_ENTITY " (before check_scan " PF_ERESULT_ENTITY ")",
2701 + PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
2703 + check_request_scan_entity(entity, 0);
2705 + if (entity->request_scan.belongs == ER_FALSE)
2706 + report(LOG_ERR, "Dangerous force of TRUE to FALSE-determined entity in eval_force_belong_entity");
2708 + entity->request_scan.belongs = ER_TRUE;
2711 +void scan_init_entity TAC_ARGS((ENTITY *entity));
2714 +scan_init_entity(entity)
2717 + entity->request_scan.seq = request_scan_seq-1; /* invalidate */
2718 + entity-> value_scan.seq = value_scan_seq-1; /* invalidate */
2719 + entity-> eval_scan.seq = eval_scan_seq-1; /* invalidate */
2720 + tac_list_init(&entity->eval_scan.notify_expr_list);
2721 + tac_list_node_init(&entity->eval_scan.pending_entity_node);
2724 +struct membership *enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child, struct expr *when));
2726 +struct membership *
2727 +enlist_entity_direct(parent, child, when)
2732 + struct membership *membership = (struct membership *) tac_malloc(sizeof(struct membership));
2734 + tac_list_node_init(&membership->parent_node);
2735 + tac_list_node_init(&membership->child_node);
2736 + membership->request_scan.seq = request_scan_seq-1;
2737 + tac_list_node_init(&membership->request_scan.virtual_membership_node);
2738 + membership->eval_scan.seq = eval_scan_seq-1;
2740 + tac_list_addtail(&parent->to_child_membership_list , &membership->parent_node);
2741 + parent->to_child_membership_num++;
2742 + tac_list_addtail(& child->to_parent_membership_list, &membership-> child_node);
2743 + membership->when = when;
2744 + if (expr_sink(membership->when, membership)) {
2745 + unlink_membership(membership);
2746 + free_membership(membership);
2750 + if (debug & DEBUG_CFGEVAL_FLAG)
2751 + report(LOG_DEBUG, "enlist_entity_direct: done: " PF_MEMBERSHIP,
2752 + PA_MEMBERSHIP(membership));
2754 + return (membership);
2757 +struct membership *virtual_enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child));
2759 +struct membership *
2760 +virtual_enlist_entity_direct(parent, child)
2764 + struct membership *membership;
2766 + if (debug & DEBUG_CFGEVAL_FLAG)
2767 + report(LOG_DEBUG, "virtual_enlist_entity_direct: the following enlist will be VIRTUAL...");
2769 + membership = enlist_entity_direct(parent, child, NULL /* when */);
2773 + check_request_scan_membership(membership, 0);
2774 + tac_list_addtail(&request_virtual_membership_list, &membership->request_scan.virtual_membership_node);
2776 + return (membership);
2779 +/* returns given 'entity' or NULL if already visited */
2781 +void (*value_scan_forward_seen_hook) TAC_ARGS((struct membership *membership));
2783 +static ENTITY *value_scan_forward TAC_ARGS((struct membership *membership));
2786 +value_scan_forward(membership)
2787 +struct membership *membership;
2789 + ENTITY *parent_entity;
2791 + if (debug & DEBUG_CFGEVAL_FLAG)
2792 + report(LOG_DEBUG, "value_scan_forward: from " PF_MEMBERSHIP " try forward...",
2793 + PA_MEMBERSHIP(membership));
2795 + parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
2797 + if (ER_TRUE != expr_eval(membership->when)) {
2798 + if (debug & DEBUG_CFGEVAL_FLAG)
2799 + report(LOG_DEBUG, "value_scan_forward: forward NOT successful due to failed 'when' evaluation.");
2802 + check_value_scan_entity(parent_entity, 0);
2803 + if (parent_entity->value_scan.seen) {
2804 + if (debug & DEBUG_CFGEVAL_FLAG)
2805 + report(LOG_DEBUG, "value_scan_forward: forward NOT successful as the parent " PF_ENTITY " was already seen this value scan.",
2806 + PA_ENTITY(parent_entity));
2807 + if (value_scan_forward_seen_hook)
2808 + (*value_scan_forward_seen_hook)(membership);
2811 + parent_entity->value_scan.seen = 1;
2812 + parent_entity->value_scan.from = membership;
2814 + if (debug & DEBUG_CFGEVAL_FLAG)
2815 + report(LOG_DEBUG, "value_scan_forward: forward SUCCESSFUL to parent " PF_ENTITY,
2816 + PA_ENTITY(parent_entity));
2817 + return (parent_entity);
2820 +struct membership *value_scan_backward TAC_ARGS((ENTITY *entity));
2822 +struct membership *
2823 +value_scan_backward(entity)
2826 + if (debug & DEBUG_CFGEVAL_FLAG)
2827 + report(LOG_DEBUG, "value_scan_backward: from " PF_ENTITY " went back to " PF_MEMBERSHIP,
2828 + PA_ENTITY(entity), PA_MEMBERSHIP(entity->value_scan.from));
2830 +#ifdef SCAN_PARANOIA
2831 + if (entity->value_scan.seq != value_scan_seq) {
2832 + report(LOG_ERR, "entity value_scan NOT up-to-date in value_scan_backward");
2837 + return (entity->value_scan.from);
2840 +/* Scan the entity graph and return each node found.
2841 + 'when' conditions for graph connections are respected,
2842 + looping is correctly prevented.
2845 +enum value_scan_func_result value_scan_entity TAC_ARGS((ENTITY *entity, int recurse, value_scan_func_t func, void *func_data));
2847 +enum value_scan_func_result
2848 +value_scan_entity(entity, recurse, func, func_data)
2851 +value_scan_func_t func;
2854 + enum value_scan_func_result vsfr;
2855 + struct tac_list_node *membership_node;
2857 + if (debug & DEBUG_CFGEVAL_FLAG)
2858 + report(LOG_DEBUG, "value_scan_entity: " PF_ENTITY ", recurse=%d",
2859 + PA_ENTITY(entity), recurse);
2861 + vsfr=(*func)(entity,func_data);
2863 + if (debug & DEBUG_CFGEVAL_FLAG)
2864 + report(LOG_DEBUG, "value_scan_entity: root func-> " PF_VSFR,
2867 + if (vsfr != VSFR_CONTINUE) {
2868 + if (debug & DEBUG_CFGEVAL_FLAG)
2869 + report(LOG_DEBUG, "value_scan_entity: finishing as root func didn't return VSFR_CONTINUE");
2873 + if (debug & DEBUG_CFGEVAL_FLAG)
2874 + report(LOG_DEBUG, "value_scan_entity: finishing as recurse not ordered");
2875 + return (VSFR_STOP);
2878 + value_scan_begin(entity);
2879 + membership_node = tac_list_first_node(&entity->to_parent_membership_list);
2880 + if (!membership_node) {
2881 + if (debug & DEBUG_CFGEVAL_FLAG)
2882 + report(LOG_DEBUG, "value_scan_entity: finishing as no parent entities of root");
2883 + return (VSFR_CONTINUE); /* no parent entities */
2887 + struct membership *membership = CHILD_NODE_TO_MEMBERSHIP(membership_node);
2889 + if (debug & DEBUG_CFGEVAL_FLAG)
2890 + report(LOG_DEBUG, "value_scan_entity: trace loop start: " PF_MEMBERSHIP,
2891 + PA_MEMBERSHIP(membership));
2893 + entity = value_scan_forward(membership);
2895 + if (debug & DEBUG_CFGEVAL_FLAG)
2896 + report(LOG_DEBUG, "value_scan_entity: successful recurse to " PF_ENTITY,
2897 + PA_ENTITY(entity));
2899 + vsfr=(*func)(entity,func_data);
2901 + if (debug & DEBUG_CFGEVAL_FLAG)
2902 + report(LOG_DEBUG, "value_scan_entity: func(" PF_ENTITY ")-> " PF_VSFR,
2903 + PA_ENTITY(entity), PA_VSFR(vsfr));
2905 + if (vsfr == VSFR_FOUND) {
2906 + if (debug & DEBUG_CFGEVAL_FLAG)
2907 + report(LOG_DEBUG, "value_scan_entity: finishing as func returned VSFR_FOUND");
2910 + if (vsfr == VSFR_CONTINUE)
2911 + membership_node = tac_list_first_node(&entity->to_parent_membership_list);
2913 + if (!entity || vsfr == VSFR_STOP) {
2914 + ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
2916 + entity = MEMBERSHIP_TO_CHILD_ENTITY(membership); /* for retreat from the LAST membership */
2918 + if (debug & DEBUG_CFGEVAL_FLAG)
2919 + report(LOG_DEBUG, "value_scan_entity: unsuccessful recurse to " PF_ENTITY ", tracing back through child " PF_ENTITY,
2920 + PA_ENTITY(parent_entity), PA_ENTITY(entity));
2922 + membership_node = tac_list_node_next(&membership->child_node);
2925 + while (!membership_node) {
2926 + membership = value_scan_backward(entity);
2927 + if (!membership) {
2928 + if (debug & DEBUG_CFGEVAL_FLAG)
2929 + report(LOG_DEBUG, "value_scan_entity: finishing as all nodes were scanned");
2930 + return (VSFR_CONTINUE); /* FINISH */
2933 + entity = MEMBERSHIP_TO_CHILD_ENTITY(membership); /* for retreat from the LAST membership */
2935 + if (debug & DEBUG_CFGEVAL_FLAG)
2936 + report(LOG_DEBUG, "value_scan_entity: backward retreat ('next' chase) "
2937 + "through " PF_MEMBERSHIP " to child " PF_ENTITY,
2938 + PA_MEMBERSHIP(membership), PA_ENTITY(entity));
2940 + membership_node = tac_list_node_next(&membership->child_node);
2945 diff --git a/cfgeval.h b/cfgeval.h
2946 new file mode 100644
2947 index 0000000..63f33cb
2952 +#define CFGEVAL_H 1
2954 +#include "tac_plus.h"
2960 +typedef struct entity ENTITY;
2961 +enum invalidate_scan {
2974 +enum value_scan_func_result {
2975 + VSFR_CONTINUE, /* for value_scan_entity() it means 'not found' */
2976 + VSFR_FOUND, /* immediately return from the whole value_scan_entity() */
2977 + VSFR_STOP /* backtrack (stop) this branch, scan further; nevere returned by value_scan_entity() */
2980 +struct membership {
2981 + struct tac_list_node parent_node; /* to_child_membership_list , AKA legacy "member" */
2982 + struct tac_list_node child_node; /* to_parent_membership_list */
2985 + unsigned seq; /* corresponds to global request_scan_seq */
2986 + struct tac_list_node virtual_membership_node;
2987 + } request_scan; /* cfg_request() scanning */
2990 + unsigned seq; /* corresponds to global eval_scan_seq */
2991 + unsigned unsolved:1; /* we haven't yet decreased
2992 + * parent_entity->eval_scan.unsolved_to_child_membership_num */
2993 + } eval_scan; /* expr_eval() scanning, many per value_scan */
2995 + struct expr *when;
2997 +#define MEMBERSHIP_TO_PARENT_ENTITY(membership) \
2998 + (&TAC_MEMBER_STRUCT(ENTITY, tac_list_node_get_list(&(membership)->parent_node), to_child_membership_list ))
2999 +#define MEMBERSHIP_TO_CHILD_ENTITY(membership) \
3000 + (&TAC_MEMBER_STRUCT(ENTITY, tac_list_node_get_list(&(membership)-> child_node), to_parent_membership_list))
3001 +#define PARENT_NODE_TO_MEMBERSHIP(parent_node_) \
3002 + (&TAC_MEMBER_STRUCT(struct membership, (parent_node_), parent_node))
3003 +#define CHILD_NODE_TO_MEMBERSHIP( child_node_) \
3004 + (&TAC_MEMBER_STRUCT(struct membership, ( child_node_), child_node))
3005 +#define UNSOLVED_CHILD_NODE_TO_MEMBERSHIP(unsolved_child_node_) \
3006 + (&TAC_MEMBER_STRUCT(struct membership, (unsolved_child_node_), eval_scan.unsolved_child_node))
3007 +#define VIRTUAL_MEMBERSHIP_NODE_TO_MEMBERSHIP(virtual_membership_node_) \
3008 + (&TAC_MEMBER_STRUCT(struct membership, (virtual_membership_node_), request_scan.virtual_membership_node))
3012 + unsigned seq; /* corresponds to global eval_scan_seq */
3013 + enum eval_result result; /* known result of this whole branch */
3014 + unsigned loop_reported:1; /* prevent excessive logging */
3015 + } request_scan; /* cfg_request() scanning */
3018 + unsigned seq; /* corresponds to global eval_scan_seq */
3021 + struct { /* for S_host, S_user or S_group */
3022 + /* connected to either "entity->eval_scan.notify_expr_list"
3023 + * or to global "eval_notified_expr_list"
3025 + struct tac_list_node notify_expr_node; /* gets removed on this expr->seq!= */
3029 + } eval_scan; /* expr_eval() scanning, many per value_scan */
3031 + struct membership *membership; /* our owner */
3032 + struct expr *parent; /* NULL if we are the root expr */
3033 + /* "parent" also (mis)used by expr_sink_{register,commit}() ! */
3034 + struct expr *next; /* used in childs of S_and / S_or */
3035 + int type; /* S_not, S_and, S_or, S_host, S_user or S_group */
3040 + struct expr *child;
3044 + struct expr *child_first; /* linked by expr->next */
3047 + struct { /* for S_host, S_user or S_group */
3054 +#define EXPR_ENTITY_TO_NOTIFYING_ENTITY(expr_) \
3055 + (&TAC_MEMBER_STRUCT(ENTITY, tac_list_node_get_list(&(expr_)->eval_scan.u.entity.notify_expr_node), eval_scan.notify_expr_list))
3056 +#define NOTIFY_EXPR_NODE_TO_EXPR(notify_expr_node_) \
3057 + (&TAC_MEMBER_STRUCT(struct expr, (notify_expr_node_), eval_scan.u.entity.notify_expr_node))
3059 +typedef enum value_scan_func_result (*value_scan_func_t) TAC_ARGS((ENTITY *entity,void *func_data));
3060 +extern void (*value_scan_forward_seen_hook) TAC_ARGS((struct membership *membership));
3063 +extern int request_scan_user_known; /* have we allowed to 'solve' S_user entities at all? */
3066 +extern void unlink_expr TAC_ARGS((struct expr *expr));
3067 +extern void free_expr TAC_ARGS((struct expr *expr));
3068 +extern void scan_free_entity TAC_ARGS((ENTITY *entity));
3069 +extern struct expr *new_expr TAC_ARGS((int type));
3070 +extern enum value_scan_func_result value_scan_entity TAC_ARGS((ENTITY *entity, int recurse, value_scan_func_t func, void *func_data));
3071 +extern struct membership *value_scan_backward TAC_ARGS((ENTITY *entity));
3072 +extern enum eval_result expr_eval TAC_ARGS((struct expr *expr_single));
3073 +extern struct expr *dupl_expr TAC_ARGS((const struct expr *in));
3074 +extern void scan_init_entity TAC_ARGS((ENTITY *entity));
3075 +extern struct membership *enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child, struct expr *when));
3076 +extern struct membership *virtual_enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child));
3077 +extern void scan_invalidate_entities_hashtable TAC_ARGS((void **hashtable, enum invalidate_scan what));
3078 +extern void request_scan_begin TAC_ARGS((void));
3079 +extern void eval_force_belong_entity TAC_ARGS((ENTITY *entity));
3080 +extern void expr_sink_register TAC_ARGS((struct expr *expr));
3081 +extern int expr_sink_commit TAC_ARGS((void));
3084 +#endif /* CFGEVAL_H */
3085 diff --git a/cfgfile.c b/cfgfile.c
3086 index 6eaef53..041993c 100644
3090 FITNESS FOR A PARTICULAR PURPOSE.
3094 #include "tac_plus.h"
3097 +#include <stdlib.h>
3099 -#include "regexp.h"
3100 +#include <string.h>
3102 +#ifndef WITH_INCLUDED_REGEX
3103 +#ifdef HAVE_REGEX_H
3108 +#include "cfgfile.h"
3109 +#include "report.h"
3114 +#include "do_author.h" /* for "struct identity" */
3116 +#ifdef WITH_INCLUDED_REGEX
3117 +#include "tac_regexp.h"
3121 +static void sym_get TAC_ARGS((void));
3122 +static void when_expr_root_init TAC_ARGS((void));
3123 +static void rch TAC_ARGS((void));
3124 +static int parse_entity TAC_ARGS((int entity_type));
3125 +static NODE *parse_svcs TAC_ARGS((void));
3126 +static int parse_conditional_block TAC_ARGS((ENTITY *entity));
3127 +static NODE *parse_cmd_matches TAC_ARGS((void));
3128 +static NODE *parse_attrs TAC_ARGS((void));
3129 +static void getsym TAC_ARGS((void));
3130 +static enum eval_result entity_svc_default TAC_ARGS((ENTITY *entity));
3136 - <decl> := <top_level_decl> | <user_decl>
3137 + <decl> := <top_level_decl> | <entity_decl>
3139 <top_level_decl> := <authen_default> |
3140 - accounting file = <string>
3141 + accounting file = <string> |
3142 default authorization = permit |
3145 + authorization = ( first | recursive )
3147 <authen_default> := default authentication = file <filename>
3153 -<permission> := permit | deny
3154 + <permission> := permit | deny
3156 <filename> := <string>
3158 <password> := <string>
3160 <user_decl> := user = <string> {
3161 - [ default service = [ permit | deny ] ]
3162 + [ <service_default> ]
3167 + <host_decl> := host = <string> {
3168 + [ <service_default> ]
3173 + <group_decl> := group = <string> {
3174 + [ <service_default> ]
3179 + <service_default> := default service = ( permit | deny | default )
3181 <password_spec> := file <filename> |
3183 cleartext <password> |
3184 @@ -80,23 +129,66 @@
3185 global = cleartext <string> |
3187 before authorization = <string> |
3188 - after authorization = <string>
3189 + after authorization = <string> |
3192 + <host_attr> := key = <string> |
3195 + <group_attr> := enlist = <entity_spec> |
3199 + <when_attr> := member = <string> |
3200 + enlist = <entity_spec> |
3204 + <when_attr_block> := <when_decl> {
3208 <svc> := <svc_auth> | <cmd_auth>
3210 <cmd_auth> := cmd = <string> {
3215 - <cmd-match> := <permission> <string>
3216 + <when_match> := <permission> <string> |
3217 + <when_match_block>
3219 + <when_match_block> := <when_decl> {
3223 - <svc_auth> := service = ( exec | arap | slip | ppp protocol = <string> {
3224 + <svc_auth> := service = ( exec | arap | slip | ppp protocol = <string> ) {
3225 +# first matching <svc_auth> is the FINAL one, no further graph scanning occurs!
3226 [ default attribute = permit ]
3227 - <attr_value_pair>*
3231 + <when_AV_pair> := [ optional ] <string> = <string> |
3232 + <when_AV_pair_block>
3234 + <when_AV_pair_block> := <when_decl> {
3238 - <attr_value_pair> := [ optional ] <string> = <string>
3239 + <when_decl> := when = <expr>
3241 +# to avoid ambiguous precence by forbid of "or" & "and" without parentheses:
3242 + <expr> := <entity_spec> |
3244 + '(' <expr_or> ')' |
3245 + '(' <expr_and> ')'
3247 + <expr_or> := <expr> |
3248 + <expr> or <expr_or>
3250 + <expr_and> := <expr> |
3251 + <expr> and <expr_and>
3253 + <entity_spec> := ( user | host | group ) <string>
3256 static char sym_buf[MAX_INPUT_LINE_LEN]; /* parse buffer */
3257 @@ -107,102 +199,54 @@ static int sym_line = 1; /* current line number for parsing */
3258 static FILE *cf = NULL; /* config file pointer */
3259 static int sym_error = 0; /* a parsing error has occurred */
3260 static int no_user_dflt = 0; /* default if user doesn't exist */
3261 + /* ='default authorization': 0/S_permit */
3262 +static int algorithm_recursive = 0; /* use newer authorization alogrithm? */
3263 + /* 1 if 'authorization = recursive' */
3264 static char *authen_default = NULL; /* top level authentication default */
3265 -static int authen_default_method = 0; /*For method check */
3266 + /* ='default authentication' */
3267 +static int authen_default_method = 0; /* For method check */
3268 + /* ='default authentication' symbol */
3269 static char *nopasswd_str = "nopassword";
3271 -/* A host definition structure. Currently unused, but when we start
3272 - configuring host-specific information e.g. per-host keys, this is
3273 - where it should be kept.
3275 - The first 2 fields (name and hash) are used by the hash table
3276 - routines to hash this structure into a table. Do not (re)move them */
3279 - char *name; /* host name */
3280 - void *hash; /* hash table next pointer */
3281 - int line; /* line number defined on */
3282 - char *key; /* host spesific key */
3283 - char *type; /* host type */
3286 -/* A user or group definition
3288 - The first 2 fields (name and hash) are used by the hash table
3289 - routines to hash this structure into a table. Move them at your
3293 - char *name; /* username */
3294 - void *hash; /* hash table next pointer */
3295 - int line; /* line number defined on */
3296 - long flags; /* flags field */
3298 -#define FLAG_ISUSER 1 /* this structure represents a user */
3299 -#define FLAG_ISGROUP 2 /* this structure represents a group */
3300 -#define FLAG_SEEN 4 /* for circular definition detection */
3302 - char *full_name; /* users full name */
3303 - char *login; /* Login password */
3304 - int nopasswd; /* user requires no password */
3305 - char *global; /* password to use if none set */
3306 - char *member; /* group we are a member of */
3307 - char *expires; /* expiration date */
3308 - char *arap; /* our arap secret */
3309 - char *pap; /* our pap secret */
3310 - char *opap; /* our outbound pap secret */
3311 - char *chap; /* our chap secret */
3313 - char *mschap; /* our mschap secret */
3314 -#endif /* MSCHAP */
3315 - char *msg; /* a message for this user */
3316 - char *before_author; /* command to run before authorization */
3317 - char *after_author; /* command to run after authorization */
3318 - int svc_dflt; /* default authorization behaviour for svc or
3320 - NODE *svcs; /* pointer to svc nodes */
3322 - int maxsess; /* Max sessions/user */
3323 -#endif /* MAXSESS */
3324 - char *time; /* Timestamp */
3327 -typedef struct host HOST;
3328 -typedef struct user USER;
3330 /* Only the first 2 fields (name and hash) are used by the hash table
3331 routines to hashh structures into a table.
3339 -typedef union hash HASH;
3340 +static void *grouptable[HASH_TAB_SIZE]; /* Table of group declarations */
3341 +static void *usertable[HASH_TAB_SIZE]; /* Table of user declarations */
3342 +static void *hosttable[HASH_TAB_SIZE]; /* Table of host declarations */
3344 -void *grouptable[HASH_TAB_SIZE];/* Table of group declarations */
3345 -void *usertable[HASH_TAB_SIZE]; /* Table of user declarations */
3346 -void *hosttable[HASH_TAB_SIZE]; /* Table of host declarations */
3348 +struct enlist_entity_item {
3349 + struct enlist_entity_item *next;
3350 + int parent_type; char *parent;
3351 + int child_type; char * child; /* will be created when not found (for "enlist") */
3352 + struct expr *when;
3355 +static struct enlist_entity_item * enlist_entity_list;
3356 +static struct enlist_entity_item **enlist_entity_list_tailp = &enlist_entity_list;
3361 +static void parse_error TAC_ARGS((char *fmt,...)) G_GNUC_PRINTF(1, 2);
3365 #include <stdarg.h> /* ANSI C, variable length args */
3367 parse_error(char *fmt,...)
3370 +#else /* __STDC__ */
3372 #include <varargs.h> /* has 'vararg' definitions */
3375 parse_error(fmt, va_alist)
3378 va_dcl /* no terminating semi-colon */
3381 +#endif /* __STDC__ */
3383 char msg[256]; /* temporary string */
3385 @@ -220,7 +264,9 @@ va_dcl /* no terminating semi-colon */
3390 +const char *cfg_nodestring TAC_ARGS((int type));
3393 cfg_nodestring(type)
3396 @@ -250,6 +296,54 @@ cfg_nodestring(type)
3400 +const char *entity_type_to_string TAC_ARGS((int entity_type));
3403 +entity_type_to_string(entity_type)
3406 + switch (entity_type) {
3417 +static void **entity_type_to_hashtable TAC_ARGS((int entity_type));
3420 +entity_type_to_hashtable(entity_type)
3423 + switch (entity_type) {
3425 + return (usertable);
3427 + return (hosttable);
3429 + return (grouptable);
3434 +void scan_invalidate_entities TAC_ARGS((enum invalidate_scan what));
3437 +scan_invalidate_entities(what)
3438 +enum invalidate_scan what;
3440 + scan_invalidate_entities_hashtable( usertable, what);
3441 + scan_invalidate_entities_hashtable( hosttable, what);
3442 + scan_invalidate_entities_hashtable(grouptable, what);
3446 +static void free_attrs TAC_ARGS((NODE *node));
3451 @@ -257,13 +351,17 @@ NODE *node;
3455 + unlink_expr(node->when);
3456 + free_expr(node->when);
3457 + node->when = NULL;
3459 switch (node->type) {
3462 if (debug & DEBUG_CLEAN_FLAG)
3463 report(LOG_DEBUG, "free_cmd_match %s %s",
3464 cfg_nodestring(node->type),
3466 + (const char *) node->value);
3469 report(LOG_ERR, "Illegal node type %s for free_attrs",
3470 @@ -278,6 +376,8 @@ NODE *node;
3474 +static void free_cmd_matches TAC_ARGS((NODE *node));
3477 free_cmd_matches(node)
3479 @@ -288,16 +388,32 @@ NODE *node;
3480 if (debug & DEBUG_CLEAN_FLAG)
3481 report(LOG_DEBUG, "free_cmd_match %s %s",
3482 cfg_nodestring(node->type),
3484 + (const char *) node->value);
3486 + unlink_expr(node->when);
3487 + free_expr(node->when);
3488 + node->when = NULL;
3490 free(node->value); /* text */
3491 - free(node->value1); /* regexp compiled text */
3493 +#ifdef WITH_INCLUDED_REGEX
3495 + free(node->value1); /* tac_regexp compiled text */
3497 +#else /* WITH_INCLUDED_REGEX */
3499 + regfree((regex_t *) node->value1); /* POSIX regex compiled text */
3501 +#endif /* WITH_INCLUDED_REGEX */
3509 +static void free_svcs TAC_ARGS((NODE *node));
3514 @@ -305,12 +421,16 @@ NODE *node;
3518 + unlink_expr(node->when);
3519 + free_expr(node->when);
3520 + node->when = NULL;
3522 switch (node->type) {
3524 if (debug & DEBUG_CLEAN_FLAG)
3525 report(LOG_DEBUG, "free %s %s",
3526 - cfg_nodestring(node->type), node->value);
3527 + cfg_nodestring(node->type),
3528 + (const char *) node->value);
3529 free(node->value); /* cmd name */
3530 free_cmd_matches(node->value1);
3532 @@ -340,85 +460,107 @@ NODE *node;
3536 +static void free_enlist_entity_item TAC_ARGS((struct enlist_entity_item *item));
3539 +free_enlist_entity_item(item)
3540 +struct enlist_entity_item *item;
3542 + free(item->parent);
3543 + free(item->child);
3544 + free_expr(item->when);
3548 +static void free_entity TAC_ARGS((ENTITY *entity));
3551 -free_userstruct(user)
3553 +free_entity(entity)
3556 if (debug & DEBUG_CLEAN_FLAG)
3557 report(LOG_DEBUG, "free %s %s",
3558 - (user->flags & FLAG_ISUSER) ? "user" : "group",
3563 - if (user->full_name)
3564 - free(user->full_name);
3566 - free(user->login);
3568 - free(user->member);
3569 - if (user->expires)
3570 - free(user->expires);
3577 + entity_type_to_string(entity->type), entity->name);
3579 + /* function MUST be called while the whole entity is still VALID! */
3580 + scan_free_entity(entity);
3583 + free(entity->name);
3584 + if (entity->full_name)
3585 + free(entity->full_name);
3586 + if (entity->login)
3587 + free(entity->login);
3588 + if (entity->expires)
3589 + free(entity->expires);
3591 + free(entity->time);
3593 + free(entity->arap);
3595 + free(entity->chap);
3598 - free(user->mschap);
3599 + if (entity->mschap)
3600 + free(entity->mschap);
3607 - free(user->global);
3610 - if (user->before_author)
3611 - free(user->before_author);
3612 - if (user->after_author)
3613 - free(user->after_author);
3614 - free_svcs(user->svcs);
3616 + free(entity->pap);
3618 + free(entity->opap);
3619 + if (entity->global)
3620 + free(entity->global);
3622 + free(entity->msg);
3623 + if (entity->before_author)
3624 + free(entity->before_author);
3625 + if (entity->after_author)
3626 + free(entity->after_author);
3628 + free(entity->key);
3629 + free_svcs(entity->svcs);
3632 +static void free_hashtable TAC_ARGS((void **hashtable));
3635 -free_hoststruct(host)
3637 +free_hashtable(hashtable)
3640 - if (debug & DEBUG_CLEAN_FLAG)
3641 - report(LOG_DEBUG, "free %s",
3650 + ENTITY *entity,**entityp;
3654 + for (i = 0; i < HASH_TAB_SIZE; i++) {
3655 + entityp = (ENTITY **) (hashtable+i);
3656 + while ((entity = *entityp)) {
3657 + *entityp = entity->hash;
3658 + free_entity(entity);
3669 +void cfg_clean_config TAC_ARGS((void));
3671 /* Free all allocated structures preparatory to re-reading the config file */
3676 - USER *entry, *next;
3677 - HOST *host_entry,*hn;
3678 + struct enlist_entity_item *enlist_entity_item;
3680 if (authen_default) {
3681 free(authen_default);
3682 authen_default = NULL;
3685 + if (algorithm_recursive) {
3686 + algorithm_recursive = 0;
3689 if (authen_default_method) {
3690 authen_default_method = 0;
3692 @@ -438,43 +580,21 @@ cfg_clean_config()
3693 session.db_acct = NULL;
3696 - /* clean the hosttable */
3697 - for (i = 0; i < HASH_TAB_SIZE; i++) {
3698 - host_entry = (HOST *) hosttable[i];
3699 - while (host_entry) {
3700 - hn = host_entry->hash;
3701 - free_hoststruct(host_entry);
3705 - hosttable[i] = NULL;
3708 - /* the grouptable */
3709 - for (i = 0; i < HASH_TAB_SIZE; i++) {
3710 - entry = (USER *) grouptable[i];
3712 - next = entry->hash;
3713 - free_userstruct(entry);
3717 - grouptable[i] = NULL;
3719 + free_hashtable( usertable);
3720 + free_hashtable( hosttable);
3721 + free_hashtable(grouptable);
3723 - /* the usertable */
3724 - for (i = 0; i < HASH_TAB_SIZE; i++) {
3725 - entry = (USER *) usertable[i];
3727 - next = entry->hash;
3728 - free_userstruct(entry);
3732 - usertable[i] = NULL;
3733 + while (enlist_entity_list) {
3734 + enlist_entity_item = enlist_entity_list;
3735 + enlist_entity_list = enlist_entity_item->next;
3736 + free_enlist_entity_item(enlist_entity_item);
3737 + free(enlist_entity_item);
3739 + enlist_entity_list_tailp = &enlist_entity_list;
3742 +static int parse_permission TAC_ARGS((void));
3747 @@ -490,6 +610,8 @@ parse_permission()
3751 +static int parse TAC_ARGS((int symbol));
3756 @@ -505,9 +627,13 @@ int symbol;
3760 +static int parse_opt_svc_default TAC_ARGS((void));
3763 parse_opt_svc_default()
3767 if (sym_code != S_default) {
3770 @@ -515,14 +641,30 @@ parse_opt_svc_default()
3774 - if (sym_code == S_permit) {
3776 - return (S_permit);
3778 + switch (sym_code) {
3780 + parse_error("expecting 'permit', 'deny' or 'default' but found '%s' on line %d",
3781 + sym_buf, sym_line);
3785 + if (!algorithm_recursive) {
3786 + parse_error("'default service = %s' supported only if set top level 'authorization = recursive', on line %d",
3787 + sym_buf, sym_line);
3793 + retval = sym_code;
3801 +static int parse_opt_attr_default TAC_ARGS((void));
3804 parse_opt_attr_default()
3806 @@ -536,20 +678,19 @@ parse_opt_attr_default()
3810 -static int parse_user();
3811 -static int parse_host();
3817 Parse lines in the config file, creating data structures
3818 Return 1 on error, otherwise 0 */
3820 +static int parse_decls TAC_ARGS((void));
3825 no_user_dflt = 0; /* default if user doesn't exist */
3826 + algorithm_recursive = 0; /* use backward compatible alg. by default */
3827 + when_expr_root_init();
3828 + enlist_entity_list_tailp = &enlist_entity_list;
3832 @@ -614,7 +755,7 @@ parse_decls()
3841 @@ -642,6 +783,26 @@ parse_decls()
3845 + case S_authorization:
3847 + parse(S_separator);
3848 + switch (sym_code) {
3850 + parse_error("expecting 'first' or 'recursive' but found '%s' on line %d",
3851 + sym_buf, sym_line);
3856 + algorithm_recursive = 0;
3860 + parse(S_recursive);
3861 + algorithm_recursive = 1;
3866 /* Process a key declaration. */
3868 @@ -656,17 +817,12 @@ parse_decls()
3880 + parse_entity(sym_code);
3883 - /* case S_host: parse_host(); continue; */
3886 parse_error("Unrecognised token %s on line %d", sym_buf, sym_line);
3888 @@ -674,8 +830,6 @@ parse_decls()
3892 -static NODE *parse_svcs();
3894 /* Assign a value to a field. Issue an error message and return 1 if
3895 it's already been assigned. This is a macro because I was sick of
3896 repeating the same code fragment over and over */
3897 @@ -688,147 +842,511 @@ sym_get(); parse(S_separator); if (field) { \
3899 field = tac_strdup(sym_buf);
3903 +static struct expr *when_expr_root;
3904 +#define WHEN_EXPR_ROOT_SANE() \
3905 + (when_expr_root && !when_expr_root->next && when_expr_root->type==S_and)
3906 +#define WHEN_EXPR_ROOT_EMPTY() \
3907 + (WHEN_EXPR_ROOT_SANE() && !when_expr_root->u.and_or.child_first)
3909 +static struct expr *parse_expr_node TAC_ARGS((int single_item));
3911 +static struct expr *
3912 +parse_expr_node(single_item)
3916 - HOST *host = (HOST *) tac_malloc(sizeof(HOST));
3918 - char buf[MAX_INPUT_LINE_LEN];
3919 + struct expr *expr_root = NULL;
3920 + struct expr **succ_exprp = &expr_root;
3921 + struct expr *expr;
3923 - bzero(host, sizeof(HOST));
3925 + switch (sym_code) {
3928 + expr = (struct expr *) tac_malloc(sizeof(struct expr));
3929 + expr->line = sym_line;
3930 + *succ_exprp = expr;
3931 + expr->next = NULL;
3932 + succ_exprp = &expr->next;
3933 + expr->type = S_not;
3935 - parse(S_separator);
3936 - host->name = tac_strdup(sym_buf);
3937 - host->line = sym_line;
3938 + expr->u.not.child = parse_expr_node(1 /* single_item */);
3939 + if (!expr->u.not.child) {
3940 + free_expr(expr_root);
3948 + expr = (struct expr *) tac_malloc(sizeof(struct expr));
3949 + expr->line = sym_line;
3950 + *succ_exprp = expr;
3951 + expr->next = NULL;
3952 + succ_exprp = &expr->next;
3953 + expr->type = sym_code;
3955 + expr->u.entity.name = tac_strdup(sym_buf);
3957 + expr->u.entity.entity = NULL; /* not known yet */
3960 - h = hash_add_entry(hosttable, (void *) host);
3963 + expr = parse_expr_node(0 /* single_item */);
3964 + *succ_exprp = expr;
3965 + parse(S_closeparen);
3968 - parse_error("multiply defined %s on lines %d and %d",
3969 - host->name, h->line, sym_line);
3972 + report(LOG_ERR, "Illegal filled next field of parsed parenthesed expr");
3973 + free_expr(expr_root);
3976 + succ_exprp = &expr->next;
3982 + parse_error("expecting 'not', 'user', 'host', 'group' or '(' but found '%s' on line %d",
3983 + sym_buf, sym_line);
3984 + free_expr(expr_root);
3988 + if (single_item) /* used by 'not' operator with high precedence */
3989 + return (expr_root);
3996 - ASSIGN(host->key);
4000 - ASSIGN(host->type);
4004 + if (expr_root->type == (sym_code==S_and ? S_or : S_and)) {
4005 + parse_error("ambiguous use of 'and' together with 'or', parentheses required on line %d",
4007 + free_expr(expr_root);
4010 + if (expr_root->type != sym_code) {
4011 + expr = (struct expr *) tac_malloc(sizeof(struct expr));
4012 + expr->line = sym_line;
4013 + expr->next = NULL;
4014 + expr->type = sym_code;
4015 + expr->u.and_or.child_first = expr_root;
4023 - parse(S_closebra);
4025 + return(expr_root);
4030 - parse_error("Unrecognised keyword %s for host %s on line %d",
4031 - sym_buf, host->name,sym_line);
4032 +static struct expr *parse_when_decl TAC_ARGS((void));
4035 +static struct expr *
4039 + if (!algorithm_recursive) {
4040 + parse_error("'when' conditionals supported only if set top level 'authorization = recursive', on line %d",
4045 -} /* finish parse_host */
4046 + parse(S_separator);
4047 + return (parse_expr_node(0 /* single_item */));
4050 +static void when_expr_root_init TAC_ARGS((void));
4053 +when_expr_root_init()
4055 + free_expr(when_expr_root);
4056 + when_expr_root = new_expr(S_and);
4059 +static int push_parsed_when_decl TAC_ARGS((void));
4063 +push_parsed_when_decl()
4067 - USER *user = (USER *) tac_malloc(sizeof(USER));
4070 - char buf[MAX_INPUT_LINE_LEN];
4071 + struct expr *parsed_expr;
4073 - bzero(user, sizeof(USER));
4074 + parsed_expr = parse_when_decl();
4077 + if (!WHEN_EXPR_ROOT_SANE()) {
4078 + report(LOG_ERR, "INTERNAL: when_expr_root not valid during push_parsed_when_decl()!");
4079 + free_expr(parsed_expr);
4082 + if (parsed_expr->next) {
4083 + report(LOG_ERR, "INTERNAL: Illegal filled next field of parsed expr");
4084 + free_expr(parsed_expr);
4087 + parsed_expr->next = when_expr_root->u.and_or.child_first;
4088 + when_expr_root->u.and_or.child_first = parsed_expr;
4089 + when_expr_root->line = parsed_expr->line;
4093 - isuser = (sym_code == S_user);
4094 +static int pop_when_decl TAC_ARGS((void));
4097 - parse(S_separator);
4098 - user->name = tac_strdup(sym_buf);
4099 - user->line = sym_line;
4103 + struct expr *first_expr;
4106 - user->flags |= FLAG_ISUSER;
4107 - n = hash_add_entry(usertable, (void *) user);
4109 - user->flags |= FLAG_ISGROUP;
4110 - n = hash_add_entry(grouptable, (void *) user);
4111 + if (!WHEN_EXPR_ROOT_SANE()) {
4112 + report(LOG_ERR, "INTERNAL: when_expr_root not valid during pop_when_decl()!");
4117 - parse_error("multiply defined %s %s on lines %d and %d",
4118 - isuser ? "user" : "group",
4119 - user->name, n->line, sym_line);
4120 + first_expr = when_expr_root->u.and_or.child_first;
4121 + if (!first_expr) {
4122 + report(LOG_ERR, "No expr in stack and pop_when_decl() called");
4127 + when_expr_root->u.and_or.child_first = first_expr->next;
4128 + first_expr->next = NULL;
4129 + free_expr(first_expr);
4133 - /* Is the default deny for svcs or cmds to be overridden? */
4134 - user->svc_dflt = parse_opt_svc_default();
4135 +static struct expr *copy_current_when_decl TAC_ARGS((void));
4138 - switch (sym_code) {
4141 +static struct expr *
4142 +copy_current_when_decl()
4144 + return (dupl_expr(when_expr_root));
4148 - ASSIGN(user->time);
4151 +static struct expr *when_expr_dungeon;
4155 - parse(S_authorization);
4156 - if (user->before_author)
4157 - free(user->before_author);
4158 - user->before_author = tac_strdup(sym_buf);
4159 +static void starve_when_decl TAC_ARGS((void));
4164 + if (!WHEN_EXPR_ROOT_SANE()) {
4165 + report(LOG_WARNING, "INTERNAL: when_expr_root not sane during starve_when_decl!");
4167 + when_expr_root->next = when_expr_dungeon;
4168 + when_expr_dungeon = when_expr_root;
4169 + when_expr_root = NULL;
4170 + when_expr_root_init();
4173 +static int feed_when_decl TAC_ARGS((void));
4178 + if (!when_expr_dungeon) {
4179 + report(LOG_ERR, "INTERNAL: No expr in dungeon and feed_when_decl() called");
4182 + if (!WHEN_EXPR_ROOT_EMPTY()) {
4183 + report(LOG_WARNING, "INTERNAL: Some 'when' expression found still pushed in dungeon during feed_when_decl()!");
4185 + free_expr(when_expr_root);
4186 + when_expr_root = when_expr_dungeon;
4187 + when_expr_dungeon = when_expr_dungeon->next;
4188 + when_expr_root->next = NULL;
4192 +ENTITY *entity_lookup TAC_ARGS((int type, const char *name));
4195 +entity_lookup(type, name)
4199 + return (hash_lookup(entity_type_to_hashtable(type), name));
4202 +static int enlist_entity_connect TAC_ARGS((void));
4205 +enlist_entity_connect()
4207 + struct enlist_entity_item *item;
4208 + ENTITY *parent_entity, *child_entity;
4210 + while ((item=enlist_entity_list)) {
4212 + parent_entity = entity_lookup(item->parent_type, item->parent);
4213 + if (!parent_entity) {
4214 + parse_error("Entity %s %s not defined, referenced as parent on line %d",
4215 + entity_type_to_string(item->parent_type), item->parent, item->line);
4218 + child_entity = entity_lookup(item-> child_type, item-> child);
4219 + if (!child_entity) {
4220 + child_entity = new_entity(item->child_type, item->child, item->line);
4221 + if (!child_entity)
4222 + return (1); /* 'hash_add_entry()' conflict */
4223 + item->child = NULL; /* don't free string ref'ed from 'child_entity'! */
4226 + if (!enlist_entity_direct(parent_entity, child_entity, item->when))
4227 + return (1); /* entities not found */
4229 + enlist_entity_list = item->next;
4230 + item->when = NULL;
4231 + free_enlist_entity_item(item);
4234 + enlist_entity_list_tailp = &enlist_entity_list;
4238 +static void enlist_entity TAC_ARGS((int parent_type, const char *parent, int child_type, const char *child));
4241 +enlist_entity(parent_type, parent, child_type, child)
4243 +const char *parent;
4247 + struct enlist_entity_item *item =
4248 + (struct enlist_entity_item *) tac_malloc(sizeof(struct enlist_entity_item));
4250 + item->next = NULL;
4251 + *enlist_entity_list_tailp = item;
4252 + enlist_entity_list_tailp = &item->next;
4254 + item->parent_type = parent_type;
4255 + item->parent = tac_strdup(parent);
4256 + item-> child_type = child_type;
4257 + item->child = tac_strdup(child);
4258 + item->when = copy_current_when_decl();
4259 + item->line = sym_line;
4262 +static int parse_entity_spec TAC_ARGS((void));
4264 +/* returns 0 for error, otherwise S_user, S_host or S_group; sym_buf filled */
4266 +parse_entity_spec()
4270 + if (sym_code != S_user
4271 + && sym_code != S_host
4272 + && sym_code != S_group
4274 + parse_error("Expecting 'user', 'host' or ' group' as entity specification, found %s on line %d",
4275 + sym_buf, sym_line);
4279 + retval = sym_code;
4287 +static int parse_conditional_block_item TAC_ARGS((ENTITY *entity));
4290 +parse_conditional_block_item(entity)
4293 + switch (sym_code) {
4297 + /* case S_closebra: not needed, handled by our caller parse_conditional_block() */
4300 + parse_error("Unrecognised keyword %s for entity on line %d",
4301 + sym_buf, sym_line);
4306 - parse(S_authorization);
4307 - if (user->after_author)
4308 - free(user->after_author);
4309 - user->after_author = tac_strdup(sym_buf);
4310 + parse(S_separator);
4311 + enlist_entity(S_group, sym_buf, entity->type, entity->name);
4317 + int parsed_entity_type;
4319 + if (entity->type != S_group) {
4320 + parse_error("'enlist' keyword allowed only in 'group' section on line %d",
4325 + parse(S_separator);
4326 + parsed_entity_type = parse_entity_spec();
4327 + if (!parsed_entity_type)
4329 + enlist_entity(entity->type, entity->name, parsed_entity_type, sym_buf);
4338 + if (entity->svcs) {
4340 * Already parsed some services/commands. Thanks to Gabor Kiss
4341 * who found this bug.
4344 - for (p=user->svcs; p->next; p=p->next)
4345 + for (p=entity->svcs; p->next; p=p->next)
4347 p->next = parse_svcs();
4349 - user->svcs = parse_svcs();
4350 + entity->svcs = parse_svcs();
4355 + if (parse_conditional_block(entity))
4363 +static int parse_conditional_block TAC_ARGS((ENTITY *entity));
4366 +parse_conditional_block(entity)
4369 + int retval = -1 /* GCC paranoia */;
4371 + if (push_parsed_when_decl())
4376 + if (sym_code == S_closebra) {
4378 + retval = 0; /* success */
4382 + if (parse_conditional_block_item(entity)) {
4383 + retval = 1; /* failure */
4388 + if (pop_when_decl())
4394 +/* passed 'name' WILL be directly stored to returned ENTITY, don't touch it! */
4396 +ENTITY *new_entity TAC_ARGS((int type, char *name, int line));
4399 +new_entity(type, name, line)
4404 + ENTITY *entity = (ENTITY *) tac_malloc(sizeof(ENTITY));
4405 + ENTITY *hash_conflict;
4407 + bzero(entity, sizeof(ENTITY));
4408 + tac_list_init(&entity->to_parent_membership_list);
4409 + tac_list_init(&entity->to_child_membership_list );
4410 + entity->to_child_membership_num = 0;
4411 + scan_init_entity(entity);
4413 + entity->type = type;
4414 + entity->name = name;
4415 + entity->line = line;
4417 + hash_conflict = hash_add_entry(entity_type_to_hashtable(type), (void *) entity);
4418 + if (hash_conflict) {
4419 + parse_error("multiply defined %s %s on lines %d and %d",
4420 + entity_type_to_string(type),
4421 + entity->name, hash_conflict->line, sym_line);
4429 +static int parse_entity TAC_ARGS((int entity_type));
4432 +parse_entity(entity_type)
4437 + char **fieldp = NULL /* GCC paranoia */;
4438 + char buf[MAX_INPUT_LINE_LEN];
4441 + parse(S_separator);
4443 + entity = new_entity(entity_type, tac_strdup(sym_buf) /* name */, sym_line /* line */);
4445 + return (1); /* 'hash_add_entry()' conflict, 'tac_strdup(sym_buf)' leaked! */
4450 + /* Is the default deny for svcs or cmds to be overridden? */
4451 + entity->svc_dflt = parse_opt_svc_default();
4454 + if (entity_type != S_user)
4455 + switch (sym_code) {
4457 + ASSIGN(entity->key);
4462 + switch (sym_code) {
4467 + ASSIGN(entity->time);
4473 + parse(S_authorization);
4474 + if (entity->before_author)
4475 + free(entity->before_author);
4476 + entity->before_author = tac_strdup(sym_buf);
4482 + parse(S_authorization);
4483 + if (entity->after_author)
4484 + free(entity->after_author);
4485 + entity->after_author = tac_strdup(sym_buf);
4490 - if (user->login) {
4491 + if (entity->login) {
4492 parse_error("Duplicate value for %s %s and %s on line %d",
4493 - codestring(sym_code), user->login,
4494 + codestring(sym_code), entity->login,
4498 @@ -837,15 +1355,15 @@ parse_user()
4502 - user->login = tac_strdup(sym_buf);
4503 + entity->login = tac_strdup(sym_buf);
4507 /* set to dummy string, so that we detect a duplicate
4508 * password definition attempt
4510 - user->login = tac_strdup(nopasswd_str);
4511 - user->nopasswd = 1;
4512 + entity->login = tac_strdup(nopasswd_str);
4513 + entity->nopasswd = 1;
4517 @@ -860,7 +1378,7 @@ parse_user()
4518 sprintf(buf, "%s ", sym_buf);
4520 strcat(buf, sym_buf);
4521 - user->login = tac_strdup(buf);
4522 + entity->login = tac_strdup(buf);
4526 @@ -878,9 +1396,9 @@ parse_user()
4531 + if (entity->pap) {
4532 parse_error("Duplicate value for %s %s and %s on line %d",
4533 - codestring(sym_code), user->pap,
4534 + codestring(sym_code), entity->pap,
4538 @@ -896,11 +1414,11 @@ parse_user()
4539 sprintf(buf, "%s ", sym_buf);
4541 strcat(buf, sym_buf);
4542 - user->pap = tac_strdup(buf);
4543 + entity->pap = tac_strdup(buf);
4546 sprintf(buf, "%s ", sym_buf);
4547 - user->pap = tac_strdup(buf);
4548 + entity->pap = tac_strdup(buf);
4552 @@ -918,23 +1436,17 @@ parse_user()
4556 - ASSIGN(user->full_name);
4561 - ASSIGN(user->member);
4562 + ASSIGN(entity->full_name);
4568 - ASSIGN(user->expires);
4569 + ASSIGN(entity->expires);
4574 - ASSIGN(user->msg);
4575 + ASSIGN(entity->msg);
4579 @@ -952,20 +1464,32 @@ parse_user()
4581 strcat(buf, sym_buf);
4583 - if (save_sym == S_arap)
4584 - fieldp = &user->arap;
4585 - if (save_sym == S_chap)
4586 - fieldp = &user->chap;
4587 + switch (save_sym) {
4589 + fieldp = &entity->arap;
4592 + fieldp = &entity->chap;
4595 - if (save_sym == S_mschap)
4596 - fieldp = &user->mschap;
4598 + fieldp = &entity->mschap;
4601 - if (save_sym == S_pap)
4602 - fieldp = &user->pap;
4603 - if (save_sym == S_opap)
4604 - fieldp = &user->opap;
4605 - if (save_sym == S_global)
4606 - fieldp = &user->global;
4608 + fieldp = &entity->pap;
4611 + fieldp = &entity->opap;
4614 + fieldp = &entity->global;
4617 + report(LOG_ERR, "INTERNAL: fieldp not recognized (on line %d)",
4623 parse_error("Duplicate value for %s %s and %s on line %d",
4624 @@ -984,7 +1508,7 @@ parse_user()
4628 - if (sscanf(sym_buf, "%d", &user->maxsess) != 1) {
4629 + if (sscanf(sym_buf, "%d", &entity->maxsess) != 1) {
4630 parse_error("expecting integer, found '%s' on line %d",
4633 @@ -997,16 +1521,14 @@ parse_user()
4635 "\npassword = <string> is obsolete. Use login = des <string>\n");
4637 - parse_error("Unrecognised keyword %s for user on line %d",
4638 - sym_buf, sym_line);
4641 + if (parse_conditional_block_item(entity))
4642 + return (0); /* error message already printed */
4647 -static NODE *parse_attrs();
4648 -static NODE *parse_cmd_matches();
4649 +static NODE *parse_svcs TAC_ARGS((void));
4653 @@ -1034,11 +1556,16 @@ parse_svcs()
4658 + starve_when_decl();
4659 result->value1 = parse_cmd_matches();
4660 + parse(S_closebra);
4661 + if (feed_when_decl())
4662 + tac_exit(1); /* no error return possibility */
4664 result->type = N_svc_cmd;
4665 + result->when = copy_current_when_decl();
4666 + expr_sink_register(result->when);
4668 - parse(S_closebra);
4669 result->next = parse_svcs();
4672 @@ -1075,25 +1602,52 @@ parse_svcs()
4673 result->value1 = tac_strdup(sym_buf);
4679 + starve_when_decl();
4681 result->dflt = parse_opt_attr_default();
4682 result->value = parse_attrs();
4687 + result->when = copy_current_when_decl();
4688 + expr_sink_register(result->when);
4690 result->next = parse_svcs();
4694 -/* <cmd-match> := <permission> <string> */
4695 +/* <cmd_match> := <permission> <string> */
4697 +static NODE *parse_cmd_matches TAC_ARGS((void));
4702 + NODE *retval = NULL, **succp = &retval;
4705 - if (sym_code != S_permit && sym_code != S_deny) {
4709 + switch (sym_code) {
4714 + if (push_parsed_when_decl())
4715 + tac_exit(1); /* no error return possibility */
4717 + result = parse_cmd_matches();
4718 + parse(S_closebra);
4719 + if (pop_when_decl())
4720 + tac_exit(1); /* no error return possibility */
4726 result = (NODE *) tac_malloc(sizeof(NODE));
4728 bzero(result, sizeof(NODE));
4729 @@ -1102,7 +1656,20 @@ parse_cmd_matches()
4730 result->type = (parse_permission() == S_permit) ? N_permit : N_deny;
4731 result->value = tac_strdup(sym_buf);
4733 - result->value1 = (void *) regcomp(result->value);
4734 +#ifdef WITH_INCLUDED_REGEX
4736 + result->value1 = (void *) tac_regcomp(result->value);
4738 +#else /* WITH_INCLUDED_REGEX */
4740 + result->value1 = tac_malloc(sizeof(regex_t));
4741 + if (regcomp(result->value1, result->value /* regex */, REG_NOSUB /* cflags */)) {
4742 + free(result->value1);
4743 + result->value1 = NULL;
4746 +#endif /* WITH_INCLUDED_REGEX */
4748 if (!result->value1) {
4749 report(LOG_ERR, "in regular expression %s on line %d",
4751 @@ -1110,30 +1677,56 @@ parse_cmd_matches()
4755 - result->next = parse_cmd_matches();
4756 + result->when = copy_current_when_decl();
4757 + expr_sink_register(result->when);
4760 + result->next = NULL;
4763 + while (result->next)
4764 + result = result->next; /* skip parsed chain from parse_cmd_matches() */
4765 + succp = &result->next;
4770 +static NODE *parse_attrs TAC_ARGS((void));
4775 + NODE *retval = NULL, **succp = &retval;
4777 char buf[MAX_INPUT_LINE_LEN];
4781 - if (sym_code == S_closebra) {
4787 + switch (sym_code) {
4792 + if (push_parsed_when_decl())
4793 + tac_exit(1); /* no error return possibility */
4795 + result = parse_attrs();
4796 + parse(S_closebra);
4797 + if (pop_when_decl())
4798 + tac_exit(1); /* no error return possibility */
4806 result = (NODE *) tac_malloc(sizeof(NODE));
4808 bzero(result, sizeof(NODE));
4809 result->line = sym_line;
4811 - if (sym_code == S_optional) {
4815 result->type = optional ? N_optarg : N_arg;
4817 strcpy(buf, sym_buf);
4818 @@ -1144,13 +1737,22 @@ parse_attrs()
4821 result->value = tac_strdup(buf);
4822 - result->next = parse_attrs();
4825 + result->when = copy_current_when_decl();
4826 + expr_sink_register(result->when);
4828 + result->next = NULL;
4831 + while (result->next)
4832 + result = result->next; /* skip parsed chain from parse_attrs() */
4833 + succp = &result->next;
4841 +static void sym_get TAC_ARGS((void));
4845 @@ -1163,9 +1765,11 @@ sym_get()
4849 +static char *sym_buf_add TAC_ARGS((int c));
4854 +int c; /* promoted "char" type */
4856 if (sym_pos >= MAX_INPUT_LINE_LEN) {
4857 sym_buf[MAX_INPUT_LINE_LEN-1] = '\0';
4858 @@ -1180,6 +1784,8 @@ char c;
4862 +static void getsym TAC_ARGS((void));
4867 @@ -1220,6 +1826,18 @@ next:
4872 + strcpy(sym_buf, "(");
4873 + sym_code = S_openparen;
4878 + strcpy(sym_buf, ")");
4879 + sym_code = S_closeparen;
4884 while ((sym_ch != '\n') && (sym_ch != EOF))
4886 @@ -1304,6 +1922,8 @@ next:
4890 +static void rch TAC_ARGS((void));
4895 @@ -1318,201 +1938,208 @@ rch()
4899 -/* For a user or group, find the value of a field. Does not recurse. */
4901 -get_value(user, field)
4903 +static VALUE get_value TAC_ARGS((ENTITY *entity, int field));
4905 +/* Find the value of a field. Does not recurse. */
4907 +get_value(entity, field)
4913 + v.pval = NULL; /* do both just for sure... */
4917 - parse_error("get_value: illegal user");
4919 + parse_error("get_value: illegal entity");
4925 - v.pval = user->name;
4926 + v.pval = entity->name;
4930 - v.pval = user->login;
4931 + v.pval = entity->login;
4935 - v.pval = user->global;
4939 - v.pval = user->member;
4940 + v.pval = entity->global;
4944 - v.pval = user->expires;
4945 + v.pval = entity->expires;
4949 - v.pval = user->arap;
4950 + v.pval = entity->arap;
4954 - v.pval = user->chap;
4955 + v.pval = entity->chap;
4960 - v.pval = user->mschap;
4961 + v.pval = entity->mschap;
4966 - v.pval = user->pap;
4967 + v.pval = entity->pap;
4971 - v.pval = user->opap;
4972 + v.pval = entity->opap;
4976 - v.pval = user->msg;
4977 + v.pval = entity->msg;
4981 - v.pval = user->svcs;
4982 + v.pval = entity->svcs;
4986 - v.pval = user->before_author;
4987 + v.pval = entity->before_author;
4991 - v.pval = user->after_author;
4992 + v.pval = entity->after_author;
4996 - v.intval = user->svc_dflt;
4997 + v.intval = entity->svc_dflt;
5002 - v.intval = user->maxsess;
5003 + v.intval = entity->maxsess;
5008 - v.intval = user->nopasswd;
5009 + v.intval = entity->nopasswd;
5013 - v.pval = user->time;
5014 + v.pval = entity->time;
5019 + if (entity->type == S_user) {
5020 + report(LOG_ERR, "get_value: S_key field not supported in %s %s",
5021 + entity_type_to_string(entity->type), entity->name);
5025 + v.pval = entity->key;
5029 report(LOG_ERR, "get_value: unknown field %d", field);
5035 -/* For host , find value of field. Doesn't recursive */
5037 -get_hvalue(host, field)
5041 +/* Internal graph scanning routines */
5043 +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));
5045 +static enum value_scan_func_result
5046 +value_scan(type, name, recurse, func, func_data)
5050 +value_scan_func_t func;
5056 - parse_error("get_hvalue: illegal host");
5061 - v.pval = host->name;
5066 - v.pval = host->key;
5068 + if (debug & DEBUG_CONFIG_FLAG)
5069 + report(LOG_DEBUG, "value_scan: find %s %s, recurse=%d",
5070 + entity_type_to_string(type), name, recurse);
5073 - report(LOG_ERR, "get_value: unknown field %d", field);
5075 + entity = entity_lookup(type, name);
5077 + if (debug & DEBUG_CONFIG_FLAG)
5078 + report(LOG_DEBUG, "value_scan: no %s named %s",
5079 + entity_type_to_string(type), name);
5080 + return (VSFR_CONTINUE);
5085 + return (value_scan_entity(entity, recurse, func, func_data));
5088 /* For each user, check she doesn't circularly reference a
5089 group. Return 1 if it does */
5091 -circularity_check()
5093 - USER *user, *entry, *group;
5094 - USER **users = (USER **) hash_get_entries(usertable);
5095 - USER **groups = (USER **) hash_get_entries(grouptable);
5099 - for (p = users; *p; p++) {
5101 +static int circularity_check_failed;
5103 - if (debug & DEBUG_PARSE_FLAG)
5104 - report(LOG_DEBUG, "circularity_check: user=%s", user->name);
5105 +static void circularity_check_fail TAC_ARGS((struct membership *membership));
5108 +circularity_check_fail(membership)
5109 +struct membership *membership;
5113 + circularity_check_failed = 1;
5115 - /* Initialise all groups "seen" flags to zero */
5116 - for (q = groups; *q; q++) {
5118 - group->flags &= ~FLAG_SEEN;
5119 + report(LOG_ERR, "recursively defined groups:");
5120 + while (membership) {
5121 + entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);
5122 + report(LOG_ERR, "%s %s",
5123 + entity_type_to_string(entity->type), entity->name);
5124 + membership = value_scan_backward(entity);
5129 +static enum value_scan_func_result circularity_check_func TAC_ARGS((ENTITY *entity, void *func_data));
5132 - /* check groups we are a member of */
5133 - char *groupname = entry->member;
5134 +static enum value_scan_func_result
5135 +circularity_check_func(entity, func_data /* unused */)
5139 + /* only useful to speedup case of failure */
5140 + if (circularity_check_failed)
5141 + return (VSFR_FOUND);
5143 - if (debug & DEBUG_PARSE_FLAG)
5144 - report(LOG_DEBUG, "\tmember of group %s",
5145 - groupname ? groupname : "<none>");
5146 + return (VSFR_CONTINUE);
5149 +static int circularity_check TAC_ARGS((void));
5151 - /* if not a member of any groups, go on to next user */
5155 +circularity_check()
5158 + ENTITY **users_base = (ENTITY **) hash_get_entries(usertable);
5161 - group = (USER *) hash_lookup(grouptable, groupname);
5163 - report(LOG_ERR, "%s=%s, group %s does not exist",
5164 - (entry->flags & FLAG_ISUSER) ? "user" : "group",
5165 - entry->name, groupname);
5170 - if (group->flags & FLAG_SEEN) {
5171 - report(LOG_ERR, "recursively defined groups");
5173 + for (users = users_base; *users; users++) {
5176 - /* print all seen "groups" */
5177 - for (q = groups; *q; q++) {
5179 - if (group->flags & FLAG_SEEN)
5180 - report(LOG_ERR, "%s", group->name);
5186 - group->flags |= FLAG_SEEN; /* mark group as seen */
5189 + if (debug & DEBUG_PARSE_FLAG)
5190 + report(LOG_DEBUG, "circularity_check: user=%s", entity->name);
5192 + circularity_check_failed = 0;
5193 + value_scan_forward_seen_hook = circularity_check_fail;
5194 + value_scan_entity(entity, TAC_PLUS_RECURSE,
5195 + (value_scan_func_t) circularity_check_func, NULL /* func_data-unused */);
5196 + value_scan_forward_seen_hook = NULL;
5197 + if (circularity_check_failed)
5204 + return (circularity_check_failed);
5208 @@ -1525,147 +2152,85 @@ circularity_check()
5209 Returns void * because it can return a string or a node pointer
5210 (should really return a union pointer).
5213 -cfg_get_value(name, isuser, attr, recurse)
5215 -int isuser, attr, recurse;
5217 - USER *user, *group;
5220 - value.pval = NULL;
5221 +static VALUE cfg_get_value_VALUE; /* private */
5223 - if (debug & DEBUG_CONFIG_FLAG)
5224 - report(LOG_DEBUG, "cfg_get_value: name=%s isuser=%d attr=%s rec=%d",
5225 - name, isuser, codestring(attr), recurse);
5227 - /* find the user/group entry */
5229 - user = (USER *) hash_lookup(isuser ? usertable : grouptable, name);
5232 - if (debug & DEBUG_CONFIG_FLAG)
5233 - report(LOG_DEBUG, "cfg_get_value: no user/group named %s", name);
5236 +static enum value_scan_func_result cfg_get_value_func TAC_ARGS((ENTITY *entity, int *attrp));
5238 +static enum value_scan_func_result
5239 +cfg_get_value_func(entity,attrp /* func_data */)
5243 /* found the entry. Lookup value from attr=value */
5244 - value = get_value(user, attr);
5245 + cfg_get_value_VALUE = get_value(entity, *attrp);
5246 + if (cfg_get_value_VALUE.pval)
5247 + return (VSFR_FOUND);
5249 - if (value.pval || !recurse) {
5252 - /* no value. Check containing group */
5254 - group = (USER *) hash_lookup(grouptable, user->member);
5257 + return (VSFR_CONTINUE);
5261 - if (debug & DEBUG_CONFIG_FLAG)
5262 - report(LOG_DEBUG, "cfg_get_value: recurse group = %s",
5264 +static VALUE cfg_get_value TAC_ARGS((int type, const char *name, int attr, int recurse));
5266 - value = get_value(group, attr);
5268 +cfg_get_value(type, name, attr, recurse)
5273 + if (debug & DEBUG_CONFIG_FLAG)
5274 + report(LOG_DEBUG, "cfg_get_value: type=%s name=%s attr=%s recurse=%d",
5275 + entity_type_to_string(type), name, codestring(attr), recurse);
5280 - /* still nothing. Check containing group and so on */
5281 + cfg_get_value_VALUE.pval = NULL;
5282 + value_scan(type, name, recurse,
5283 + (value_scan_func_t) cfg_get_value_func, &attr /* func_data */);
5284 + return (cfg_get_value_VALUE);
5287 - if (group->member)
5288 - group = (USER *) hash_lookup(grouptable, group->member);
5293 - /* no value for this user or her containing groups */
5294 - value.pval = NULL;
5297 +/* Wrappers for cfg_get_value:
5300 +int cfg_get_intvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
5302 -/* Wrappers for cfg_get_value */
5304 -cfg_get_intvalue(name, isuser, attr, recurse)
5306 -int isuser, attr, recurse;
5307 +cfg_get_intvalue(type, name, attr, recurse)
5312 - int val = cfg_get_value(name, isuser, attr, recurse).intval;
5313 + int val = cfg_get_value(type, name, attr, recurse).intval;
5315 if (debug & DEBUG_CONFIG_FLAG)
5316 report(LOG_DEBUG, "cfg_get_intvalue: returns %d", val);
5321 -cfg_get_pvalue(name, isuser, attr, recurse)
5323 -int isuser, attr, recurse;
5325 - char *p = cfg_get_value(name, isuser, attr, recurse).pval;
5327 - if (debug & DEBUG_CONFIG_FLAG)
5328 - report(LOG_DEBUG, "cfg_get_pvalue: returns %s",
5333 -/* For getting host values */
5335 -cfg_get_hvalue(name, attr)
5342 - value.pval = NULL;
5343 - if (debug & DEBUG_CONFIG_FLAG)
5344 - report(LOG_DEBUG, "cfg_get_hvalue: name=%s attr=%s ",
5345 - name, codestring(attr));
5347 - /* find the host entry in hash table */
5348 +const char *cfg_get_pvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
5350 - host = (HOST *) hash_lookup( hosttable, name);
5353 - if (debug & DEBUG_CONFIG_FLAG)
5354 - report(LOG_DEBUG, "cfg_get_hvalue: no host named %s", name);
5358 - /* found the entry. Lookup value from attr=value */
5359 - value = get_hvalue(host, attr);
5364 - /* No any value for this host */
5365 - value.pval = NULL;
5369 -/* Wrappers for cfg_get_hvalue */
5371 -cfg_get_phvalue(name, attr)
5375 +cfg_get_pvalue(type, name, attr, recurse)
5380 - char *p = cfg_get_hvalue(name, attr).pval;
5381 + char *p = cfg_get_value(type, name, attr, recurse).pval;
5383 if (debug & DEBUG_CONFIG_FLAG)
5384 - report(LOG_DEBUG, "cfg_get_phvalue: returns %s",
5385 + report(LOG_DEBUG, "cfg_get_pvalue: returns %s",
5391 - Read the config file and do some basic sanity checking on
5392 - it. Return 1 if we find any errors. */
5393 +/* Read the config file and do some basic sanity checking on
5394 + * it. Return 1 if we find any errors.
5396 +int cfg_read_config TAC_ARGS((const char *cfile));
5399 cfg_read_config(cfile)
5405 @@ -1679,7 +2244,17 @@ char *cfile;
5409 - if (circularity_check()) {
5411 + || enlist_entity_connect()
5412 + || expr_sink_commit()
5413 + /* circularity is allowed in the new fully-recursive algorithm */
5414 + || (!algorithm_recursive && circularity_check())
5419 + if (!WHEN_EXPR_ROOT_EMPTY() || when_expr_dungeon) {
5420 + report(LOG_ERR, "Some 'when' expression found still pushed on stack");
5424 @@ -1688,346 +2263,443 @@ char *cfile;
5428 -/* return 1 if user exists, 0 otherwise */
5429 +/* return 1 if user exists, 0 otherwise
5431 +int cfg_user_exists TAC_ARGS((const char *username));
5434 cfg_user_exists(username)
5436 +const char *username;
5438 - USER *user = (USER *) hash_lookup(usertable, username);
5440 - return (user != NULL);
5441 + return (NULL != hash_lookup(usertable, username));
5444 /* return expiry string of user. If none, try groups she is a member
5445 - on, and so on, recursively if recurse is non-zero */
5447 -cfg_get_expires(username, recurse)
5449 + * on, and so on, recursively if recurse is non-zero
5451 +const char *cfg_get_expires TAC_ARGS((const char *username, int recurse));
5454 +cfg_get_expires(username, recurse)
5455 +const char *username;
5458 - return (cfg_get_pvalue(username, TAC_IS_USER, S_expires, recurse));
5459 + return (cfg_get_pvalue(S_user, username, S_expires, recurse));
5462 /* return time string of user. If none, try groups she is a member
5463 - on, and so on, recursively if recurse is non-zero */
5465 + * on, and so on, recursively if recurse is non-zero
5467 +const char *cfg_get_timestamp TAC_ARGS((const char *username, int recurse));
5470 cfg_get_timestamp(username, recurse)
5472 +const char *username;
5475 - return (cfg_get_pvalue(username, TAC_IS_USER, S_time, recurse));
5476 + return (cfg_get_pvalue(S_user, username, S_time, recurse));
5480 /* return password string of user. If none, try groups she is a member
5481 - on, and so on, recursively if recurse is non-zero */
5483 -cfg_get_login_secret(user, recurse)
5485 + * on, and so on, recursively if recurse is non-zero
5487 +const char *cfg_get_login_secret TAC_ARGS((const char *user, int recurse));
5490 +cfg_get_login_secret(user, recurse)
5494 - return (cfg_get_pvalue(user, TAC_IS_USER, S_login, recurse));
5495 + return (cfg_get_pvalue(S_user, user, S_login, recurse));
5498 /* return value of the nopasswd field. If none, try groups she is a member
5499 - on, and so on, recursively if recurse is non-zero */
5500 + * on, and so on, recursively if recurse is non-zero
5502 +int cfg_get_user_nopasswd TAC_ARGS((const char *user, int recurse));
5505 cfg_get_user_nopasswd(user, recurse)
5510 - return (cfg_get_intvalue(user, TAC_IS_USER, S_nopasswd, recurse));
5511 + return (cfg_get_intvalue(S_user, user, S_nopasswd, recurse));
5514 /* return user's secret. If none, try groups she is a member
5515 - on, and so on, recursively if recurse is non-zero */
5517 -cfg_get_arap_secret(user, recurse)
5519 + * on, and so on, recursively if recurse is non-zero
5521 +const char *cfg_get_arap_secret TAC_ARGS((const char *user, int recurse));
5524 +cfg_get_arap_secret(user, recurse)
5528 - return (cfg_get_pvalue(user, TAC_IS_USER, S_arap, recurse));
5529 + return (cfg_get_pvalue(S_user, user, S_arap, recurse));
5533 -cfg_get_chap_secret(user, recurse)
5535 +const char *cfg_get_chap_secret TAC_ARGS((const char *user, int recurse));
5538 +cfg_get_chap_secret(user, recurse)
5542 - return (cfg_get_pvalue(user, TAC_IS_USER, S_chap, recurse));
5543 + return (cfg_get_pvalue(S_user, user, S_chap, recurse));
5548 -cfg_get_mschap_secret(user, recurse)
5551 +const char *cfg_get_mschap_secret TAC_ARGS((const char *user, int recurse));
5554 +cfg_get_mschap_secret(user, recurse)
5558 - return (cfg_get_pvalue(user, TAC_IS_USER, S_mschap, recurse));
5559 + return (cfg_get_pvalue(S_user, user, S_mschap, recurse));
5565 +const char *cfg_get_pap_secret TAC_ARGS((const char *user, int recurse));
5568 cfg_get_pap_secret(user, recurse)
5573 - return (cfg_get_pvalue(user, TAC_IS_USER, S_pap, recurse));
5574 + return (cfg_get_pvalue(S_user, user, S_pap, recurse));
5578 +const char *cfg_get_opap_secret TAC_ARGS((const char *user, int recurse));
5581 cfg_get_opap_secret(user, recurse)
5586 - return (cfg_get_pvalue(user, TAC_IS_USER, S_opap, recurse));
5587 + return (cfg_get_pvalue(S_user, user, S_opap, recurse));
5590 /* return the global password for the user (or the group, etc.) */
5593 -cfg_get_global_secret(user, recurse)
5595 +const char *cfg_get_global_secret TAC_ARGS((const char *user, int recurse));
5598 +cfg_get_global_secret(user, recurse)
5602 - return (cfg_get_pvalue(user, TAC_IS_USER, S_global, recurse));
5603 + return (cfg_get_pvalue(S_user, user, S_global, recurse));
5608 /* Return a pointer to a node representing a PAM Service name */
5610 -cfg_get_pam_service(user,recurse)
5613 +const char *cfg_get_pam_service TAC_ARGS((const char *user, int recurse));
5616 +cfg_get_pam_service(user, recurse)
5622 + const char *cfg_passwd;
5625 -cfg_passwd = cfg_get_pap_secret(user, recurse);
5626 + cfg_passwd = cfg_get_pap_secret(user, recurse);
5630 cfg_passwd = cfg_get_global_secret(user, recurse);
5633 -if (!cfg_passwd && !cfg_user_exists(user)) {
5634 + if (!cfg_passwd && !cfg_user_exists(user)) {
5635 cfg_passwd = cfg_get_authen_default();
5636 switch (cfg_get_authen_default_method()) {
5639 if (debug & DEBUG_AUTHOR_FLAG)
5640 report(LOG_DEBUG, "Get Default PAM Service :%s",cfg_passwd);
5645 if (debug & DEBUG_AUTHOR_FLAG)
5646 report(LOG_DEBUG, "I havent find any PAM Service!!");
5647 return(NULL);/* Haven't any PAM Service!! */
5652 -p=tac_find_substring("pam ", cfg_passwd);
5653 + p = tac_find_substring("pam ", cfg_passwd);
5655 -if(p) { /* We find PAM services */
5656 + if(p) { /* We find PAM services */
5657 if (debug & DEBUG_AUTHOR_FLAG)
5658 report(LOG_DEBUG, "I get PAM sevice:%s",p);
5664 -if (debug & DEBUG_AUTHOR_FLAG)
5665 + if (debug & DEBUG_AUTHOR_FLAG)
5666 report(LOG_DEBUG, "No any PAM Sevice");
5672 #endif /* For PAM */
5676 /* Return a pointer to a node representing a given service
5677 authorization, taking care of recursion issues correctly. Protocol
5678 - is only read if the type is N_svc_ppp. svcname is only read if type
5679 + is only read if the svctype is N_svc_ppp. svcname is only read if type
5684 -cfg_get_svc_node(username, type, protocol, svcname, recurse)
5687 -char *protocol, *svcname;
5690 - USER *user, *group;
5693 - if (debug & DEBUG_CONFIG_FLAG)
5695 - "cfg_get_svc_node: username=%s %s proto=%s svcname=%s rec=%d",
5697 - cfg_nodestring(type),
5698 - protocol ? protocol : "",
5699 - svcname ? svcname : "",
5702 - /* find the user/group entry */
5703 - user = (USER *) hash_lookup(usertable, username);
5704 +struct cfg_get_svc_node_param {
5706 + const char *protocol, *svcname;
5712 - if (debug & DEBUG_CONFIG_FLAG)
5713 - report(LOG_DEBUG, "cfg_get_svc_node: no user named %s", username);
5716 +static enum value_scan_func_result cfg_get_svc_node_func TAC_ARGS((ENTITY *entity, struct cfg_get_svc_node_param *param));
5718 - /* found the user entry. Find svc node */
5719 - for(svc = (NODE *) get_value(user, S_svc).pval; svc; svc = svc->next) {
5720 +static enum value_scan_func_result
5721 +cfg_get_svc_node_func(entity, param /* func_data */)
5723 +struct cfg_get_svc_node_param *param;
5726 + enum eval_result svc_default;
5728 - if (svc->type != type)
5729 + for (svc = (NODE *) get_value(entity, S_svc).pval; svc; svc = svc->next) {
5730 + if (svc->type != param->svctype)
5733 - if (type == N_svc_ppp && !STREQ(svc->value1, protocol)) {
5734 + if (param->svctype == N_svc_ppp && param->protocol && !STREQ(svc->value1, param->protocol))
5738 - if (type == N_svc && !STREQ(svc->value1, svcname)) {
5739 + if (param->svctype == N_svc && param->svcname && !STREQ(svc->value1, param->svcname ))
5741 + if (expr_eval(svc->when) != ER_TRUE) /* expensive */
5745 if (debug & DEBUG_CONFIG_FLAG)
5747 "cfg_get_svc_node: found %s proto=%s svcname=%s",
5748 - cfg_nodestring(type),
5749 - protocol ? protocol : "",
5750 - svcname ? svcname : "");
5751 + cfg_nodestring(param->svctype),
5752 + param->protocol ? param->protocol : "",
5753 + param->svcname ? param->svcname : "");
5756 + param->node = svc;
5757 + param->retval = 1;
5758 + return (VSFR_FOUND);
5762 - if (debug & DEBUG_CONFIG_FLAG)
5763 - report(LOG_DEBUG, "cfg_get_svc_node: returns NULL");
5766 + /* look at 'default service' settings */
5767 + svc_default = entity_svc_default(entity);
5768 + switch (svc_default) {
5770 - /* no matching node. Check containing group */
5772 - group = (USER *) hash_lookup(grouptable, user->member);
5777 + if (debug & DEBUG_AUTHOR_FLAG)
5779 + "cfg_get_svc_node: svc=%s protocol=%s svcname=%s forced %s by default service",
5780 + cfg_nodestring(param->svctype),
5781 + param->protocol ? param->protocol : "",
5782 + param->svcname ? param->svcname : "",
5783 + (svc_default == ER_TRUE ? "permit" : "deny"));
5786 - if (debug & DEBUG_CONFIG_FLAG)
5787 - report(LOG_DEBUG, "cfg_get_svc_node: recurse group = %s",
5789 + param->retval = (svc_default == ER_TRUE);
5790 + return (VSFR_FOUND);
5792 - for(svc = (NODE *) get_value(group, S_svc).pval; svc; svc = svc->next) {
5793 + default: /* shouldn't happen */
5795 + return (VSFR_CONTINUE);
5800 - if (svc->type != type)
5802 +int cfg_get_svc_node TAC_ARGS((const char *username, int svctype, const char *protocol, const char *svcname, int recurse, NODE **nodep));
5804 - if (type == N_svc_ppp && !STREQ(svc->value1, protocol)) {
5808 +cfg_get_svc_node(username, svctype, protocol, svcname, recurse, nodep)
5809 +const char *username;
5811 +const char *protocol;
5812 +const char *svcname;
5816 + struct cfg_get_svc_node_param param;
5817 + enum value_scan_func_result vsfr;
5819 - if (type == N_svc && !STREQ(svc->value1, svcname)) {
5822 + param.svctype = svctype;
5823 + param.protocol = protocol;
5824 + param.svcname = svcname;
5825 + param.node = NULL;
5828 if (debug & DEBUG_CONFIG_FLAG)
5830 - "cfg_get_svc_node: found %s proto=%s svcname=%s",
5831 - cfg_nodestring(type),
5832 + "cfg_get_svc_node: username=%s %s proto=%s svcname=%s rec=%d",
5834 + cfg_nodestring(svctype),
5835 protocol ? protocol : "",
5836 - svcname ? svcname : "");
5840 + svcname ? svcname : "",
5843 - /* still nothing. Check containing group and so on */
5844 + vsfr = value_scan(S_user, username, recurse,
5845 + (value_scan_func_t) cfg_get_svc_node_func, ¶m /* func_data */);
5847 + *nodep = param.node;
5849 - if (group->member)
5850 - group = (USER *) hash_lookup(grouptable, group->member);
5854 + if (vsfr == VSFR_FOUND)
5855 + return (param.retval);
5857 - if (debug & DEBUG_CONFIG_FLAG)
5858 - report(LOG_DEBUG, "cfg_get_svc_node: returns NULL");
5860 - /* no matching svc node for this user or her containing groups */
5862 + /* The service does not exist. Do the default */
5863 + return (cfg_no_user_permitted() ? 1 : 0);
5866 -/* Return a pointer to the node representing a set of command regexp
5867 +/* Return a pointer to the node representing a set of command tac_regexp
5868 matches for a user and command, handling recursion issues correctly */
5870 -cfg_get_cmd_node(name, cmdname, recurse)
5871 -char *name, *cmdname;
5874 +struct cfg_authorize_cmd_param {
5877 + enum eval_result result;
5880 +static enum value_scan_func_result cfg_authorize_cmd_func TAC_ARGS((ENTITY *entity, struct cfg_authorize_cmd_param *param));
5882 +static enum value_scan_func_result
5883 +cfg_authorize_cmd_func(entity, param /* func_data */)
5885 +struct cfg_authorize_cmd_param *param;
5887 - USER *user, *group;
5890 - if (debug & DEBUG_CONFIG_FLAG)
5891 - report(LOG_DEBUG, "cfg_get_cmd_node: name=%s cmdname=%s rec=%d",
5892 - name, cmdname, recurse);
5893 + for (svc = (NODE *) get_value(entity, S_svc).pval; svc; svc = svc->next) {
5896 - /* find the user/group entry */
5897 - user = (USER *) hash_lookup(usertable, name);
5898 + if (svc->type != N_svc_cmd)
5900 + if (!STREQ(svc->value, param->cmd))
5902 + if (expr_eval(svc->when) != ER_TRUE) /* expensive */
5906 if (debug & DEBUG_CONFIG_FLAG)
5907 - report(LOG_DEBUG, "cfg_get_cmd_node: no user named %s", name);
5909 + report(LOG_DEBUG, "cfg_authorize_cmd: found cmd %s %s node",
5910 + param->cmd, cfg_nodestring(svc->type));
5912 + /* we have 'cmd <openbra>' point, now traverse through its 'permit'/'deny' pairs: */
5914 + for (node = svc->value1; node; node = node->next) {
5917 + if (expr_eval(node->when) != ER_TRUE) /* expensive */
5920 +#ifdef WITH_INCLUDED_REGEX
5922 + match = tac_regexec((tac_regexp *) node->value1, param->args);
5924 +#else /* WITH_INCLUDED_REGEX */
5926 + match = !regexec((const regex_t *) node->value1, param->args /* string */,
5927 + 0 /* nmatch */, NULL /* pmatch */, 0 /* eflags */);
5929 +#endif /* WITH_INCLUDED_REGEX */
5931 + if (debug & DEBUG_AUTHOR_FLAG) {
5932 + report(LOG_INFO, "line %d compare %s %s '%s' & '%s' %smatch",
5933 + node->line, param->cmd,
5934 + node->type == N_permit ? "permit" : "deny",
5935 + (const char *) node->value, param->args, (match ? "" : "no "));
5937 - /* found the user entry. Find svc node */
5938 - svc = (NODE *) get_value(user, S_svc).pval;
5941 - if (svc->type == N_svc_cmd && STREQ(svc->value, cmdname)) {
5942 - if (debug & DEBUG_CONFIG_FLAG)
5943 - report(LOG_DEBUG, "cfg_get_cmd_node: found cmd %s %s node",
5944 - cmdname, cfg_nodestring(svc->type));
5949 + switch (node->type) {
5951 + if (debug & DEBUG_AUTHOR_FLAG) {
5952 + report(LOG_DEBUG, "%s %s permitted by line %d",
5953 + param->cmd, param->args, node->line);
5956 + param->result = ER_TRUE;
5957 + return (VSFR_FOUND);
5960 + if (debug & DEBUG_AUTHOR_FLAG) {
5961 + report(LOG_DEBUG, "%s %s denied by line %d",
5962 + param->cmd, param->args, node->line);
5964 + param->result = ER_FALSE;
5965 + return (VSFR_FOUND);
5968 + report(LOG_ERR, "INTERNAL: illegal configuration node: %s: %s %s",
5969 + session.peer, param->cmd, param->args);
5970 + param->result = ER_UNKNOWN; /* error */
5971 + return (VSFR_FOUND);
5974 + if (!algorithm_recursive) { /* compatibility mode: */
5975 + if (debug & DEBUG_AUTHOR_FLAG)
5976 + report(LOG_DEBUG, "cmd %s exists, but no args match, denied (as no 'authorization = recursive' found)",
5978 + param->result = ER_FALSE; /* emulate last "deny .*" */
5979 + return (VSFR_FOUND);
5983 - if (debug & DEBUG_CONFIG_FLAG)
5984 - report(LOG_DEBUG, "cfg_get_cmd_node: returns NULL");
5987 - /* no matching node. Check containing group */
5989 - group = (USER *) hash_lookup(grouptable, user->member);
5994 - if (debug & DEBUG_CONFIG_FLAG)
5995 - report(LOG_DEBUG, "cfg_get_cmd_node: recurse group = %s",
5997 + /* look at 'default service' settings */
5998 + param->result = entity_svc_default(entity);
5999 + switch (param->result) {
6001 - svc = get_value(group, S_svc).pval;
6003 + if (debug & DEBUG_AUTHOR_FLAG)
6004 + report(LOG_DEBUG, "cmd %s does not exist, permitted by default", param->cmd);
6005 + return (VSFR_FOUND);
6008 - if (svc->type == N_svc_cmd && STREQ(svc->value, cmdname)) {
6009 - if (debug & DEBUG_CONFIG_FLAG)
6010 - report(LOG_DEBUG, "cfg_get_cmd_node: found cmd %s node %s",
6011 - cmdname, cfg_nodestring(svc->type));
6018 - /* still nothing. Check containing group and so on */
6019 + if (debug & DEBUG_AUTHOR_FLAG)
6020 + report(LOG_DEBUG, "cmd %s does not exist, denied by default", param->cmd);
6021 + return (VSFR_FOUND);
6023 - if (group->member)
6024 - group = (USER *) hash_lookup(grouptable, group->member);
6027 + default: /* shouldn't happen */
6029 + return (VSFR_CONTINUE);
6034 +enum eval_result cfg_authorize_cmd TAC_ARGS((const char *username, const char *cmd, const char *args));
6037 +cfg_authorize_cmd(username, cmd, args)
6038 +const char *username;
6042 + struct cfg_authorize_cmd_param param;
6045 + param.args = args;
6046 + param.result = ER_UNKNOWN; /* error */
6048 if (debug & DEBUG_CONFIG_FLAG)
6049 - report(LOG_DEBUG, "cfg_get_cmd_node: returns NULL");
6050 + report(LOG_DEBUG, "cfg_authorize_cmd: name=%s cmdname=%s args=%s",
6051 + username, cmd, args);
6053 - /* no matching cmd node for this user or her containing groups */
6055 + value_scan(S_user, username, TAC_PLUS_RECURSE,
6056 + (value_scan_func_t) cfg_authorize_cmd_func, ¶m /* func_data */);
6058 + if (param.result != ER_UNKNOWN)
6059 + return (param.result);
6061 + /* The command does not exist. Do the default */
6062 + return (cfg_no_user_permitted() ? ER_TRUE : ER_FALSE);
6065 /* Return an array of character strings representing configured AV
6066 @@ -2039,6 +2711,8 @@ int recurse;
6067 * Lastly, indicate what default permission was configured by setting
6070 +char **cfg_get_svc_attrs TAC_ARGS((NODE *svcnode, int *denyp));
6073 cfg_get_svc_attrs(svcnode, denyp)
6075 @@ -2063,9 +2737,14 @@ int *denyp;
6078 for (node = svcnode->value; node; node = node->next) {
6079 - char *arg = tac_strdup(node->value);
6080 - char *p = index(arg, '=');
6084 + if (expr_eval(node->when) != ER_TRUE) /* expensive */
6085 + continue; /* ignore this node */
6087 + arg = tac_strdup(node->value);
6088 + p = index(arg, '=');
6089 if (p && node->type == N_optarg)
6092 @@ -2075,23 +2754,28 @@ int *denyp;
6097 -cfg_user_svc_default_is_permit(user)
6099 +static enum eval_result entity_svc_default TAC_ARGS((ENTITY *entity));
6101 +static enum eval_result
6102 +entity_svc_default(entity)
6105 - int permit = cfg_get_intvalue(user, TAC_IS_USER, S_svc_dflt,
6106 - TAC_PLUS_RECURSE);
6109 - default: /* default is deny */
6112 + switch (entity->svc_dflt) {
6117 + return (ER_FALSE);
6119 + case 0: /* not specified */
6120 + return (ER_UNKNOWN);
6122 + report(LOG_ERR, "INTERNAL: invalid entity svc_dflt (%d)", entity->svc_dflt);
6123 + return (ER_UNKNOWN);
6127 +int cfg_no_user_permitted TAC_ARGS((void));
6130 cfg_no_user_permitted()
6132 @@ -2101,12 +2785,16 @@ cfg_no_user_permitted()
6137 +const char *cfg_get_authen_default TAC_ARGS((void));
6140 cfg_get_authen_default()
6142 return (authen_default);
6145 +int cfg_get_authen_default_method TAC_ARGS((void));
6147 /* For describe authentication method(pam,file,db..etc) */
6149 cfg_get_authen_default_method()
6150 @@ -2115,92 +2803,123 @@ cfg_get_authen_default_method()
6154 -/* Return 1 if this user has any ppp services configured. Used for
6155 - authorizing ppp/lcp requests */
6157 -cfg_ppp_is_configured(username, recurse)
6160 +/* Host entity management:
6163 +const char *cfg_get_host_key TAC_ARGS((const char *host));
6165 +/* For getting host key */
6167 +cfg_get_host_key(host)
6170 - USER *user, *group;
6172 + return (cfg_get_pvalue(S_host, host, S_key, algorithm_recursive /* recurse */));
6175 - if (debug & DEBUG_CONFIG_FLAG)
6176 - report(LOG_DEBUG, "cfg_ppp_is_configured: username=%s rec=%d",
6177 - username, recurse);
6178 +static ENTITY *force_belong_entity TAC_ARGS((int type, const char *name));
6181 +force_belong_entity(type, name)
6185 + ENTITY *entity = entity_lookup(type, name);
6187 - /* find the user/group entry */
6188 - user = (USER *) hash_lookup(usertable, username);
6190 + eval_force_belong_entity(entity);
6193 - if (debug & DEBUG_CONFIG_FLAG)
6194 - report(LOG_DEBUG, "cfg_ppp_is_configured: no user named %s",
6201 - /* found the user entry. Find svc node */
6202 - for(svc = (NODE *) get_value(user, S_svc).pval; svc; svc = svc->next) {
6203 +/* assumed existing initialized "session.peer*" */
6205 - if (svc->type != N_svc_ppp)
6207 +static ENTITY *request_peer_addr;
6208 +static ENTITY *request_peer;
6209 +static ENTITY *request_DEFAULT_group;
6211 - if (debug & DEBUG_CONFIG_FLAG)
6212 - report(LOG_DEBUG, "cfg_ppp_is_configured: found svc ppp %s node",
6214 +static void enlist_request_peer TAC_ARGS((const char *hostname, ENTITY **entityp));
6219 +enlist_request_peer(hostname, entityp)
6220 +const char *hostname;
6228 - if (debug & DEBUG_CONFIG_FLAG)
6229 - report(LOG_DEBUG, "cfg_ppp_is_configured: returns 0");
6232 + *entityp = force_belong_entity(S_host, hostname);
6233 + if (*entityp && request_DEFAULT_group)
6234 + virtual_enlist_entity_direct(request_DEFAULT_group /* parent */, *entityp /* child */);
6237 - /* no matching node. Check containing group */
6239 - group = (USER *) hash_lookup(grouptable, user->member);
6242 +/* Try to build the following scenery:
6244 + * host <session.peer_addr> [=ER_TRUE]
6246 + * +-- group <DEFAULT_GROUPNAME>
6248 + * host <session.peer > [=ER_TRUE]
6250 + * +-- group <DEFAULT_GROUPNAME>
6254 - if (debug & DEBUG_CONFIG_FLAG)
6255 - report(LOG_DEBUG, "cfg_ppp_is_configured: recurse group = %s",
6257 +void cfg_request_scan_begin TAC_ARGS((void));
6259 - for(svc = (NODE *) get_value(group, S_svc).pval; svc; svc = svc->next) {
6261 +cfg_request_scan_begin()
6263 + request_scan_begin();
6265 - if (svc->type != N_svc_ppp)
6267 + request_DEFAULT_group = entity_lookup(S_group, DEFAULT_GROUPNAME);
6269 - if (debug & DEBUG_CONFIG_FLAG)
6270 - report(LOG_DEBUG, "cfg_ppp_is_configured: found svc ppp %s node",
6272 + if (session.peer_addr != session.peer)
6273 + enlist_request_peer(session.peer_addr, &request_peer_addr);
6274 + enlist_request_peer(session.peer, &request_peer);
6279 +/* Try to build the following scenery:
6281 + * ( user <identity->username> | user <DEFAULT_USERNAME> ) [=ER_TRUE]
6283 + * +-- host <session.peer_addr> [=ER_TRUE]
6285 + * | +- group <DEFAULT_GROUPNAME>
6287 + * +-- host <session.peer > [=ER_TRUE]
6289 + * | +-- group <DEFAULT_GROUPNAME>
6291 + * +-- group <DEFAULT_GROUPNAME>
6294 - /* still nothing. Check containing group and so on */
6295 +void cfg_request_identity TAC_ARGS((const struct identity *identity));
6297 - if (group->member)
6298 - group = (USER *) hash_lookup(grouptable, group->member);
6303 +cfg_request_identity(identity)
6304 +const struct identity *identity;
6306 + ENTITY *user_entity,*request_DEFAULT_group;
6308 if (debug & DEBUG_CONFIG_FLAG)
6309 - report(LOG_DEBUG, "cfg_ppp_is_configured: returns 0");
6310 + report(LOG_DEBUG, "cfg_request_identity: username=%s, NAS_name=%s, NAS_port=%s, NAC_address=%s, priv_lvl=%d",
6311 + identity->username, identity->NAS_name, identity->NAS_port, identity->NAC_address, identity->priv_lvl);
6313 - /* no PPP svc nodes for this user or her containing groups */
6316 + user_entity = force_belong_entity(S_user, identity->username);
6317 + request_DEFAULT_group = entity_lookup(S_group, DEFAULT_GROUPNAME);
6319 -/* For getting host key */
6321 -cfg_get_host_key(host)
6324 - return (cfg_get_phvalue(host, S_key));
6327 + user_entity = force_belong_entity(S_user, DEFAULT_USERNAME);
6329 + request_scan_user_known = 1;
6334 + if (request_peer_addr)
6335 + virtual_enlist_entity_direct(request_peer_addr /* parent */, user_entity /* child */);
6336 + if (request_peer )
6337 + virtual_enlist_entity_direct(request_peer /* parent */, user_entity /* child */);
6338 + if (request_DEFAULT_group)
6339 + virtual_enlist_entity_direct(request_DEFAULT_group /* parent */, user_entity /* child */);
6341 diff --git a/cfgfile.h b/cfgfile.h
6342 new file mode 100644
6343 index 0000000..3669996
6348 +#define CFGFILE_H 1
6350 +#include "tac_plus.h"
6353 +#include "cfgeval.h"
6359 +#define DEFAULT_USERNAME "DEFAULT"
6360 +#define DEFAULT_GROUPNAME "DEFAULT"
6363 +#define TAC_PLUS_RECURSE 1
6364 +#define TAC_PLUS_NORECURSE 0
6369 +#define N_optarg 51
6370 +#define N_svc_exec 52
6371 +#define N_svc_slip 53
6372 +#define N_svc_ppp 54
6373 +#define N_svc_arap 55
6374 +#define N_svc_cmd 56
6375 +#define N_permit 57
6379 +typedef struct node NODE;
6381 +/* A parse tree node */
6383 + int type; /* node type (arg, svc, proto) */
6384 + NODE *next; /* pointer to next node in chain */
6385 + void *value; /* node value */
6386 + void *value1; /* node value */
6387 + int dflt; /* default value for node */
6388 + int line; /* line number declared on */
6389 + struct expr *when; /* conditions needed to respect this NODE */
6397 +typedef union v VALUE;
6399 +/* A user, host or group definition
6401 + The first 2 fields (name and hash) are used by the hash table
6402 + routines to hash this structure into a table. Move them at your
6407 + char *name; /* username/groupname/hostname */
6408 + void *hash; /* hash table next pointer */
6409 + int line; /* line number defined on */
6410 + int type; /* set to S_user, S_host or S_group */
6412 + char *full_name; /* users full name */
6413 + char *login; /* Login password */
6414 + int nopasswd; /* user requires no password */
6415 + char *global; /* password to use if none set */
6416 + char *expires; /* expiration date */
6417 + char *arap; /* our arap secret */
6418 + char *pap; /* our pap secret */
6419 + char *opap; /* our outbound pap secret */
6420 + char *chap; /* our chap secret */
6422 + char *mschap; /* our mschap secret */
6423 +#endif /* MSCHAP */
6424 + char *msg; /* a message for this user */
6425 + char *before_author; /* command to run before authorization */
6426 + char *after_author; /* command to run after authorization */
6427 + char *key; /* host spesific key (N/A for S_user) */
6428 + int svc_dflt; /* default authorization behaviour for svc or
6430 + /* =S_permit, S_deny or S_default */
6431 + NODE *svcs; /* pointer to svc nodes */
6433 + int maxsess; /* Max sessions/user */
6434 +#endif /* MAXSESS */
6435 + char *time; /* Timestamp */
6437 + struct tac_list to_parent_membership_list; /* ordered list of memberships to groups owning us: */
6438 + struct tac_list to_child_membership_list; /* ordered list of memberships to entities in this group: */
6439 + unsigned to_child_membership_num; /* # of 'to_child_membership_list' items */
6442 + unsigned seq; /* corresponds to global request_scan_seq */
6443 + enum eval_result belongs; /* whether this ENTITY 'belongs' */
6444 + } request_scan; /* cfg_request() scanning */
6447 + unsigned seq; /* corresponds to global value_scan_seq */
6449 + struct membership *from; /* from which we got to this one or NULL */
6450 + } value_scan; /* cfg_get_value() scanning, many per request_scan */
6453 + unsigned seq; /* corresponds to global eval_scan_seq */
6454 + struct tac_list notify_expr_list; /* contains expr.u.waiting_expr_node */
6455 + /* may be from any of: eval_{want,solved,destroy}_entity_list: */
6456 + struct tac_list_node pending_entity_node; /* we are interested in this entity */
6457 + /* child memberships which are not yet check_eval-ed are NOT present here,
6458 + * although when check_eval-entity finishes, all will be added here.
6459 + * List refilling driven by check_eval_scan_entity(),
6460 + * although each unsolved_child_node is added in check_eval_scan_membership().
6462 + unsigned unsolved_to_child_membership_num; /* when 0, we know we are ER_FALSE */
6463 + struct membership *unsolved_to_child_membership_first;
6464 + } eval_scan; /* expr_eval() scanning, many per value_scan */
6466 +#define PENDING_ENTITY_NODE_TO_ENTITY(pending_entity_node_) \
6467 + (&TAC_MEMBER_STRUCT(ENTITY, (pending_entity_node_), eval_scan.pending_entity_node))
6472 +extern const char *cfg_nodestring TAC_ARGS((int type));
6473 +extern void cfg_clean_config TAC_ARGS((void));
6474 +extern int cfg_get_intvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
6475 +extern const char *cfg_get_pvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
6476 +extern int cfg_read_config TAC_ARGS((const char *cfile));
6477 +extern int cfg_user_exists TAC_ARGS((const char *username));
6478 +extern const char *cfg_get_expires TAC_ARGS((const char *username, int recurse));
6479 +extern const char *cfg_get_timestamp TAC_ARGS((const char *username, int recurse));
6480 +extern const char *cfg_get_login_secret TAC_ARGS((const char *user, int recurse));
6481 +extern int cfg_get_user_nopasswd TAC_ARGS((const char *user, int recurse));
6482 +extern const char *cfg_get_arap_secret TAC_ARGS((const char *user, int recurse));
6483 +extern const char *cfg_get_chap_secret TAC_ARGS((const char *user, int recurse));
6485 +extern const char *cfg_get_mschap_secret TAC_ARGS((const char *user, int recurse));
6486 +#endif /* MSCHAP */
6487 +extern const char *cfg_get_pap_secret TAC_ARGS((const char *user, int recurse));
6488 +extern const char *cfg_get_opap_secret TAC_ARGS((const char *user, int recurse));
6489 +extern const char *cfg_get_global_secret TAC_ARGS((const char *user, int recurse));
6491 +extern const char *cfg_get_pam_service TAC_ARGS((const char *user, int recurse));
6493 +extern int cfg_get_svc_node TAC_ARGS((const char *username, int svctype, const char *protocol, const char *svcname, int recurse, NODE **nodep));
6494 +extern char **cfg_get_svc_attrs TAC_ARGS((NODE *svcnode, int *denyp));
6495 +extern int cfg_no_user_permitted TAC_ARGS((void));
6496 +extern const char *cfg_get_authen_default TAC_ARGS((void));
6497 +extern int cfg_get_authen_default_method TAC_ARGS((void));
6498 +extern const char *cfg_get_host_key TAC_ARGS((const char *host));
6499 +extern void cfg_request_scan_begin TAC_ARGS((void));
6500 +extern void cfg_request_identity TAC_ARGS((const struct identity *identity));
6501 +extern enum eval_result cfg_authorize_cmd TAC_ARGS((const char *username, const char *cmd, const char *args));
6503 +/* for use by cfgeval.c: */
6504 +extern ENTITY *new_entity TAC_ARGS((int type, char *name, int line));
6505 +extern const char *entity_type_to_string TAC_ARGS((int entity_type));
6506 +extern void scan_invalidate_entities TAC_ARGS((enum invalidate_scan what));
6507 +extern ENTITY *entity_lookup TAC_ARGS((int type, const char *name));
6510 +#endif /* CFGFILE_H */
6511 diff --git a/choose_authen.c b/choose_authen.c
6512 index 9329b73..d6b3062 100644
6513 --- a/choose_authen.c
6514 +++ b/choose_authen.c
6516 FITNESS FOR A PARTICULAR PURPOSE.
6520 #include "tac_plus.h"
6522 +#include "choose_authen.h"
6524 +#include "enable.h"
6525 +#include "report.h"
6526 +#include "cfgfile.h"
6527 +#include "default_fn.h"
6528 +#include "default_v0_fn.h"
6529 +#include "sendauth.h"
6530 +#include "sendpass.h"
6531 +#include "packet.h"
6533 +#include "do_author.h" /* for "struct identity" */
6535 -static int choose_login();
6536 -static int choose_sendpass();
6537 -static int choose_sendauth();
6539 +#include "skey_fn.h"
6544 +static int choose_sendpass TAC_ARGS((struct authen_data *data, struct authen_type *type));
6545 +static int choose_sendauth TAC_ARGS((struct authen_data *data, struct authen_type *type));
6546 +static int choose_login TAC_ARGS((struct authen_data *data, struct authen_type *type));
6553 return(session.version & ~TAC_PLUS_MAJOR_VER_MASK);
6555 +#endif /* unused */
6558 * Choose an authentication function. Return CHOOSE_OK if chosen,
6559 * CHOOSE_GETUSER if we need a username, CHOOSE_FAILED on failure
6562 +int choose_authen TAC_ARGS((struct authen_data *data, struct authen_type *type));
6565 choose_authen(data, type)
6566 struct authen_data *data;
6567 @@ -84,14 +107,16 @@ struct authen_type *type;
6568 return(CHOOSE_FAILED);
6571 +static int choose_login TAC_ARGS((struct authen_data *data, struct authen_type *type));
6573 /* Choose an authentication function for action == LOGIN, service != enable */
6575 choose_login(data, type)
6576 struct authen_data *data;
6577 struct authen_type *type;
6579 - char *name = data->NAS_id->username;
6581 + const char *name = data->NAS_id->username;
6582 + const char *cfg_passwd;
6584 switch(type->authen_type) {
6585 case TAC_PLUS_AUTHEN_TYPE_ASCII:
6586 @@ -193,6 +218,8 @@ struct authen_type *type;
6587 return(CHOOSE_FAILED);
6590 +static int choose_sendauth TAC_ARGS((struct authen_data *data, struct authen_type *type));
6593 choose_sendauth(data, type)
6594 struct authen_data *data;
6595 @@ -247,6 +274,8 @@ struct authen_type *type;
6596 return(CHOOSE_FAILED);
6599 +static int choose_sendpass TAC_ARGS((struct authen_data *data, struct authen_type *type));
6601 /* Compatibility routine for (obsolete) minor version == 0 */
6603 choose_sendpass(data, type)
6604 @@ -291,4 +320,3 @@ struct authen_type *type;
6606 return(CHOOSE_FAILED);
6609 diff --git a/choose_authen.h b/choose_authen.h
6610 new file mode 100644
6611 index 0000000..1276494
6613 +++ b/choose_authen.h
6615 +#ifndef CHOOSE_AUTHEN_H
6616 +#define CHOOSE_AUTHEN_H 1
6618 +#include "tac_plus.h"
6620 +#include <sys/types.h> /* for u_* */
6624 + * This structure describes an authentication method.
6625 + * authen_name contains the name of the authentication method.
6626 + * authen_func is a pointer to the authentication function.
6627 + * authen_method numeric value of authentication method
6630 +#define AUTHEN_NAME_SIZE 128
6632 +struct authen_data;
6634 +struct authen_type {
6635 + char authen_name[AUTHEN_NAME_SIZE];
6636 + int (*authen_func) TAC_ARGS((struct authen_data *data));
6641 + * The authen_data structure is the data structure for passing
6642 + * information to and from the authentication function
6643 + * (authen_type.authen_func).
6646 +struct authen_data {
6647 + struct identity *NAS_id; /* user identity */
6648 + char *server_msg; /* null-terminated output msg */
6650 + int server_dlen; /* output data length */
6651 + unsigned char *server_data; /* output data */
6653 + char *client_msg; /* null-terminated input msg a user typed */
6655 + int client_dlen; /* input data length */
6656 + char *client_data; /* input data */
6658 + void *method_data; /* opaque private method data */
6659 + int action; /* what's to be done */
6660 + int service; /* calling service */
6661 + int status; /* Authen status */
6662 + int type; /* Authen type */
6663 + u_char flags; /* input & output flags fields */
6666 +/* return values for choose_authen(); */
6668 +#define CHOOSE_FAILED -1 /* failed to choose an authentication function */
6669 +#define CHOOSE_OK 0 /* successfully chose an authentication function */
6670 +#define CHOOSE_GETUSER 1 /* need a username before choosing */
6671 +#define CHOOSE_BADTYPE 2 /* Invalid preferred authen function specified */
6674 +extern int choose_authen TAC_ARGS((struct authen_data *data, struct authen_type *type));
6677 +#endif /* CHOOSE_AUTHEN_H */
6678 diff --git a/configure.in b/configure.in
6679 index 6b3eb13..0b8fd72 100644
6683 dnl This file writen by Devrim SERAL for tac_plus daemon
6686 +dnl Check for Host information
6687 +dnl AC_CANONICAL_HOST()
6688 +AC_CANONICAL_SYSTEM()
6689 +AM_INIT_AUTOMAKE(tac_plus, F4.0.3.alpha.8.gts4)
6691 dnl Checks for programs.
6695 -dnl Check for Host information
6696 -dnl AC_CANONICAL_HOST()
6697 -AC_CANONICAL_SYSTEM()
6701 - OS="-DLINUX -DGLIBC"
6707 + AC_DEFINE(SOLARIS)
6711 + AC_DEFINE(FREEBSD)
6720 + AC_MSG_WARN([See /usr/lpp/bos/bsdport on your system for details of how to define bsdcc])
6731 +AM_CONFIG_HEADER(config.h)
6734 +if test "x$USE_MAINTAINER_MODE" = "xyes"; then
6735 + AC_DEFINE(MAINTAINER_MODE)
6738 +if test "x$USE_MAINTAINER_MODE" = "xyes" -a "x$GCC" = "xyes"; then
6739 + CFLAGS="$CFLAGS -ggdb3 -Wall -Wstrict-prototypes -pedantic -Wsign-compare"
6742 +# Set these options as otherwise some autoconf tests give different results:
6743 +final_CFLAGS="$CFLAGS"
6744 +CFLAGS="$CFLAGS -D_XOPEN_SOURCE=1 -D_XOPEN_SOURCE_EXTENDED=1 -D_BSD_SOURCE=1 -D_OSF_SOURCE=1 -D__EXTENSIONS__=1"
6749 +AC_SUBST(conf_LDFLAGS)
6751 +AC_SUBST(conf_LDADD)
6754 dnl Checks for libraries.
6755 dnl Replace `main' with a function in -lnsl:
6756 -AC_CHECK_LIB(nsl, main)
6757 +AC_CHECK_LIB(nsl, main, [ conf_LDADD="-lnsl $conf_LDADD" ] )
6758 dnl Replace `main' with a function in -log:
6759 -AC_CHECK_LIB(og, main)
6760 -dnl Replace `main' with a function in -lldap:
6761 -AC_CHECK_LIB(ldap, main)
6762 -dnl Replace `main' with a function in -llber:
6763 -AC_CHECK_LIB(lber, main)
6764 +AC_CHECK_LIB(og, main, [ conf_LDADD="-log $conf_LDADD" ] )
6765 dnl Replace `main' with a function in -lsocket:
6766 -AC_CHECK_LIB(socket, main)
6767 +AC_CHECK_LIB(socket, main, [ conf_LDADD="-lsocket $conf_LDADD" ] )
6768 dnl Check for Crypt function
6769 +dnl Never use CONF_LDADD here as it is used also for "generate_passwd"
6770 AC_CHECK_LIB(crypt, crypt)
6771 AC_CHECK_LIB(c,printf)
6773 +dnl Checks for header files.
6775 +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)
6776 +AC_CHECK_HEADERS(shadow.h,[
6777 + if test -f /etc/shadow ; then
6778 + AC_DEFINE(SHADOW_PASSWORDS)
6781 +dnl Checks for typedefs, structures, and compiler characteristics.
6785 +dnl Checks for library functions.
6786 +AC_PROG_GCC_TRADITIONAL
6792 +AC_CHECK_FUNCS(select socket strcspn strdup strtol siginterrupt)
6793 +AC_CHECK_SIZEOF(unsigned short,2)
6794 +AC_CHECK_SIZEOF(unsigned int,4)
6795 +AC_CHECK_SIZEOF(unsigned long,4)
6798 -AC_CONFIG_HEADER(config.h)
6801 AC_MSG_CHECKING(for PAM support:)
6802 @@ -55,9 +103,10 @@ echo
6804 [ --with-pam With PAM Support ],,)
6805 if test "x$with_pam" = "xyes";then
6806 - AC_CHECK_LIB(dl, dlopen)
6807 - AC_CHECK_LIB(pam, pam_start)
6808 - DEFINES="-DUSE_PAM $DEFINES";
6809 + AC_CHECK_LIB(dl, dlopen, [ conf_LDADD="-ldl $conf_LDADD" ] )
6810 + AC_CHECK_LIB(pam, pam_start, [ conf_LDADD="-lpam $conf_LDADD" ] )
6811 + AC_DEFINE(USE_PAM)
6812 + COND_USE="$COND_USE "'$(cond_USE_PAM)'
6813 AC_MSG_RESULT(Pam support... yes)
6815 AC_MSG_RESULT(Pam support... no)
6816 @@ -70,10 +119,15 @@ AC_ARG_WITH(ldap,
6817 [ --with-ldap With LDAP Support ],,)
6819 if test "x$with_ldap" = "xyes";then
6820 - AC_CHECK_LIB(ldap, ldap_simple_bind_s)
6821 - AC_CHECK_LIB(ldap, ldap_init)
6823 - DEFINES="-DUSE_LDAP $DEFINES"
6824 + dnl Replace `main' with a function in -llber:
6825 + AC_CHECK_LIB(lber, main, [ conf_LDADD="-llber $conf_LDADD"; liblber="-llber" ], [ liblber="" ] )
6826 + dnl Replace `main' with a function in -lldap:
6827 + AC_CHECK_LIB(ldap, ldap_simple_bind_s, [ conf_LDADD="-lldap $conf_LDADD" ],
6829 + AC_CHECK_LIB(ldap, ldap_init, [ conf_LDADD="-lldap $conf_LDADD" ],, $liblber)
6831 + AC_DEFINE(USE_LDAP)
6832 + COND_USE="$COND_USE "'$(cond_USE_LDAP)'
6833 AC_MSG_RESULT(LDAP support... yes)
6835 AC_MSG_RESULT(LDAP support... no)
6836 @@ -85,7 +139,10 @@ echo
6838 [ --with-db For DB Support ],,)
6839 if test "x$with_db" = "xyes";then
6840 - DB="$DB -DDB -DDB_NULL"
6842 + AC_DEFINE(DB_NULL)
6843 + COND_USE="$COND_USE "'$(cond_DB)'
6844 + COND_USE="$COND_USE "'$(cond_DB_NULL)'
6845 AC_MSG_RESULT(DB support... yes)
6847 AC_MSG_RESULT(DB support... no)
6848 @@ -108,14 +165,15 @@ AC_ARG_WITH(mysql-prefix,
6850 if test "x$with_mysql" = "xyes";then
6852 - LDFLAGS="-L$MYSQL_PREFIX/lib/mysql $LDFLAGS"
6853 - LDFLAGS="-I$MYSQL_PREFIX/include/mysql $LDFLAGS"
6854 + conf_LDFLAGS="-L$MYSQL_PREFIX/lib/mysql $conf_LDFLAGS"
6855 + CPPFLAGS="-I$MYSQL_PREFIX/include/mysql $CPPFLAGS"
6856 AC_CHECK_LIB(mysqlclient, mysql_init,
6857 - LIBS="-lmysqlclient -lm $LIBS",
6858 + conf_LDADD="-lmysqlclient -lm $conf_LDADD",
6859 AC_MSG_ERROR(*** couldn't find libmysqlclient),
6862 - DB="$DB -DDB_MYSQL";
6863 + AC_DEFINE(DB_MYSQL)
6864 + COND_USE="$COND_USE "'$(cond_DB_MYSQL)'
6865 AC_MSG_RESULT(Mysql support... yes)
6867 AC_MSG_RESULT(Mysql support... no)
6868 @@ -140,13 +198,14 @@ AC_ARG_WITH(pgsql-prefix,
6870 if test "x$with_pgsql" = "xyes";then
6872 - LDFLAGS="-L$PGSQL_PREFIX/lib/pgsql $LDFLAGS"
6873 - LDFLAGS="-I$PGSQL_PREFIX/include/pgsql $LDFLAGS"
6874 + conf_LDFLAGS="-L$PGSQL_PREFIX/lib/pgsql $conf_LDFLAGS"
6875 + CPPFLAGS="-I$PGSQL_PREFIX/include/pgsql $CPPFLAGS"
6876 AC_CHECK_LIB(pq,PQconnectdb ,
6877 - LIBS="-lpq $LIBS",
6878 + conf_LDADD="-lpq $conf_LDADD",
6879 AC_MSG_ERROR(*** couldn't find libpq))
6881 - DB="$DB -DDB_PGSQL";
6882 + AC_DEFINE(DB_PGSQL)
6883 + COND_USE="$COND_USE "'$(cond_DB_PGSQL)'
6884 AC_MSG_RESULT(Pgsql support... yes)
6886 AC_MSG_RESULT(Pgsql support... no)
6887 @@ -164,7 +223,8 @@ AC_ARG_WITH(tacgid,
6889 if (test "x$with_tacuid" != "x" && test "x$with_tacgid" != "x" && test "x$with_tacuid" != "xyes" && test "x$with_tacgid" != "xyes");then
6891 - DEFINES="-DTACPLUS_USERID=$with_tacuid -DTACPLUS_GROUPID=$with_tacgid $DEFINES";
6892 + AC_DEFINE_UNQUOTED(TACPLUS_USERID, $with_tacuid)
6893 + AC_DEFINE_UNQUOTED(TACPLUS_GROUPID, $with_tacgid)
6894 AC_MSG_RESULT(tacacs+ work with given user and group id)
6897 @@ -173,8 +233,9 @@ AC_ARG_ENABLE(maxsess,
6898 [ --enable-maxsess Enable maxsess feature ],
6900 if test "$enableval" = "yes";then
6901 - DEFINES="-DMAXSESS $DEFINES";
6902 + AC_DEFINE(MAXSESS)
6904 + COND_USE="$COND_USE "'$(cond_MAXSESS)'
6908 @@ -184,16 +245,18 @@ fi
6911 dnl Enable tacacs.pid file directory
6913 AC_ARG_WITH(tacplus_pid,
6914 [ --with-tacplus_pid=PREFIX Tac_plus pid file location [default=/var/run] ],
6915 - PIDFILE="-DTACPLUS_PIDFILE=\\\"$withval/tac_plus.pid\\\"",
6916 - PIDFILE="-DTACPLUS_PIDFILE=\\\"/var/run/tac_plus.pid\\\""
6917 + [ pidfile="$withval" ],
6920 +if test "x$pidfile" '!=' "x"; then
6921 + AC_DEFINE_UNQUOTED(TACPLUS_PIDFILE, "$pidfile/tac_plus.pid")
6924 dnl For libwrap check
6925 -AC_MSG_CHECKING(whether to enable the libwrap feture)
6927 +AC_MSG_CHECKING(whether to enable the libwrap feature)
6929 AC_ARG_WITH(libwrap,
6930 [ --with-libwrap[=PATH] Compile in libwrap (tcp_wrappers) support.],
6931 [ case "$withval" in
6932 @@ -203,48 +266,221 @@ AC_ARG_WITH(libwrap,
6935 AC_CHECK_LIB(wrap, request_init, [
6936 - LIBS="-lwrap $LIBS"
6937 - DEFINES="-DTCPWRAPPER $DEFINES"])
6938 + conf_LDADD="-lwrap $conf_LDADD"
6944 if test -d "$withval"; then
6945 LDFLAGS="-L$withval $LDFLAGS"
6946 - DEFINES="-DTCPWRAPPER $DEFINES"
6948 AC_TRY_LINK([ int allow_severity; int deny_severity; ],
6949 [ hosts_access(); ],
6951 [ AC_MSG_ERROR(Could not find the $withval library. You must first install tcp_wrappers.) ])
6958 + AC_DEFINE(TCPWRAPPER)
6959 + COND_USE="$COND_USE "'$(cond_TCPWRAPPER)'
6962 -dnl insert defines to Makefile
6968 +AC_MSG_CHECKING(whether to use SKEY security feature)
6971 +[ --with-skey[=LIBPATH] Compile with SKEY support (also use -I in CPPFLAGS var).],
6972 +[ case "$withval" in
6977 + AC_MSG_RESULT(yes)
6981 + AC_MSG_RESULT(yes)
6982 + if test '!' -f "$withval";then
6983 + AC_MSG_ERROR([Cannot find $withval library file, you may wish to use LIBS variable instead.])
6985 + conf_LDADD="$withval $conf_LDADD"
6993 + COND_USE="$COND_USE "'$(cond_SKEY)'
6996 -dnl Checks for header files.
6998 -AC_CHECK_HEADERS(fcntl.h malloc.h strings.h sys/file.h sys/ioctl.h sys/time.h syslog.h unistd.h)
6999 -AC_CHECK_HEADERS(shadow.h,[
7000 - if test -f /etc/shadow ; then
7001 - AC_DEFINE(SHADOW_PASSWORDS)
7002 +dnl For MSCHAP and also MSCHAP_DES
7003 +AC_MSG_CHECKING(whether to compile with Microsoft CHAP)
7005 +AC_ARG_WITH(mschap,
7006 +[ --with-mschap[=des] Compile with Microsoft CHAP (optionally including MSCHAP_DES).],
7007 +[ case "$withval" in
7012 + AC_MSG_RESULT([yes, without DES])
7016 + AC_MSG_RESULT([yes, including DES])
7017 + AC_DEFINE(MSCHAP_DES)
7021 + AC_MSG_ERROR(Unknown --with-mschap argument $withval, use: no, yes or des)
7028 + COND_USE="$COND_USE "'$(cond_MSCHAP)'
7031 +dnl For SunOS encryption compatibility
7032 +dnl Never use CONF_LDADD here as it is used also for "generate_passwd"
7033 +AC_MSG_CHECKING(whether to use SunOS encryption compatibility)
7035 +AC_ARG_WITH(descrypt,
7036 +[ --with-descrypt Be password encryption compatible with SunOS.],
7037 +[ case "$withval" in
7042 + AC_MSG_RESULT(yes)
7043 + LIBS="-ldescrypt $LIBS"
7046 + AC_MSG_RESULT(yes - $withval)
7047 + LIBS="$withval $LIBS"
7053 +AC_ARG_WITH(efence,
7054 +[ --with-efence compile with efence support (for debugging)],,[
7055 + if test "x$USE_MAINTAINER_MODE" = "xyes"; then
7061 -dnl Checks for typedefs, structures, and compiler characteristics.
7065 +if test "$with_efence" != no; then
7066 + AC_CHECK_LIB(efence,malloc,,[
7067 + if test "$with_efence" = yes; then
7068 + AC_MSG_ERROR(Unable to find efence library.)
7073 -dnl Checks for library functions.
7074 -AC_PROG_GCC_TRADITIONAL
7079 -AC_CHECK_FUNCS(regcomp select socket strcspn strdup strtol)
7080 +dnl Check for type in sys/socket.h
7081 +AC_MSG_CHECKING([for parameter type of 3rd accept() arg])
7082 +AC_CACHE_VAL(tac_plus_cv_accept_type, [
7084 + for type in socklen_t size_t int; do
7086 +#include <sys/types.h>
7087 +#include <sys/socket.h>
7089 +#include <stdlib.h>
7090 +#include <stddef.h>
7094 + int accept(int s, struct sockaddr *addr, ]$type[ *addrlen)
7096 + int discarded_main() {
7098 + [check_ok=true;break],continue)
7102 + tac_plus_cv_accept_type=$type
7104 + tac_plus_cv_accept_type=no
7107 +if test "x$tac_plus_cv_accept_type" = "xno"
7109 + AC_DEFINE(socklen_t,int)
7110 + AC_MSG_RESULT([failed to detect, will try int])
7112 + AC_MSG_RESULT($tac_plus_cv_accept_type)
7113 + if test "x$tac_plus_cv_accept_type" != "xsocklen_t"
7115 + AC_DEFINE_UNQUOTED(socklen_t,$tac_plus_cv_accept_type)
7119 +dnl Check for system regex (stolen from "mutt" package)
7120 +AC_ARG_WITH(included-regex, [ --with-included-regex Use the included regex library ],
7121 + [tac_plus_cv_included_regex=yes],
7122 + [AC_CHECK_FUNCS(regcomp, tac_plus_cv_included_regex=no, tac_plus_cv_included_regex=yes)])
7124 +if test $tac_plus_cv_included_regex = no ; then
7125 +AC_CACHE_CHECK([whether your system's regexp library is completely broken],
7126 + [tac_plus_cv_included_regex_broken],
7128 +#ifdef HAVE_UNISTD_H
7129 +#include <unistd.h>
7131 +#ifdef HAVE_REGEX_H
7134 +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); }],
7135 + tac_plus_cv_included_regex_broken=no, tac_plus_cv_included_regex_broken=yes, tac_plus_cv_included_regex_broken=yes))
7136 + if test $tac_plus_cv_included_regex_broken = yes ; then
7137 + echo "Using the included regex instead." >&AC_FD_MSG
7138 + tac_plus_cv_included_regex=yes
7141 +if test $tac_plus_cv_included_regex = yes; then
7142 + AC_DEFINE(WITH_INCLUDED_REGEX)
7143 + COND_USE="$COND_USE "'$(cond_WITH_INCLUDED_REGEX)'
7146 +dnl Check for "struct passwd.pw_{age,comment}"
7147 +dnl Stolen from Julianne Frances Haugh's login replacement.
7148 +AC_CACHE_CHECK(for pw_age in struct passwd,
7149 +tac_plus_cv_struct_passwd_pw_age, AC_TRY_COMPILE([#include <pwd.h>],
7150 +[ struct passwd pw; pw.pw_age = "" ],
7151 +tac_plus_cv_struct_passwd_pw_age=yes, tac_plus_cv_struct_passwd_pw_age=no))
7153 +if test "$tac_plus_cv_struct_passwd_pw_age" = "yes"; then
7154 + AC_DEFINE(HAVE_PASSWD_PW_AGE)
7156 +AC_CACHE_CHECK(for pw_comment in struct passwd,
7157 +tac_plus_cv_struct_passwd_pw_comment, AC_TRY_COMPILE([#include <pwd.h>],
7158 +[ struct passwd pw; pw.pw_comment = "" ],
7159 +tac_plus_cv_struct_passwd_pw_comment=yes, tac_plus_cv_struct_passwd_pw_comment=no))
7161 +if test "$tac_plus_cv_struct_passwd_pw_comment" = "yes"; then
7162 + AC_DEFINE(HAVE_PASSWD_PW_COMMENT)
7164 +AC_CACHE_CHECK(for ut_host in struct utmp,
7165 +tac_plus_cv_struct_utmp_ut_host, AC_TRY_COMPILE([#include <utmp.h>],
7166 +[ struct utmp ut; ut.ut_host = "" ],
7167 +tac_plus_cv_struct_utmp_ut_host=yes, tac_plus_cv_struct_utmp_ut_host=no))
7169 +if test "$tac_plus_cv_struct_utmp_ut_host" = "yes"; then
7170 + AC_DEFINE(HAVE_UTMP_UT_HOST)
7173 +CFLAGS="$final_CFLAGS"
7175 -AC_OUTPUT(Makefile,echo timestamp > stamp-h)
7180 diff --git a/convert.pl b/convert.pl
7181 index eb0b5c2..83cbdcc 100755
7184 @@ -141,6 +141,3 @@ exit 0 if ($acl_valid);
7185 foreach $group (keys %groups) {
7186 print "group = $group { }\n";
7191 diff --git a/db.c b/db.c
7192 index 9cbbbe1..b5c156c 100644
7196 devrim(devrim@gazi.edu.tr)
7202 #include "tac_plus.h"
7207 +#include <stdlib.h>
7208 +#include <string.h>
7211 +#include "report.h"
7212 +#include "do_acct.h"
7214 +#include "do_author.h" /* for "struct identity" */
7219 +#include "db_mysql.h"
7222 +#include "db_null.h"
7225 +#include "db_pgsql.h"
7229 +static int check_db_type TAC_ARGS((char *db_type));
7232 /* The databases recognized by this function */
7233 #define DEFINED_DB {"null","mysql","pgsql"}
7235 -char *find_attr_value();
7236 +int db_verify TAC_ARGS((const char *user, const char *users_passwd, const char *str_conn));
7239 db_verify(user, users_passwd, str_conn)
7240 -char *user, *users_passwd; /* Username and gived password */
7241 -char *str_conn; /* String connection to database */
7242 +const char *user; /* username ... */
7243 +const char *users_passwd; /* ... and given password */
7244 +const char *str_conn; /* string connection to database */
7247 char *db_pref, *db_user, *db_password;
7248 @@ -65,11 +94,7 @@ char *str_conn; /* String connection to database */
7249 if (debug & DEBUG_PASSWD_FLAG)
7250 report(LOG_DEBUG, "verify %s by database at %s", user, str_conn);
7252 - buffer = db_pref = (char *)malloc( strlen(str_conn) + 1 );
7253 - if( buffer == NULL ){
7254 - report(LOG_DEBUG, "Error allocation memory");
7257 + buffer = db_pref = (char *) tac_malloc( strlen(str_conn) + 1 );
7259 strcpy( buffer, str_conn );
7261 @@ -216,6 +241,8 @@ char *str_conn; /* String connection to database */
7265 +int db_acct TAC_ARGS((struct acct_rec *rec));
7267 /* Db accounting routine */
7270 @@ -227,12 +254,7 @@ struct acct_rec *rec;
7271 char *a_username,*s_name,*c_name,*elapsed_time,*bytes_in,*bytes_out;
7274 - buffer = db_pref = (char *)malloc( strlen(session.db_acct) + 1 );
7276 - if( buffer == NULL ){
7277 - report(LOG_DEBUG, "Error allocation memory");
7280 + buffer = db_pref = (char *) tac_malloc( strlen(session.db_acct) + 1 );
7282 strcpy( buffer, session.db_acct);
7284 @@ -384,8 +406,10 @@ struct acct_rec *rec;
7288 +static int check_db_type TAC_ARGS((char *db_type));
7290 /* For checking DB type */
7293 check_db_type(db_type)
7296 @@ -400,4 +424,9 @@ for (i=0; dbp[i] ; i++ ) {
7303 +TAC_SOURCEFILE_EMPTY
7306 diff --git a/db.h b/db.h
7307 new file mode 100644
7308 index 0000000..dfc0c23
7315 +#include "tac_plus.h"
7322 +extern int db_verify TAC_ARGS((const char *user, const char *users_passwd, const char *str_conn));
7323 +extern int db_acct TAC_ARGS((struct acct_rec *rec));
7329 diff --git a/db_mysql.c b/db_mysql.c
7330 index 8aef6d4..4c09f48 100644
7334 -#if defined(DB_MYSQL) && defined(DB)
7337 -Writen by Devrim SERAL(devrim@tef.gazi.edu.tr)
7339 + * Writen by Devrim SERAL(devrim@tef.gazi.edu.tr)
7343 #include "tac_plus.h"
7345 +#if defined(DB_MYSQL) && defined(DB)
7349 +#include <stdlib.h>
7352 +#include "db_mysql.h"
7353 +#include "report.h"
7359 #define SQLCMDL 1024
7360 #define AUTHSQL "SELECT %s FROM %s WHERE %s=\"%s\""
7361 #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())"
7366 -MYSQL_FIELD *table_field;
7368 -int mysql_db_verify(user, users_passwd, db_user, db_password,
7369 - db_hostname,db_name, db_table, dbfield_name, dbfield_passwd)
7370 +static MYSQL mysqldb;
7371 +static MYSQL_RES *res;
7372 +static MYSQL_ROW row;
7375 -char *user, *users_passwd; /* Username and gived password */
7376 -char *db_user; /* db's parameters */
7381 -char *dbfield_name;
7382 -char *dbfield_passwd;
7383 +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));
7385 +int mysql_db_verify(user, users_passwd, db_user, db_password,
7386 + db_hostname, db_name, db_table, dbfield_name, dbfield_passwd)
7387 +const char *user; /* username ... */
7388 +const char *users_passwd; /* ... and given password */
7389 +const char *db_user; /* db's parameters */
7390 +const char *db_password;
7391 +const char *db_hostname;
7392 +const char *db_name;
7393 +const char *db_table;
7394 +const char *dbfield_name;
7395 +const char *dbfield_passwd;
7401 + char *real_passwd;
7405 if (debug & DEBUG_AUTHEN_FLAG)
7406 report(LOG_DEBUG, "MySQL: verify %s", user);
7408 -/* Connect database server */
7409 + /* Connect database server */
7411 - if ( !( mysql_connect(&mysqldb,db_hostname,db_user,db_password) ) )
7413 + if ( !( mysql_connect(&mysqldb,db_hostname,db_user,db_password) ) ) {
7414 if (debug & DEBUG_AUTHEN_FLAG)
7415 report(LOG_DEBUG, "MySQL: cannot connect as %s", db_user);
7419 -/*Select tacacs db */
7420 + /* Select tacacs db */
7422 - if ( mysql_select_db(&mysqldb,db_name) )
7424 + if ( mysql_select_db(&mysqldb,db_name) ) {
7425 if (debug & DEBUG_AUTHEN_FLAG)
7426 report(LOG_DEBUG, "MySQL: cannot find database named %s",db_name);
7430 -/* Check select string length */
7431 + /* Check select string length */
7433 -sql_len=strlen(dbfield_passwd)+strlen(dbfield_name)+strlen(db_table)+strlen(user)+strlen(AUTHSQL);
7434 + sql_len = strlen(dbfield_passwd)+strlen(dbfield_name)+strlen(db_table)+strlen(user)+strlen(AUTHSQL);
7436 - if ( sql_len> SQLCMDL )
7438 + if ( sql_len> SQLCMDL ) {
7439 if (debug & DEBUG_AUTHEN_FLAG)
7440 report(LOG_DEBUG, "MySQL: Sql cmd exceed alowed limits");
7444 -/* Prepare select string */
7445 + /* Prepare select string */
7447 -mysqlcmd=(char *) malloc(sql_len);
7449 -if(mysqlcmd==NULL) {
7450 - if (debug & DEBUG_AUTHEN_FLAG)
7451 - report(LOG_ERR, "mysql_db_verify: mysqlcmd malloc error");
7454 + mysqlcmd = (char *) tac_malloc(sql_len);
7456 -sprintf(mysqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
7457 + sprintf(mysqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
7459 -/* Query database */
7460 + /* Query database */
7462 - if (mysql_query(&mysqldb,mysqlcmd))
7464 + if (mysql_query(&mysqldb,mysqlcmd)) {
7465 if (debug & DEBUG_AUTHEN_FLAG)
7466 report(LOG_DEBUG, "MySQL: cannot query database ");
7468 @@ -91,32 +91,29 @@ sprintf(mysqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
7472 - if (!(res = mysql_store_result(&mysqldb)))
7474 + if (!(res = mysql_store_result(&mysqldb))) {
7475 if (debug & DEBUG_AUTHEN_FLAG)
7476 report(LOG_DEBUG, "MySQL: cannot store result");
7480 - if(!(row = mysql_fetch_row(res)))
7482 + if (!(row = mysql_fetch_row(res))) {
7483 if (debug & DEBUG_AUTHEN_FLAG)
7484 report(LOG_DEBUG, "MySQL: cannot fetch row");
7488 - if (strlen(row[0]) <=0 )
7490 + if (strlen(row[0]) <=0 ) {
7491 if (debug & DEBUG_AUTHEN_FLAG)
7492 report(LOG_DEBUG, "MySQL: DB passwd entry is NULL");
7496 /* Allocate memory for real_passwd */
7497 - real_passwd=(char *) malloc(strlen(row[0])+1);
7498 + real_passwd=(char *) tac_malloc(strlen(row[0])+1);
7499 strcpy(real_passwd,row[0]);
7501 - if (!mysql_eof(res))
7503 + if (!mysql_eof(res)) {
7504 if (debug & DEBUG_AUTHEN_FLAG)
7505 report(LOG_DEBUG, "MySQL: Result not end!!");
7507 @@ -125,7 +122,7 @@ sprintf(mysqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
7508 mysql_free_result(res);
7509 mysql_close(&mysqldb);
7511 -if (debug & DEBUG_AUTHEN_FLAG)
7512 + if (debug & DEBUG_AUTHEN_FLAG)
7513 report(LOG_DEBUG, "MySQL: verify password '%s' to DES encrypted string '%s'", users_passwd, real_passwd);
7515 /* Try to verify the password */
7516 @@ -133,69 +130,65 @@ if (debug & DEBUG_AUTHEN_FLAG)
7522 return (1); /* Return 1 if verified, 0 otherwise. */
7526 -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)
7528 -char *db_user; /* db's parameters */
7533 -char *s_name, *c_name,*a_username,*elapsed_time,*bytes_in,*bytes_out;
7534 +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));
7537 +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)
7538 +const char *db_user; /* db's parameters */
7539 +const char *db_password;
7540 +const char *db_hostname;
7541 +const char *db_name;
7542 +const char *db_table;
7543 +const char *s_name;
7544 +const char *c_name;
7545 +const char *a_username;
7546 +const char *elapsed_time;
7547 +const char *bytes_in;
7548 +const char *bytes_out;
7556 -/* Connect database server */
7557 + /* Connect database server */
7559 - if (!(mysql_connect(&mysqldb,db_hostname,db_user,db_password)))
7561 + if (!(mysql_connect(&mysqldb,db_hostname,db_user,db_password))) {
7562 if (debug & DEBUG_ACCT_FLAG)
7563 report(LOG_DEBUG, "MySQL: cannot connect as %s", db_user);
7567 -/*Select tacacs db */
7568 + /*Select tacacs db */
7570 - if (mysql_select_db(&mysqldb,db_name))
7572 + if (mysql_select_db(&mysqldb,db_name)) {
7573 if (debug & DEBUG_ACCT_FLAG)
7574 report(LOG_DEBUG, "MySQL: cannot find database named %s",db_name);
7578 -/* Check buffer overflow for select string */
7579 -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);
7580 + /* Check buffer overflow for select string */
7581 + 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);
7583 -if ( sql_len >SQLCMDL)
7585 + if ( sql_len >SQLCMDL) {
7586 if (debug & DEBUG_ACCT_FLAG)
7587 report(LOG_DEBUG, "MySQL: Sql cmd exceed alowed limits");
7592 -/* Prepare select string */
7593 -mysqlcmd=(char *) malloc(sql_len);
7594 + /* Prepare select string */
7595 + mysqlcmd=(char *) tac_malloc(sql_len);
7597 -if(mysqlcmd==NULL) {
7598 - if (debug & DEBUG_ACCT_FLAG)
7599 - report(LOG_ERR, "mysql_db_acct: mysqlcmd malloc error");
7603 -sprintf(mysqlcmd,ACCTSQL,db_table,a_username,s_name,c_name,elapsed_time,bytes_in,bytes_out);
7604 + sprintf(mysqlcmd,ACCTSQL,db_table,a_username,s_name,c_name,elapsed_time,bytes_in,bytes_out);
7606 -/* Query database */
7607 + /* Query database */
7609 - if (mysql_query(&mysqldb,mysqlcmd))
7611 + if (mysql_query(&mysqldb,mysqlcmd)) {
7612 if (debug & DEBUG_ACCT_FLAG)
7613 report(LOG_DEBUG, "MySQL: cannot query database");
7615 @@ -204,13 +197,18 @@ sprintf(mysqlcmd,ACCTSQL,db_table,a_username,s_name,c_name,elapsed_time,bytes_in
7619 -/* Check if accounting is sucess */
7620 - if ( mysql_affected_rows( &mysqldb ) < 0 )
7622 + /* Check if accounting is sucess */
7623 + if ( mysql_affected_rows( &mysqldb ) < 0 ) {
7624 if (debug & DEBUG_ACCT_FLAG)
7625 report(LOG_DEBUG, "MySQL: Insert isn't sucess");
7629 return (1); /* Return 1 if verified, 0 otherwise. */
7633 +#else /* defined(DB_MYSQL) && defined(DB) */
7635 +TAC_SOURCEFILE_EMPTY
7637 +#endif /* defined(DB_MYSQL) && defined(DB) */
7638 diff --git a/db_mysql.h b/db_mysql.h
7639 new file mode 100644
7640 index 0000000..7e806b6
7645 +#define DB_MYSQL_H 1
7647 +#include "tac_plus.h"
7649 +#if defined(DB_MYSQL) && defined(DB)
7652 +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));
7653 +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));
7656 +#endif /* defined(DB_MYSQL) && defined(DB) */
7658 +#endif /* DB_MYSQL_H */
7659 diff --git a/db_null.c b/db_null.c
7660 index 40252d8..9892ef0 100644
7664 ** DO_NOT_USE_THIS_FOR_WORK!
7667 -#if defined(DB_NULL) && defined(DB)
7669 #include "tac_plus.h"
7671 -int null_db_verify(user, users_passwd, db_user, db_password, db_hostname,
7672 - db_table, dbfield_name, dbfield_passwd)
7673 +#if defined(DB_NULL) && defined(DB)
7675 +#include "db_null.h"
7676 +#include "report.h"
7679 -char *user, *users_passwd; /* Username and gived password */
7680 -char *db_user; /* db's parametr's */
7684 -char *dbfield_name;
7685 -char *dbfield_passwd;
7687 +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));
7689 +int null_db_verify(user, users_passwd, db_user, db_password, db_hostname,
7690 + db_table, dbfield_name, dbfield_passwd)
7691 +const char *user; /* username ... */
7692 +const char *users_passwd; /* ... and given password */
7693 +const char *db_user; /* db's parametr's */
7694 +const char *db_password;
7695 +const char *db_hostname;
7696 +const char *db_table;
7697 +const char *dbfield_name;
7698 +const char *dbfield_passwd;
7700 -//report(LOG_DEBUG, "DB_NULL(%u) - ok", __LINE__);
7701 +/* report(LOG_DEBUG, "DB_NULL(%u) - ok", __LINE__); */
7703 /* Try to verify the password
7704 Successful if username and password equal */
7705 @@ -36,22 +44,30 @@ char *dbfield_passwd;
7707 /* Null Database Accounting */
7709 +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));
7712 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)
7713 -char *db_user; /* db's parametr's */
7721 -char *elapsed_time;char *bytes_in;char *bytes_out;
7722 +const char *db_user; /* db's parametr's */
7723 +const char *db_password;
7724 +const char *db_hostname;
7725 +const char *db_name;
7726 +const char *db_table;
7727 +const char *s_name;
7728 +const char *c_name;
7729 +const char *a_username;
7730 +const char *elapsed_time;
7731 +const char *bytes_in;
7732 +const char *bytes_out;
7734 -report(LOG_INFO,"Db accounting user=%s pass=%s host=%s
7735 -db_name=%s table=%s servern=%s clientn=%s username=%s et=%s bi=%s bo=%s",db_user,db_password,db_hostname,
7736 -db_name,db_table,s_name,c_name,a_username,elapsed_time,bytes_in,bytes_out);
7738 + report(LOG_INFO,"Db accounting user=%s pass=%s host=%s \
7739 + db_name=%s table=%s servern=%s clientn=%s username=%s et=%s bi=%s bo=%s",db_user,db_password,db_hostname,
7740 + db_name,db_table,s_name,c_name,a_username,elapsed_time,bytes_in,bytes_out);
7745 +#else /* defined(DB_NULL) && defined(DB) */
7747 +TAC_SOURCEFILE_EMPTY
7749 +#endif /* defined(DB_NULL) && defined(DB) */
7750 diff --git a/db_null.h b/db_null.h
7751 new file mode 100644
7752 index 0000000..4e82047
7757 +#define DB_NULL_H 1
7759 +#include "tac_plus.h"
7761 +#if defined(DB_NULL) && defined(DB)
7764 +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));
7765 +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));
7768 +#endif /* defined(DB_NULL) && defined(DB) */
7770 +#endif /* DB_NULL_H */
7771 diff --git a/db_pgsql.c b/db_pgsql.c
7772 index 22725fe..321133c 100644
7776 -#if defined(DB_PGSQL) && defined(DB)
7779 Writen by Devrim SERAL(devrim@tef.gazi.edu.tr)
7780 For PostgreSQL Authentication And Accounting
7781 @@ -7,80 +5,87 @@ For PostgreSQL Authentication And Accounting
7782 This program protected with GPL License.
7786 #include "tac_plus.h"
7788 +#if defined(DB_PGSQL) && defined(DB)
7791 -#include "libpq-fe.h"
7792 +#include <stdlib.h>
7793 +#include <libpq-fe.h>
7794 +#include <string.h>
7796 +#include "db_pgsql.h"
7798 +#include "report.h"
7803 +static void exit_nicely TAC_ARGS((PGconn *cn, PGresult *r));
7806 #define SQLCMDL 1024
7808 #define AUTHSQL "SELECT %s FROM %s WHERE %s='%s'"
7809 #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())"
7814 -int pgsql_db_verify(user, users_passwd, db_user, db_password,
7815 - db_hostname,db_name, db_table, dbfield_name, dbfield_passwd)
7816 +static PGconn *conn;
7817 +static PGresult *res;
7820 -char *user, *users_passwd; /* Username and gived password */
7821 -char *db_user; /* db's parameters */
7826 -char *dbfield_name;
7827 -char *dbfield_passwd;
7828 +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));
7830 +int pgsql_db_verify(user, users_passwd, db_user, db_password,
7831 + db_hostname, db_name, db_table, dbfield_name, dbfield_passwd)
7832 +const char *user; /* username ... */
7833 +const char *users_passwd; /* ... and given password */
7834 +const char *db_user; /* db's parameters */
7835 +const char *db_password;
7836 +const char *db_hostname;
7837 +const char *db_name;
7838 +const char *db_table;
7839 +const char *dbfield_name;
7840 +const char *dbfield_passwd;
7842 + char *real_passwd;
7852 -if (debug & DEBUG_AUTHEN_FLAG)
7853 + if (debug & DEBUG_AUTHEN_FLAG)
7854 report(LOG_DEBUG, "PGSQL: verify %s", user);
7856 -/* Connect database server */
7857 + /* Connect database server */
7859 -conn=PQsetdbLogin(db_hostname,NULL,NULL,NULL,db_name,db_user,db_password);
7860 + conn=PQsetdbLogin(db_hostname,NULL,NULL,NULL,db_name,db_user,db_password);
7862 -if ( PQstatus(conn) == CONNECTION_BAD )
7864 + if ( PQstatus(conn) == CONNECTION_BAD ) {
7865 if (debug & DEBUG_AUTHEN_FLAG)
7866 report(LOG_DEBUG, "PGSQL: Connection to database %s failed", db_name);
7871 -/* Check select string length */
7872 + /* Check select string length */
7874 -sql_len=strlen(dbfield_passwd)+strlen(dbfield_name)+strlen(db_table)+strlen(user)+strlen(AUTHSQL);
7875 + sql_len=strlen(dbfield_passwd)+strlen(dbfield_name)+strlen(db_table)+strlen(user)+strlen(AUTHSQL);
7877 -if ( sql_len> SQLCMDL )
7879 + if ( sql_len> SQLCMDL ) {
7880 if (debug & DEBUG_AUTHEN_FLAG)
7881 report(LOG_DEBUG, "PGSQL: Sql cmd exceed alowed limits");
7885 -/* Prepare select string */
7888 -pgsqlcmd=(char *) malloc(sql_len);
7889 + /* Prepare select string */
7893 - if (debug & DEBUG_AUTHEN_FLAG)
7894 - report(LOG_ERR, "pgsql_db_verify: pgsqlcmd malloc error");
7897 + pgsqlcmd=(char *) tac_malloc(sql_len);
7899 -sprintf(pgsqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
7900 + sprintf(pgsqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
7902 -/* Query database */
7903 -res=PQexec(conn,pgsqlcmd);
7904 + /* Query database */
7905 + res=PQexec(conn,pgsqlcmd);
7907 -if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
7909 + if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) {
7910 if (debug & DEBUG_AUTHEN_FLAG) {
7911 report(LOG_DEBUG, "PGSQL: cannot query database ");
7912 report(LOG_DEBUG, "PGSQL: Error message->%s", PQerrorMessage(conn) );
7913 @@ -88,119 +93,109 @@ if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
7915 exit_nicely(conn,res);
7923 -if( nrow=PQntuples(res)!=1)
7925 + if ( (nrow=PQntuples(res)) !=1 ) {
7926 if (debug & DEBUG_AUTHEN_FLAG)
7927 report(LOG_DEBUG, "PGSQL: Have we got more than one password!!");
7928 exit_nicely(conn,res);
7933 -if ( PQgetisnull(res,0,PQfnumber(res,dbfield_passwd)) )
7935 + if ( PQgetisnull(res,0,PQfnumber(res,dbfield_passwd)) ) {
7936 if (debug & DEBUG_AUTHEN_FLAG)
7937 report(LOG_DEBUG, "PGSQL: DB passwd entry is NULL");
7938 exit_nicely(conn,res);
7943 /* Allocate memory for real_passwd */
7944 - real_passwd=(char *) malloc(PWLEN+1);
7945 + real_passwd=(char *) tac_malloc(PWLEN+1);
7946 strncpy(real_passwd,PQgetvalue(res,0,PQfnumber(res,dbfield_passwd)),PWLEN);
7947 real_passwd[PWLEN]='\0';
7949 -exit_nicely(conn,res);
7950 + exit_nicely(conn,res);
7952 -if (debug & DEBUG_AUTHEN_FLAG)
7953 + if (debug & DEBUG_AUTHEN_FLAG)
7954 report(LOG_DEBUG, "PGSQL: verify password '%s' to DES encrypted string '%s'", users_passwd, real_passwd);
7956 /* Try to verify the password */
7957 if (!des_verify(users_passwd, real_passwd))
7962 return (1); /* Return 1 if verified, 0 otherwise. */
7965 /* PGSQL ACCOUNTING function */
7967 -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)
7969 -char *db_user; /* db's parameters */
7974 -char *s_name, *c_name,*a_username,*elapsed_time,*bytes_in,*bytes_out;
7975 +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));
7977 +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)
7978 +const char *db_user; /* db's parameters */
7979 +const char *db_password;
7980 +const char *db_hostname;
7981 +const char *db_name;
7982 +const char *db_table;
7983 +const char *s_name;
7984 +const char *c_name;
7985 +const char *a_username;
7986 +const char *elapsed_time;
7987 +const char *bytes_in;
7988 +const char *bytes_out;
7996 if (debug & DEBUG_ACCT_FLAG)
7997 report(LOG_DEBUG, "PGSQL: Accounting for %s begin", a_username);
7999 -/* Connect database server */
8000 + /* Connect database server */
8002 -conn=PQsetdbLogin(db_hostname,NULL,NULL,NULL,db_name,db_user,db_password);
8003 + conn=PQsetdbLogin(db_hostname,NULL,NULL,NULL,db_name,db_user,db_password);
8005 -if ( PQstatus(conn) == CONNECTION_BAD )
8007 + if ( PQstatus(conn) == CONNECTION_BAD ) {
8008 if (debug & DEBUG_ACCT_FLAG) {
8009 report(LOG_DEBUG, "PGSQL: Connection to database %s failed", db_name);
8010 report(LOG_DEBUG, "PGSQL: Error message->%s", PQerrorMessage(conn) );
8016 -/* Check select string length */
8017 + /* Check select string length */
8019 -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);
8020 + 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);
8022 -if ( sql_len> SQLCMDL )
8024 + if ( sql_len> SQLCMDL ) {
8025 if (debug & DEBUG_ACCT_FLAG)
8026 report(LOG_DEBUG, "PGSQL: Sql cmd exceed alowed limits");
8030 -/* Prepare select string */
8033 -pgsqlcmd=(char *) malloc(sql_len);
8034 + /* Prepare select string */
8038 -if (debug & DEBUG_ACCT_FLAG)
8039 - report(LOG_ERR, "pgsql_db_verify: pgsqlcmd malloc error");
8042 + pgsqlcmd=(char *) tac_malloc(sql_len);
8044 -sprintf(pgsqlcmd,ACCTSQL,db_table,a_username,s_name,c_name,elapsed_time,bytes_in,bytes_out);
8045 + sprintf(pgsqlcmd,ACCTSQL,db_table,a_username,s_name,c_name,elapsed_time,bytes_in,bytes_out);
8047 -/* Query database */
8048 -res=PQexec(conn,pgsqlcmd);
8049 + /* Query database */
8050 + res=PQexec(conn,pgsqlcmd);
8052 -if (!res || PQresultStatus(res) != PGRES_COMMAND_OK )
8054 + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK ) {
8055 if (debug & DEBUG_ACCT_FLAG) {
8056 report(LOG_DEBUG, "PGSQL: cannot establish database query");
8057 report(LOG_DEBUG, "PGSQL: Error message->%s", PQerrorMessage(conn) );
8061 exit_nicely(conn,res);
8069 -/* Flush all result and close connection */
8070 -exit_nicely(conn,res);
8071 + /* Flush all result and close connection */
8072 + exit_nicely(conn,res);
8074 if (debug & DEBUG_ACCT_FLAG)
8075 report(LOG_DEBUG, "PGSQL: Accounting for %s finished", a_username);
8076 @@ -208,11 +203,20 @@ exit_nicely(conn,res);
8077 return (1); /* Return 1 if verified, 0 otherwise. */
8081 -exit_nicely(PGconn *cn,PGresult *r)
8083 +static void exit_nicely TAC_ARGS((PGconn *cn, PGresult *r));
8095 +#else /* defined(DB_PGSQL) && defined(DB) */
8097 +TAC_SOURCEFILE_EMPTY
8099 +#endif /* defined(DB_PGSQL) && defined(DB) */
8100 diff --git a/db_pgsql.h b/db_pgsql.h
8101 new file mode 100644
8102 index 0000000..b966bfc
8107 +#define DB_PGSQL_H 1
8109 +#include "tac_plus.h"
8111 +#if defined(DB_PGSQL) && defined(DB)
8114 +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));
8115 +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));
8118 +#endif /* defined(DB_PGSQL) && defined(DB) */
8120 +#endif /* DB_PGSQL_H */
8121 diff --git a/default_fn.c b/default_fn.c
8122 index f97e9e2..d6196cf 100644
8126 FITNESS FOR A PARTICULAR PURPOSE.
8130 #include "tac_plus.h"
8132 +#include <stdlib.h>
8133 +#include <string.h>
8136 +#include "default_fn.h"
8139 +#include "report.h"
8141 +#include "cfgfile.h"
8143 +#include "choose_authen.h" /* for "struct authen_data" */
8144 +#include "do_author.h" /* for "struct identity" */
8145 +#include "packet.h"
8153 #include "arap_des.h"
8155 +#endif /* MSCHAP_DES */
8159 #include "arap_des.h"
8163 +struct private_data;
8165 +static void chap_verify TAC_ARGS((struct authen_data *data));
8166 +static void arap_verify TAC_ARGS((struct authen_data *data));
8167 +static void pap_verify TAC_ARGS((struct authen_data *data));
8168 +static void tac_login TAC_ARGS((struct authen_data *data, struct private_data *p));
8171 +static void mschap_verify TAC_ARGS((struct authen_data *data));
8175 /* internal state variables */
8176 #define STATE_AUTHEN_START 0 /* no requests issued */
8177 #define STATE_AUTHEN_GETUSER 1 /* username has been requested */
8178 @@ -44,13 +71,6 @@ struct private_data {
8182 -static void chap_verify();
8184 -static void mschap_verify();
8185 -#endif /* MSCHAP */
8186 -static void arap_verify();
8187 -static void pap_verify();
8188 -static void tac_login();
8191 * Default tacacs login authentication function. Wants a username
8192 @@ -67,6 +87,8 @@ static void tac_login();
8193 * Return 0 if data->status is valid, otherwise 1
8196 +int default_fn TAC_ARGS((struct authen_data *data));
8200 struct authen_data *data;
8201 @@ -210,6 +232,8 @@ struct authen_data *data;
8205 +static void tac_login TAC_ARGS((struct authen_data *data, struct private_data *p));
8209 struct authen_data *data;
8210 @@ -278,6 +302,8 @@ struct private_data *p;
8214 +static void pap_verify TAC_ARGS((struct authen_data *data));
8218 struct authen_data *data;
8219 @@ -305,6 +331,8 @@ struct authen_data *data;
8223 +static void chap_verify TAC_ARGS((struct authen_data *data));
8225 /* Verify the challenge and id against the response by looking up the
8226 * chap secret in the config file. Set data->status appropriately.
8228 @@ -312,8 +340,9 @@ static void
8230 struct authen_data *data;
8232 - char *name, *secret, *chal, digest[MD5_LEN];
8233 - char *exp_date, *p;
8234 + char *name, *chal, digest[MD5_LEN];
8235 + const char *secret;
8236 + const char *exp_date, *p;
8239 int chal_len, inlen;
8240 @@ -398,13 +427,15 @@ struct authen_data *data;
8244 +static void pw_bitshift TAC_ARGS((char *pw));
8247 * Force the "parity" bit to zero on a password before passing it to
8248 * des. This is not documented anywhere. (I believe forcing the parity
8249 * to zero reduces the integrity of the encrypted keys but this is
8250 * what Apple chose to do).
8257 @@ -423,12 +454,14 @@ char *pw;
8261 +static void arap_verify TAC_ARGS((struct authen_data *data));
8265 struct authen_data *data;
8267 char nas_chal[8], r_chal[8], r_resp[8], secret[8];
8268 - char *name, *cfg_secret, *exp_date, *p;
8269 + const char *name, *cfg_secret, *exp_date, *p;
8271 if (!(char) data->NAS_id->username[0]) {
8272 report(LOG_ERR, "%s %s: no username for arap_verify",
8273 @@ -511,9 +544,12 @@ struct authen_data *data;
8276 /* Following code is added for ms-chap */
8278 +static void mschap_desencrypt TAC_ARGS((const char *clear, unsigned char *str, unsigned char *cypher));
8281 mschap_desencrypt(clear, str, cypher)
8285 unsigned char *cypher;
8287 @@ -576,19 +612,23 @@ unsigned char *cypher;
8291 +static void mschap_deshash TAC_ARGS((unsigned char *clear, unsigned char *cypher));
8294 mschap_deshash(clear, cypher)
8297 +unsigned char *clear;
8298 +unsigned char *cypher;
8300 mschap_desencrypt(MSCHAP_KEY, clear, cypher);
8304 +static void mschap_lmpasswordhash TAC_ARGS((const char *password, unsigned char *passwordhash));
8307 mschap_lmpasswordhash(password, passwordhash)
8309 -char *passwordhash;
8310 +const char *password;
8311 +unsigned char *passwordhash;
8313 unsigned char upassword[15];
8315 @@ -604,13 +644,15 @@ char *passwordhash;
8319 +static void mschap_challengeresponse TAC_ARGS((const char *challenge, unsigned char *passwordhash, unsigned char *response));
8322 mschap_challengeresponse(challenge, passwordhash, response)
8324 -char *passwordhash;
8326 +const char *challenge;
8327 +unsigned char *passwordhash;
8328 +unsigned char *response;
8330 - char zpasswordhash[21];
8331 + unsigned char zpasswordhash[21];
8333 memset(zpasswordhash, 0, 21);
8334 memcpy(zpasswordhash, passwordhash, 16);
8335 @@ -621,22 +663,26 @@ char *response;
8339 +void mschap_lmchallengeresponse TAC_ARGS((const char *challenge, const char *password, unsigned char *response));
8342 mschap_lmchallengeresponse(challenge, password, response)
8346 +const char *challenge;
8347 +const char *password;
8348 +unsigned char *response;
8350 - char passwordhash[16];
8351 + unsigned char passwordhash[16];
8353 mschap_lmpasswordhash(password, passwordhash);
8354 mschap_challengeresponse(challenge, passwordhash, response);
8358 +static int mschap_unicode_len TAC_ARGS((unsigned char *password));
8361 mschap_unicode_len(password)
8363 +unsigned char *password;
8367 @@ -649,14 +695,16 @@ char *password;
8371 +static void mschap_ntpasswordhash TAC_ARGS((const char *password, unsigned char *passwordhash));
8374 mschap_ntpasswordhash(password, passwordhash)
8376 -char *passwordhash;
8377 +const char *password;
8378 +unsigned char *passwordhash;
8384 unsigned char unicode_password[512];
8386 memset(unicode_password, 0, 512);
8387 @@ -676,15 +724,15 @@ char *passwordhash;
8391 +void mschap_ntchallengeresponse TAC_ARGS((const char *challenge, const char *password, unsigned char *response));
8394 -mschap_ntchallengeresponse(challenge,
8400 +mschap_ntchallengeresponse(challenge, password, response)
8401 +const char *challenge;
8402 +const char *password;
8403 +unsigned char *response;
8405 - char passwordhash[16];
8406 + unsigned char passwordhash[16];
8408 mschap_ntpasswordhash(password, passwordhash);
8409 mschap_challengeresponse(challenge, passwordhash, response);
8410 @@ -694,16 +742,19 @@ char *response;
8411 /* Verify the challenge and id against the response by looking up the
8412 * ms-chap secret in the config file. Set data->status appropriately.
8415 +static void mschap_verify TAC_ARGS((struct authen_data *data));
8419 struct authen_data *data;
8421 - char *name, *secret, *chal, *resp;
8422 - char *exp_date, *p;
8423 + const char *name, *secret, *chal, *resp;
8424 + const char *exp_date, *p;
8427 - char lmresponse[24];
8428 - char ntresponse[24];
8429 + unsigned char lmresponse[24];
8430 + unsigned char ntresponse[24];
8433 if (!(char) data->NAS_id->username[0]) {
8434 diff --git a/default_fn.h b/default_fn.h
8435 new file mode 100644
8436 index 0000000..20e0e0f
8440 +#ifndef DEFAULT_FN_H
8441 +#define DEFAULT_FN_H 1
8443 +#include "tac_plus.h"
8446 +struct authen_data;
8448 +extern int default_fn TAC_ARGS((struct authen_data *data));
8450 +extern void mschap_lmchallengeresponse TAC_ARGS((const char *challenge, const char *password, unsigned char *response));
8451 +extern void mschap_ntchallengeresponse TAC_ARGS((const char *challenge, const char *password, unsigned char *response));
8455 +#endif /* DEFAULT_FN_H */
8456 diff --git a/default_v0_fn.c b/default_v0_fn.c
8457 index 96e0c1d..7c4c9cb 100644
8458 --- a/default_v0_fn.c
8459 +++ b/default_v0_fn.c
8461 FITNESS FOR A PARTICULAR PURPOSE.
8465 #include "tac_plus.h"
8467 +#include <stdlib.h>
8468 +#include <string.h>
8470 +#include "default_v0_fn.h"
8473 +#include "report.h"
8475 +#include "choose_authen.h" /* for "struct authen_data" */
8476 +#include "do_author.h" /* for "struct identity" */
8477 +#include "packet.h"
8479 +#include "cfgfile.h"
8482 /* internal state variables */
8483 #define STATE_AUTHEN_START 0 /* no requests issued */
8484 @@ -45,6 +60,8 @@ struct private_data {
8485 * Return 0 if data->status is valid, otherwise 1
8488 +int default_v0_fn TAC_ARGS((struct authen_data *data));
8492 struct authen_data *data;
8493 @@ -185,4 +202,3 @@ struct authen_data *data;
8498 diff --git a/default_v0_fn.h b/default_v0_fn.h
8499 new file mode 100644
8500 index 0000000..1165ee4
8502 +++ b/default_v0_fn.h
8504 +#ifndef DEFAULT_V0_FN_H
8505 +#define DEFAULT_V0_FN_H 1
8507 +#include "tac_plus.h"
8510 +struct authen_data;
8512 +extern int default_v0_fn TAC_ARGS((struct authen_data *data));
8515 +#endif /* DEFAULT_V0_FN_H */
8516 diff --git a/do_acct.c b/do_acct.c
8517 index dee8eaa..287b0dc 100644
8521 FITNESS FOR A PARTICULAR PURPOSE.
8525 #include "tac_plus.h"
8527 +#include <stdlib.h>
8530 +#include <sys/types.h>
8531 +#include <sys/stat.h>
8532 +#ifdef HAVE_FCNTL_H
8535 +#include <string.h>
8537 +#ifdef HAVE_UNISTD_H
8538 +#include <unistd.h>
8541 +#include "do_acct.h"
8542 +#include "report.h"
8545 +#include "do_author.h" /* for "struct identity" */
8548 +char *wtmpfile = NULL; /* for wtmp file logging */
8551 +static int wtmpfd = 0;
8552 static int acctfd = 0;
8554 /* Make a acct entry into the accounting file for accounting.
8555 Return 1 on error */
8557 +static int acct_write TAC_ARGS((char *string));
8564 - if (write(acctfd, string, strlen(string)) != strlen(string)) {
8565 + if ((unsigned long)write(acctfd, string, strlen(string)) != strlen(string)) {
8566 report(LOG_ERR, "%s: couldn't write acct file %s %s",
8568 session.acctfile, sys_errlist[errno]);
8569 @@ -41,11 +69,13 @@ acct_write(string)
8573 +static int acct_write_field TAC_ARGS((char *string));
8575 /* Write a string or "unknown" into the accounting file.
8576 Return 1 on error */
8578 acct_write_field(string)
8582 if (string && string[0]) {
8583 if (acct_write(string))
8584 @@ -57,6 +87,8 @@ acct_write_field(string)
8588 +int do_acct TAC_ARGS((struct acct_rec *rec));
8592 struct acct_rec *rec;
8593 @@ -131,10 +163,12 @@ struct acct_rec *rec;
8598 +static int wtmp_entry TAC_ARGS((char *line, char *name, char *host, time_t utime));
8601 wtmp_entry (line, name, host, utime)
8602 - char *line, *name, *host;
8604 +char *line, *name, *host;
8609 @@ -152,7 +186,7 @@ wtmp_entry (line, name, host, utime)
8610 strcpy(entry.ut_name, name);
8611 else bcopy(name, entry.ut_name, sizeof entry.ut_name);
8614 +#ifdef HAVE_UTMP_UT_HOST
8615 if (strlen(host) < sizeof entry.ut_host)
8616 strcpy(entry.ut_host, host);
8617 else bcopy(host, entry.ut_host, sizeof entry.ut_host);
8618 @@ -180,16 +214,18 @@ wtmp_entry (line, name, host, utime)
8621 if (debug & DEBUG_ACCT_FLAG) {
8622 - report(LOG_DEBUG, "wtmp: %s, %s %s %d", line, name, host, utime);
8623 + report(LOG_DEBUG, "wtmp: %s, %s %s %ld", line, name, host, (long)utime);
8629 +char *find_attr_value TAC_ARGS((char *attr, char **args, int cnt));
8632 find_attr_value (attr, args, cnt)
8633 - char *attr, **args;
8635 +char *attr, **args;
8640 @@ -208,9 +244,11 @@ find_attr_value (attr, args, cnt)
8644 +int do_wtmp TAC_ARGS((struct acct_rec *rec));
8648 - struct acct_rec *rec;
8649 +struct acct_rec *rec;
8651 time_t now = time(NULL);
8653 diff --git a/do_acct.h b/do_acct.h
8654 new file mode 100644
8655 index 0000000..5e6e025
8660 +#define DO_ACCT_H 1
8662 +#include "tac_plus.h"
8665 +/* An API accounting record structure */
8667 + int acct_type; /* start, stop, update */
8669 +#define ACCT_TYPE_START 1
8670 +#define ACCT_TYPE_STOP 2
8671 +#define ACCT_TYPE_UPDATE 3
8673 + struct identity *identity;
8674 + int authen_method;
8676 + int authen_service;
8677 + char *msg; /* output field */
8678 + char *admin_msg; /* output field */
8683 +extern char *wtmpfile; /* for wtmp file logging */
8686 +extern int do_acct TAC_ARGS((struct acct_rec *rec));
8687 +extern char *find_attr_value TAC_ARGS((char *attr, char **args, int cnt));
8688 +extern int do_wtmp TAC_ARGS((struct acct_rec *rec));
8691 +#endif /* DO_ACCT_H */
8692 diff --git a/do_author.c b/do_author.c
8693 index 574736f..3f23602 100644
8697 FITNESS FOR A PARTICULAR PURPOSE.
8701 #include "tac_plus.h"
8702 -#include "regexp.h"
8704 -static int get_nas_svc();
8705 -static int authorize_cmd();
8706 -static int authorize_exec();
8707 -static int authorize_svc();
8708 -static void post_authorization();
8709 -static int pre_authorization();
8710 +#include <stdlib.h>
8711 +#include <string.h>
8713 +#include "do_author.h"
8714 +#include "tac_regexp.h"
8715 +#include "cfgfile.h"
8716 +#include "report.h"
8718 +#include "programs.h"
8721 +#include "cfgeval.h"
8724 +#include "maxsess.h"
8727 +#include "tac_pam.h"
8731 +static int pre_authorization TAC_ARGS((const char *username, struct author_data *data));
8732 +static int get_nas_svc TAC_ARGS((struct author_data *data, char **cmdname, char **protocol, char **svcname));
8733 +static int authorize_cmd TAC_ARGS((const char *user, const char *cmd, struct author_data *data));
8734 +static int authorize_exec TAC_ARGS((const char *user, struct author_data *data));
8735 +static int authorize_svc TAC_ARGS((const char *user, int svc, const char *protocol, const char *svcname, struct author_data *data));
8736 +static void post_authorization TAC_ARGS((const char *username, struct author_data *data));
8739 +int do_author TAC_ARGS((struct author_data *data));
8741 /* Return 0 is data->status is valid */
8743 @@ -37,7 +61,7 @@ struct author_data *data;
8745 char *cmd, *protocol, *svcname;
8747 - char *pam_service= NULL;
8748 + const char *pam_service= NULL;
8752 @@ -48,7 +72,8 @@ struct author_data *data;
8754 /* If this user doesn't exist in our configs, do the default */
8756 - if (!cfg_user_exists(username) && !cfg_user_exists(DEFAULT_USERNAME)) {
8757 + if (!cfg_user_exists(username)) {
8758 + if (!cfg_user_exists(DEFAULT_USERNAME)) {
8760 if (cfg_no_user_permitted()) {
8761 if (debug & DEBUG_AUTHOR_FLAG)
8762 @@ -70,7 +95,8 @@ struct author_data *data;
8766 - if (!cfg_user_exists(username) && cfg_user_exists(DEFAULT_USERNAME)) {
8767 + /* assumed (cfg_user_exists(DEFAULT_USERNAME)): */
8769 if (debug & DEBUG_AUTHOR_FLAG) {
8770 report(LOG_DEBUG, "Authorizing user '%s' instead of '%s'",
8771 DEFAULT_USERNAME, username);
8772 @@ -127,19 +153,20 @@ struct author_data *data;
8774 /* Check PAM Authorization */
8779 -if (pam_service=cfg_get_pam_service(data->id->username,TAC_PLUS_RECURSE) ) {
8780 + if ((pam_service = cfg_get_pam_service(data->id->username, TAC_PLUS_RECURSE) )) {
8782 if (debug & DEBUG_AUTHOR_FLAG)
8783 report(LOG_DEBUG, "PAM Authorization begin for user %s",data->id->username);
8784 - if(tac_pam_authorization(data->id->username,data,pam_service))
8786 + if (tac_pam_authorization(data->id->username, data, pam_service)) {
8787 if (debug & DEBUG_AUTHOR_FLAG)
8788 report(LOG_DEBUG, "PAM Authorization Fail");
8791 -} /* Pam_service */
8792 + } /* Pam_service */
8797 @@ -181,15 +208,17 @@ if (pam_service=cfg_get_pam_service(data->id->username,TAC_PLUS_RECURSE) ) {
8798 A return value of 1 means no further authorization is required
8801 +static int pre_authorization TAC_ARGS((const char *username, struct author_data *data));
8804 pre_authorization(username, data)
8806 +const char *username;
8807 struct author_data *data;
8814 char error_str[255];
8815 int error_len = 255;
8817 @@ -199,7 +228,7 @@ struct author_data *data;
8818 /* If a before-authorization program exists, call it to see how to
8821 - cmd = cfg_get_pvalue(username, TAC_IS_USER,
8822 + cmd = cfg_get_pvalue(S_user, username,
8823 S_before, TAC_PLUS_RECURSE);
8826 @@ -303,16 +332,17 @@ struct author_data *data;
8827 change the authorization status by calling an external program.
8830 +static void post_authorization TAC_ARGS((const char *username, struct author_data *data));
8833 post_authorization(username, data)
8835 - struct author_data *data;
8836 +const char *username;
8837 +struct author_data *data;
8842 - char *after = cfg_get_pvalue(username, TAC_IS_USER,
8843 - S_after, TAC_PLUS_RECURSE);
8844 + const char *after = cfg_get_pvalue(S_user, username, S_after, TAC_PLUS_RECURSE);
8848 @@ -378,6 +408,8 @@ post_authorization(username, data)
8852 +static char *value TAC_ARGS((char *s));
8854 /* Return a pointer to the value part of an attr=value string */
8857 @@ -393,6 +425,8 @@ char *s;
8858 /* Reassemble the command arguments as typed by the user, out of the
8859 array of args we received. Return "" if there are no arguments */
8861 +static char *assemble_args TAC_ARGS((struct author_data *data));
8865 struct author_data *data;
8866 @@ -445,30 +479,27 @@ struct author_data *data;
8867 Otherwise, we return 1, indicating no further processing is
8868 required for this request. */
8870 +static int authorize_exec TAC_ARGS((const char *user, struct author_data *data));
8873 authorize_exec(user, data)
8876 struct author_data *data;
8880 if (debug & DEBUG_AUTHOR_FLAG)
8881 report(LOG_DEBUG, "exec authorization request for %s", user);
8883 /* Is an exec explicitly configured? If so, return 0 so we know to
8884 process its attributes */
8886 - svc = cfg_get_svc_node(user, N_svc_exec, NULL, NULL, TAC_PLUS_RECURSE);
8888 + if (cfg_get_svc_node(user, N_svc_exec, NULL, NULL, TAC_PLUS_RECURSE, NULL /* nodep */)) {
8889 if (debug & DEBUG_AUTHOR_FLAG)
8890 - report(LOG_DEBUG, "exec is explicitly permitted by line %d",
8892 + report(LOG_DEBUG, "exec is explicitly permitted");
8896 /* No exec is configured. Are any commands configured? */
8897 - svc = cfg_get_svc_node(user, N_svc_cmd, NULL, NULL, TAC_PLUS_RECURSE);
8899 + if (cfg_get_svc_node(user, N_svc_cmd, NULL, NULL, TAC_PLUS_RECURSE, NULL /* nodep */)) {
8900 if (debug & DEBUG_AUTHOR_FLAG)
8901 report(LOG_DEBUG, "exec permitted because commands are configured");
8903 @@ -478,18 +509,6 @@ struct author_data *data;
8907 - /* No exec or commands configured. What's the default? */
8908 - if (cfg_user_svc_default_is_permit(user)) {
8910 - if (debug & DEBUG_AUTHOR_FLAG)
8911 - report(LOG_DEBUG, "exec permitted by default");
8913 - data->status = AUTHOR_STATUS_PASS_ADD;
8914 - data->output_args = NULL;
8915 - data->num_out_args = 0;
8919 if (debug & DEBUG_AUTHOR_FLAG)
8920 report(LOG_DEBUG, "exec denied by default");
8922 @@ -501,16 +520,15 @@ struct author_data *data;
8923 /* Is an exec command authorized per our database(s)?
8924 Return 0 if status is valid */
8926 +static int authorize_cmd TAC_ARGS((const char *user, const char *cmd, struct author_data *data));
8929 authorize_cmd(user, cmd, data)
8933 struct author_data *data;
8939 - args = assemble_args(data);
8942 data->status = AUTHOR_STATUS_ERROR;
8943 @@ -520,93 +538,41 @@ struct author_data *data;
8947 - node = cfg_get_cmd_node(user, cmd, TAC_PLUS_RECURSE);
8949 - /* The command does not exist. Do the default */
8952 - if (cfg_user_svc_default_is_permit(user)) {
8954 - if (debug & DEBUG_AUTHOR_FLAG)
8955 - report(LOG_DEBUG, "cmd %s does not exist, permitted by default",
8958 - data->status = AUTHOR_STATUS_PASS_ADD;
8959 - data->num_out_args = 0;
8965 - if (debug & DEBUG_AUTHOR_FLAG)
8966 - report(LOG_DEBUG, "cmd %s does not exist, denied by default",
8969 - data->status = AUTHOR_STATUS_FAIL;
8970 - data->num_out_args = 0;
8976 - /* The command exists. The default if nothing matches is DENY */
8977 - data->status = AUTHOR_STATUS_FAIL;
8978 - data->num_out_args = 0;
8980 - for (node=node->value1; node && args; node = node->next) {
8981 - match = regexec((regexp *) node->value1, args);
8983 - if (debug & DEBUG_AUTHOR_FLAG) {
8984 - report(LOG_INFO, "line %d compare %s %s '%s' & '%s' %smatch",
8986 - node->type == N_permit ? "permit" : "deny",
8987 - node->value, args, (match ? "" : "no "));
8992 + args = assemble_args(data);
8993 + switch (cfg_authorize_cmd(user, cmd, args)) {
8995 - switch (node->type) {
8997 - if (debug & DEBUG_AUTHOR_FLAG) {
8998 - report(LOG_DEBUG, "%s %s permitted by line %d",
8999 - cmd, args, node->line);
9002 data->status = AUTHOR_STATUS_PASS_ADD;
9003 data->num_out_args = 0;
9006 - if (debug & DEBUG_AUTHOR_FLAG) {
9007 - report(LOG_DEBUG, "%s %s denied by line %d",
9008 - cmd, args, node->line);
9012 data->status = AUTHOR_STATUS_FAIL;
9013 data->num_out_args = 0;
9018 data->status = AUTHOR_STATUS_ERROR;
9019 - data->admin_msg = tac_strdup("Server error illegal configuration node");
9020 - report(LOG_ERR, "%s: %s %s %s",
9021 - session.peer, cmd, args, data->admin_msg);
9022 + data->admin_msg = tac_strdup("Server error illegal configuration");
9037 +static int is_separator TAC_ARGS((int ch));
9042 +int ch; /* promoted "char" type */
9044 return (ch == '=' || ch == '*');
9047 +static int arg_ok TAC_ARGS((char *arg));
9049 /* check an attr=value pair for well-formedness */
9052 @@ -630,6 +596,8 @@ char *arg;
9056 +static int match_attrs TAC_ARGS((char *nas_arg, char *server_arg));
9058 /* return 1 if attrs match, 0 otherwise */
9060 match_attrs(nas_arg, server_arg)
9061 @@ -647,6 +615,8 @@ char *nas_arg, *server_arg;
9065 +static int match_values TAC_ARGS((char *nas_arg, char *server_arg));
9067 /* return 1 if values match, 0 otherwise */
9069 match_values(nas_arg, server_arg)
9070 @@ -671,6 +641,8 @@ char *nas_arg, *server_arg;
9071 return(STREQ(nas_arg, server_arg));
9074 +static int mandatory TAC_ARGS((char *arg));
9076 /* Return 1 if arg is mandatory, 0 otherwise */
9079 @@ -690,6 +662,8 @@ char *arg;
9083 +static int optional TAC_ARGS((char *arg));
9088 @@ -699,21 +673,16 @@ char *arg;
9090 /* PPP-LCP requests are a special case. If they are not explicitly
9091 configured, but there are other ppp services explicitly configured,
9092 - we admit (return 0) any PPP-LCP request */
9093 + we admit (return 1) any PPP-LCP request */
9095 +static int ppp_lcp_allowed TAC_ARGS((const char *user));
9098 -ppp_lcp_allowed(svc, protocol, user)
9100 - char *user, *protocol;
9101 +ppp_lcp_allowed(user)
9104 - /* This is not a ppp/lcp request. Just Say No */
9105 - if (!(svc == N_svc_ppp &&
9107 - STREQ(protocol, "lcp")))
9110 - /* It is an LCP request. Are there PPP services configured */
9111 - if (cfg_ppp_is_configured(user, TAC_PLUS_RECURSE)) {
9112 + /* It is an LCP request. Are there PPP services configured? */
9113 + if (cfg_get_svc_node(user, N_svc_ppp, NULL /* protocol */, NULL /* svcname */, TAC_PLUS_RECURSE, NULL /* nodep */)) {
9114 if (debug & DEBUG_AUTHOR_FLAG) {
9116 "ppp/lcp request permitted (ppp is configured for %s)",
9117 @@ -730,14 +699,16 @@ ppp_lcp_allowed(svc, protocol, user)
9121 +static int authorize_svc TAC_ARGS((const char *user, int svc, const char *protocol, const char *svcname, struct author_data *data));
9123 /* Return 0 means data->status is valid */
9125 authorize_svc(user, svc, protocol, svcname, data)
9129 - struct author_data *data;
9130 - char *protocol; /* valid only if svc == ppp */
9133 +const char *svcname;
9134 +struct author_data *data;
9135 +const char *protocol; /* valid only if svc == ppp */
9138 char **out_args, **outp;
9139 @@ -747,20 +718,23 @@ authorize_svc(user, svc, protocol, svcname, data)
9141 int deny_by_default;
9143 + int service_permit;
9149 /* Does this service exist? */
9150 - node = cfg_get_svc_node(user, svc, protocol, svcname, TAC_PLUS_RECURSE);
9151 + service_permit = cfg_get_svc_node(user, svc, protocol, svcname, TAC_PLUS_RECURSE, &node);
9154 - /* Service not found. If the default is permit, or this is an
9155 - PPP/LCP request and other ppp services are configured,
9156 - we'll allow it. */
9157 + /* Now we may have three cases:
9158 + * service_permit == 1 && node != NULL
9159 + * service_permit == 1 && node == NULL
9160 + * service_permit == 0 (BTW node == NULL)
9163 - if (cfg_user_svc_default_is_permit(user)) {
9164 + if (service_permit && !node) {
9165 + /* Service not found and the default is permit, we'll allow it. */
9167 if (debug & DEBUG_AUTHOR_FLAG)
9169 @@ -775,7 +749,13 @@ authorize_svc(user, svc, protocol, svcname, data)
9173 - if (ppp_lcp_allowed(svc, protocol, user)) {
9174 + if (!service_permit) {
9175 + /* Service not found, if this is an
9176 + PPP/LCP request and other ppp services are configured,
9177 + we'll allow it. */
9179 + if (svc == N_svc_ppp && protocol && STREQ(protocol, "lcp")
9180 + && ppp_lcp_allowed(user)) {
9181 data->status = AUTHOR_STATUS_PASS_ADD;
9182 data->num_out_args = 0;
9183 data->output_args = NULL;
9184 @@ -1200,6 +1180,8 @@ authorize_svc(user, svc, protocol, svcname, data)
9188 +static int get_nas_svc TAC_ARGS((struct author_data *data, char **cmdname, char **protocol, char **svcname));
9191 get_nas_svc(data, cmdname, protocol, svcname)
9192 struct author_data *data;
9193 diff --git a/do_author.h b/do_author.h
9194 new file mode 100644
9195 index 0000000..08bea16
9199 +#ifndef DO_AUTHOR_H
9200 +#define DO_AUTHOR_H 1
9202 +#include "tac_plus.h"
9206 + * This structure describes a principal that is to be authenticated.
9207 + * username is the principals name (ASCII, null terminated)
9208 + * NAS_name is the name of the NAS where the user is
9209 + * NAS_port is the port on the NAS where the user is
9210 + * NAC_address is the remote user location. This may be
9211 + * a remote IP address or a caller-ID or ...
9212 + * priv_lvl user's requested privilege level.
9219 + char *NAC_address;
9225 + * This structure is the data structure for passing information to
9226 + * and from the authorization function (do_author()).
9228 +struct author_data {
9229 + struct identity *id; /* user id */
9230 + int authen_method; /* authentication method */
9232 +#define AUTHEN_METH_NONE 0x01
9233 +#define AUTHEN_METH_KRB5 0x02
9234 +#define AUTHEN_METH_LINE 0x03
9235 +#define AUTHEN_METH_ENABLE 0x04
9236 +#define AUTHEN_METH_LOCAL 0x05
9237 +#define AUTHEN_METH_TACACSPLUS 0x06
9238 +#define AUTHEN_METH_RCMD 0x20
9240 + int authen_type; /* authentication type see authen_type */
9241 + int service; /* calling service */
9242 + char *msg; /* optional NULL-terminated return message */
9243 + char *admin_msg; /* optional NULL-terminated admin message */
9244 + int status; /* return status */
9246 +#define AUTHOR_STATUS_PASS_ADD 0x01
9247 +#define AUTHOR_STATUS_PASS_REPL 0x02
9248 +#define AUTHOR_STATUS_FAIL 0x10
9249 +#define AUTHOR_STATUS_ERROR 0x11
9251 + int num_in_args; /* input arg count */
9252 + char **input_args; /* input arguments */
9253 + int num_out_args; /* output arg cnt */
9254 + char **output_args; /* output arguments */
9259 +extern int do_author TAC_ARGS((struct author_data *data));
9262 +#endif /* DO_AUTHOR_H */
9263 diff --git a/dump.c b/dump.c
9264 index ae58e5e..511085b 100644
9268 FITNESS FOR A PARTICULAR PURPOSE.
9272 #include "tac_plus.h"
9274 +#include <netinet/in.h> /* for ntohl() */
9277 +#include "report.h"
9279 +#include "packet.h"
9280 +#include "do_author.h"
9284 +char *summarise_outgoing_packet_type TAC_ARGS((u_char *pak));
9286 /* Routines for dumping packets to stderr */
9288 summarise_outgoing_packet_type(pak)
9289 @@ -90,7 +103,9 @@ u_char *pak;
9294 +static void dump_header TAC_ARGS((u_char *pak));
9300 @@ -117,7 +132,10 @@ u_char *pak;
9304 +void dump_nas_pak TAC_ARGS((u_char *pak));
9306 /* Dump packets originated by a NAS */
9311 @@ -376,6 +394,9 @@ u_char *pak;
9313 /* Dump packets originated by Tacacsd */
9315 +void dump_tacacs_pak TAC_ARGS((u_char *pak));
9318 dump_tacacs_pak(pak)
9321 @@ -482,6 +503,8 @@ u_char *pak;
9322 report(LOG_DEBUG, "End packet");
9325 +char *summarise_incoming_packet_type TAC_ARGS((u_char *pak));
9327 /* summarise packet types for logging routines. */
9329 summarise_incoming_packet_type(pak)
9330 diff --git a/dump.h b/dump.h
9331 new file mode 100644
9332 index 0000000..bddce30
9339 +#include "tac_plus.h"
9341 +#include <sys/types.h> /* for u_* */
9344 +extern char *summarise_outgoing_packet_type TAC_ARGS((u_char *pak));
9345 +extern void dump_nas_pak TAC_ARGS((u_char *pak));
9346 +extern void dump_tacacs_pak TAC_ARGS((u_char *pak));
9347 +extern char *summarise_incoming_packet_type TAC_ARGS((u_char *pak));
9350 +#endif /* DUMP_H */
9351 diff --git a/enable.c b/enable.c
9352 index 63a17eb..3e56c92 100644
9356 FITNESS FOR A PARTICULAR PURPOSE.
9360 #include "tac_plus.h"
9362 +#include <stdlib.h>
9363 +#include <string.h>
9365 +#include "enable.h"
9368 +#include "report.h"
9370 +#include "choose_authen.h" /* for "struct authen_data" */
9371 +#include "do_author.h" /* for "struct identity" */
9372 +#include "packet.h"
9374 +#include "cfgfile.h"
9377 /* internal state variables */
9378 #define STATE_AUTHEN_START 0 /* no requests issued */
9379 @@ -30,6 +45,8 @@ struct private_data {
9383 +static void enable TAC_ARGS((char *passwd, struct authen_data *data));
9386 enable(passwd, data)
9388 @@ -84,6 +101,8 @@ struct authen_data *data;
9389 * Return 0 if data->status is valid, otherwise 1
9392 +int enable_fn TAC_ARGS((struct authen_data *data));
9396 struct authen_data *data;
9397 diff --git a/enable.h b/enable.h
9398 new file mode 100644
9399 index 0000000..10a4e8a
9406 +#include "tac_plus.h"
9409 +struct authen_data;
9411 +extern int enable_fn TAC_ARGS((struct authen_data *data));
9414 +#endif /* ENABLE_H */
9415 diff --git a/encrypt.c b/encrypt.c
9416 index 60ba5e9..2840916 100644
9420 FITNESS FOR A PARTICULAR PURPOSE.
9424 #include "tac_plus.h"
9426 +#include <stdlib.h>
9427 +#include <netinet/in.h> /* for ntohl() */
9429 +#include "encrypt.h"
9432 +#include "report.h"
9433 +#include "packet.h"
9438 * create_md5_hash(): create an md5 hash of the "session_id", "the user's
9444 +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));
9447 create_md5_hash(session_id, key, version, seq_no, prev_hash, hash)
9453 +unsigned version; /* promoted "u_char" type */
9454 +unsigned seq_no; /* promoted "u_char" type */
9458 u_char *md_stream, *mdp;
9461 + u_char version_uchar = version;
9462 + u_char seq_no_uchar = seq_no;
9464 - md_len = sizeof(session_id) + strlen(key) + sizeof(version) +
9466 + md_len = sizeof(session_id) + strlen(key) + sizeof(version_uchar) +
9467 + sizeof(seq_no_uchar);
9471 @@ -62,11 +77,11 @@ u_char *hash;
9472 bcopy(key, mdp, strlen(key));
9475 - bcopy(&version, mdp, sizeof(version));
9476 - mdp += sizeof(version);
9477 + bcopy(&version_uchar, mdp, sizeof(version_uchar));
9478 + mdp += sizeof(version_uchar);
9480 - bcopy(&seq_no, mdp, sizeof(seq_no));
9481 - mdp += sizeof(seq_no);
9482 + bcopy(&seq_no_uchar, mdp, sizeof(seq_no_uchar));
9483 + mdp += sizeof(seq_no_uchar);
9486 bcopy(prev_hash, mdp, MD5_LEN);
9487 @@ -90,10 +105,13 @@ u_char *hash;
9488 * Return 0 on success, -1 on failure.
9491 +int md5_xor TAC_ARGS((HDR *hdr, u_char *data, const char *key));
9494 md5_xor(hdr, data, key)
9501 u_char hash[MD5_LEN]; /* the md5 hash */
9502 diff --git a/encrypt.h b/encrypt.h
9503 new file mode 100644
9504 index 0000000..9c7ae53
9509 +#define ENCRYPT_H 1
9511 +#include "tac_plus.h"
9513 +#include <sys/types.h> /* for u_* */
9515 +#include "packet.h" /* for "HDR" */
9518 +extern int md5_xor TAC_ARGS((HDR *hdr, u_char *data, const char *key));
9521 +#endif /* ENCRYPT_H */
9522 diff --git a/expire.c b/expire.c
9523 index 1ef745c..3aed354 100644
9527 FITNESS FOR A PARTICULAR PURPOSE.
9531 #include "tac_plus.h"
9535 +#include <string.h>
9542 * check a date for expiry. If the field specifies
9543 * a shell return PW_OK
9544 @@ -37,9 +45,11 @@ static char *monthname[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
9545 static long days_ere_month[] = {0, 31, 59, 90, 120, 151,
9546 181, 212, 243, 273, 304, 334};
9548 +int check_expiration TAC_ARGS((const char *date));
9551 check_expiration(date)
9555 long day, month, year, leaps, now, expiration, warning;
9557 @@ -52,11 +62,11 @@ char *date;
9560 /* Parse date string. Fail it upon error. */
9561 - if (sscanf(date, "%s %d %d", monthstr, &day, &year) != 3)
9562 + if (sscanf(date, "%s %ld %ld", monthstr, &day, &year) != 3)
9563 return (PW_EXPIRED);
9565 for(i=0; i < 3; i++) {
9566 - monthstr[i] = toupper(monthstr[i]);
9567 + monthstr[i] = toupper((int) monthstr[i]);
9570 /* Compute the expiration date in days. */
9571 diff --git a/expire.h b/expire.h
9572 index c7df48d..6e7fc5e 100644
9579 +#include "tac_plus.h"
9582 Copyright (c) 1995-1998 by Cisco systems, Inc.
9585 FITNESS FOR A PARTICULAR PURPOSE.
9589 #define PW_OK 0 /* pw not expired and not due to expire soon */
9590 #define PW_EXPIRED 1 /* pw has expired */
9591 #define PW_EXPIRING 2 /* pw will expire soon */
9593 #define MAX_PASSWD_LEN 256
9595 -extern int check_expiration();
9597 +extern int check_expiration TAC_ARGS((const char *date));
9600 +#endif /* EXPIRE_H */
9601 diff --git a/generate_passwd.c b/generate_passwd.c
9602 index 509e48a..a21098d 100644
9603 --- a/generate_passwd.c
9604 +++ b/generate_passwd.c
9611 +#ifdef HAVE_CONFIG_H
9612 +#include "config.h"
9616 +#ifdef HAVE_UNISTD_H
9617 +#include <unistd.h>
9619 +#include <stdlib.h>
9622 +#include <string.h>
9626 +#define NULL ((void *) 0)
9629 +/* Stolen from pbmplus.h of netpbm: */
9632 +#define TAC_ARGS(alist) alist
9634 +#define TAC_ARGS(alist) ()
9635 +#endif /*__STDC__*/
9638 +int main TAC_ARGS((int argc, char **argv));
9646 char pass[25], *salt, buf[24];
9649 @@ -42,10 +71,10 @@ char **argv;
9651 write(1, prompt, strlen(prompt));
9652 n = read(0, pass, sizeof(pass));
9658 + int i, r, r1 = 0 /* GCC paranoia */, r2 = 0 /* GCC paranoia */;
9662 @@ -82,9 +111,6 @@ char **argv;
9664 write(1, result, strlen(result));
9672 + return (EXIT_SUCCESS);
9674 diff --git a/hash.c b/hash.c
9675 index 443d42b..2db807b 100644
9679 FITNESS FOR A PARTICULAR PURPOSE.
9683 #include "tac_plus.h"
9694 -typedef struct entry ENTRY;
9695 +static int calculate_hash TAC_ARGS((const char *name));
9697 /* Calculate hash value from a string */
9699 calculate_hash(name)
9704 int len = strlen(name);
9705 @@ -43,12 +48,14 @@ char *name;
9709 +void *hash_lookup TAC_ARGS((void **hashtab, const char *name));
9711 /* Lookup a name in a hash table. Return its node if it exists, NULL
9714 hash_lookup(hashtab, name)
9720 int hashval = calculate_hash(name);
9721 @@ -64,6 +71,8 @@ char *name;
9725 +void *hash_add_entry TAC_ARGS((void **hashtab, ENTRY *newentry));
9727 /* Add a node to a hash table. Return node if it exists, NULL
9730 @@ -86,6 +95,8 @@ ENTRY *newentry;
9734 +void **hash_get_entries TAC_ARGS((void **hashtab));
9736 /* Return an array of pointers to all the entries in a hash table */
9738 hash_get_entries(hashtab)
9739 diff --git a/hash.h b/hash.h
9740 new file mode 100644
9741 index 0000000..a808f05
9748 +#include "tac_plus.h"
9751 +#define HASH_TAB_SIZE 157 /* user and group hash table sizes */
9753 +typedef struct entry ENTRY;
9756 +extern void *hash_lookup TAC_ARGS((void **hashtab, const char *name));
9757 +extern void *hash_add_entry TAC_ARGS((void **hashtab, ENTRY *newentry));
9758 +extern void **hash_get_entries TAC_ARGS((void **hashtab));
9761 +#endif /* HASH_H */
9762 diff --git a/ldap_author.c b/ldap_author.c
9763 index ca1a8ef..c788e82 100644
9766 @@ -36,21 +36,30 @@ Port name isn't required.. I would like to change format with :
9770 -#if defined(USE_LDAP)
9771 +#include "tac_plus.h"
9777 +#include <stdlib.h>
9780 #include <ldap_cdefs.h>
9782 -#include "tac_plus.h"
9784 +#include "ldap_author.h"
9787 +#include "report.h"
9790 +int ldap_verify TAC_ARGS((const char *user, const char *users_passwd, const char *str_conn));
9793 ldap_verify(user, users_passwd, str_conn)
9794 -char *user, *users_passwd; /* Username and gived password */
9795 -char *str_conn; /* String connection to database */
9796 +const char *user; /* username ... */
9797 +const char *users_passwd; /* ... and given password */
9798 +const char *str_conn; /* string connection to database */
9802 @@ -62,11 +71,7 @@ char *str_conn; /* String connection to database */
9803 /* Don't allow null username and passwd */
9804 if ( *user == '0' || *users_passwd == '0' ) return (1);
9806 - buf=(char *)malloc(strlen(str_conn)+1);
9807 - if (buf == NULL ){
9808 - report(LOG_DEBUG, "Error can't allocate memory");
9811 + buf = (char *) tac_malloc(strlen(str_conn)+1);
9813 strcpy(buf,str_conn);
9814 ldapServer=strstr(buf, "://");
9815 @@ -99,7 +104,7 @@ char *str_conn; /* String connection to database */
9819 - err=ldap_simple_bind_s(ld, user, users_passwd);
9820 + err=ldap_simple_bind_s(ld, (/* de-const */ char *) user, (/* de-const */ char *) users_passwd);
9822 if(err != LDAP_SUCCESS)
9824 @@ -116,4 +121,9 @@ char *str_conn; /* String connection to database */
9830 +#else /* USE_LDAP */
9832 +TAC_SOURCEFILE_EMPTY
9834 +#endif /* USE_LDAP */
9835 diff --git a/ldap_author.h b/ldap_author.h
9836 index 6479426..ecd71dd 100644
9841 +#ifndef LDAP_AUTHOR_H
9842 +#define LDAP_AUTHOR_H 1
9844 +#include "tac_plus.h"
9849 +extern int ldap_verify TAC_ARGS((const char *user, const char *users_passwd, const char *str_conn));
9852 +#endif /* USE_LDAP */
9854 +#endif /* LDAP_AUTHOR_H */
9855 diff --git a/main.c b/main.c
9856 index cf0ffd8..c356b75 100644
9860 * distribution of the program without specific prior permission, and
9861 * notice be given in supporting documentation that modification,
9862 * copying and distribution is by permission of Cisco Systems, Inc.
9865 * Cisco Systems, Inc. makes no representations about the suitability
9866 * of this software for any purpose. THIS SOFTWARE IS PROVIDED ``AS
9867 * IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
9869 * FITNESS FOR A PARTICULAR PURPOSE.
9873 #include "tac_plus.h"
9874 -#include "sys/wait.h"
9875 -#include "signal.h"
9877 +#include <stdlib.h>
9878 +#include <sys/wait.h>
9879 +#include <signal.h>
9880 +#include <sys/socket.h>
9881 +#include <netinet/in.h>
9882 +#include <arpa/inet.h>
9883 +#include <sys/types.h>
9884 +#include <sys/stat.h>
9887 +#ifdef HAVE_SYS_TIME_H
9888 +#include <sys/time.h>
9890 +#ifdef HAVE_UNISTD_H
9891 +#include <unistd.h>
9893 +#ifdef HAVE_SYSLOG_H
9894 +#include <syslog.h>
9896 +#ifdef HAVE_SYS_SYSLOG_H
9897 +#include <sys/syslog.h>
9899 +#ifdef HAVE_FCNTL_H
9902 +#ifdef HAVE_SYS_IOCTL_H
9903 +#include <sys/ioctl.h>
9907 +#include "report.h"
9909 +#include "cfgfile.h"
9910 +#include "packet.h"
9912 +#include "author.h"
9914 +#include "authen.h"
9915 +#include "do_acct.h"
9919 +#include "maxsess.h"
9923 +static void version TAC_ARGS((void));
9924 +static void start_session TAC_ARGS((void));
9930 +#ifndef TAC_PLUS_PORT
9931 +#define TAC_PLUS_PORT 49
9935 static int standalone = 1; /* running standalone (1) or under inetd (0) */
9936 static int initialised = 0; /* data structures have been allocated */
9937 int sendauth_only = 0; /* don't respond to sendpass requests */
9938 int debug = 0; /* debugging flags */
9939 -int port = 0; /* port we're listening on */
9940 +static int port = 0; /* port we're listening on */
9941 int console = 0; /* write all syslog messages to console */
9942 int parse_only = 0; /* exit after verbose parsing */
9943 int single = 0; /* single thread (for debugging) */
9944 -int wtmpfd = 0; /* for wtmp file logging */
9945 -char *wtmpfile = NULL;
9947 -struct timeval started_at;
9949 struct session session; /* session data */
9951 static char pidfilebuf[75]; /* holds current name of the pidfile */
9953 -void start_session();
9961 -#endif /* VOIDSIG */
9963 +static RETSIGTYPE reapchild TAC_ARGS((int signo));
9971 @@ -61,6 +111,8 @@ reapchild()
9975 + signal(SIGCHLD, reapchild);
9978 pid = wait3(&status, WNOHANG, 0);
9980 @@ -71,6 +123,8 @@ reapchild()
9982 #endif /* REAPCHILD */
9984 +static void die TAC_ARGS((int signum));
9989 @@ -80,6 +134,8 @@ int signum;
9993 +static void init TAC_ARGS((void));
9998 @@ -104,26 +160,59 @@ init()
10002 - report(LOG_INFO, "Version %s Initialized %d", VERSION, initialised);
10003 + report(LOG_INFO, "Version %s%s Initialized %d", VERSION, VERSION_TAIL, initialised);
10008 +/* 'handler()' will be called during initialization to setup signal handler,
10009 + * keep it in mind when modifying it!
10012 +static int handler_occured = 0;
10014 +static RETSIGTYPE handler TAC_ARGS((int signum));
10020 - report(LOG_INFO, "Received signal %d", signum);
10022 -#ifdef REARMSIGNAL
10023 + /* never execute any non-trivial (=system-call) commands here
10024 + * as it may immediately abort the whole 'handler()' (SYSV signal).
10025 + * We hope that SA_RESTART is NOT set for our signals
10027 + handler_occured = 1;
10028 + /* It is never wrong to reinstall 'handler' just to be safe */
10029 signal(SIGUSR1, handler);
10030 - signal(SIGHUP, handler);
10031 -#endif REARMSIGNAL
10032 + signal(SIGHUP , handler);
10034 + /* DON'T interrupt! */
10035 +#ifdef HAVE_SIGINTERRUPT
10036 + siginterrupt(SIGUSR1, 0 /* flag */);
10037 + siginterrupt(SIGHUP , 0 /* flag */);
10041 +static void check_handler_occured TAC_ARGS((void));
10044 +check_handler_occured()
10047 + if (!handler_occured)
10050 + handler_occured = 0;
10051 + report(LOG_INFO, "Signal detected, reloading configuration");
10056 * Return a socket bound to an appropriate port number/address. Exits
10057 * the program on failure */
10059 +static int get_socket TAC_ARGS((void));
10065 @@ -171,6 +260,8 @@ get_socket()
10069 +static void open_logfile TAC_ARGS((void));
10074 @@ -182,6 +273,29 @@ open_logfile()
10075 setlogmask(LOG_UPTO(LOG_DEBUG));
10078 +static void prep_session_peer TAC_ARGS((const struct sockaddr_in *from));
10081 +prep_session_peer(from)
10082 +const struct sockaddr_in *from;
10084 + struct hostent *hp;
10086 + if (session.peer_addr && session.peer_addr != session.peer)
10087 + free(session.peer_addr);
10088 + if (session.peer)
10089 + free(session.peer);
10091 + session.peer_addr = tac_strdup( (char *) inet_ntoa(from->sin_addr) );
10093 + hp = gethostbyaddr((char *) &from->sin_addr.s_addr, sizeof(from->sin_addr.s_addr), AF_INET);
10096 + session.peer = tac_strdup(hp->h_name);
10098 + session.peer = session.peer_addr;
10104 @@ -189,6 +303,9 @@ open_logfile()
10105 * Parse arguments and act appropiately.
10108 +int main TAC_ARGS((int argc, char **argv));
10114 @@ -214,6 +331,10 @@ char **argv;
10115 port = TAC_PLUS_PORT;
10118 +#ifdef MAINTAINER_MODE
10119 + session.cfgfile = "/etc/tacacs/tac_plus.cfg";
10123 fprintf(stderr, "Usage: tac_plus -C <configuration file>\n");
10124 fprintf(stderr, "\t[ -t ] [ -P ] [ -g ] [ -p <port> ]\n");
10125 @@ -284,8 +405,9 @@ char **argv;
10129 - signal(SIGUSR1, handler);
10130 - signal(SIGHUP, handler);
10131 + handler(-1 /* signum */); /* connect to the signals */
10132 + handler_occured = 0; /* post-fix cludge */
10134 signal(SIGTERM, die);
10135 signal(SIGPIPE, SIG_IGN);
10137 @@ -293,31 +415,27 @@ char **argv;
10141 - report(LOG_DEBUG, "tac_plus server %s starting", VERSION);
10142 + report(LOG_DEBUG, "tac_plus server %s%s starting", VERSION, VERSION_TAIL);
10145 /* running under inetd */
10146 struct sockaddr_in name;
10149 + socklen_t name_len;
10151 + int fionbio_on = 1;
10154 name_len = sizeof(name);
10156 - session.sock = 0;
10157 if (getpeername(session.sock, (struct sockaddr *) &name, &name_len)) {
10158 report(LOG_ERR, "getpeername failure %s", sys_errlist[errno]);
10160 - struct hostent *hp;
10161 - hp = gethostbyaddr((char *) &name.sin_addr.s_addr,
10162 - sizeof(name.sin_addr.s_addr), AF_INET);
10163 - if (session.peer) {
10164 - free(session.peer);
10166 - session.peer = tac_strdup(hp ? hp->h_name :
10167 - (char *) inet_ntoa(name.sin_addr));
10169 + prep_session_peer(NULL);
10171 + prep_session_peer(&name);
10173 + session.sock = 0;
10175 - if (ioctl(session.sock, FIONBIO, &on) < 0) {
10176 + if (ioctl(session.sock, FIONBIO, &fionbio_on) < 0) {
10177 report(LOG_ERR, "ioctl(FIONBIO) %s", sys_errlist[errno]);
10180 @@ -351,23 +469,29 @@ char **argv;
10185 +#ifdef SETPGRP_VOID
10186 if (setpgrp() == -1)
10188 +#else /* SETPGRP_VOID */
10189 if (setpgrp(0, getpid()) == -1)
10190 -#endif /* LINUX */
10191 +#endif /* SETPGRP_VOID */
10192 report(LOG_ERR, "Can't change process group");
10195 c = open("/dev/tty", O_RDWR);
10197 ioctl(c, TIOCNOTTY, (char *) 0);
10201 signal(SIGCHLD, reapchild);
10203 #else /* REAPCHILD */
10205 +#ifdef SETPGRP_VOID
10206 if (setpgrp() == 1)
10207 +#else /* SETPGRP_VOID */
10208 + if (setpgrp(0, getpid()) == 1)
10209 +#endif /* SETPGRP_VOID */
10210 report(LOG_ERR, "Can't change process group");
10212 signal(SIGHUP, SIG_IGN);
10213 @@ -423,7 +547,7 @@ char **argv;
10215 /* write process id to pidfile */
10216 if ((fp = fopen(pidfilebuf, "w")) != NULL) {
10217 - fprintf(fp, "%d\n", getpid());
10218 + fprintf(fp, "%d\n", (int) getpid());
10221 report(LOG_ERR, "Cannot write pid to %s %s",
10222 @@ -446,38 +570,45 @@ char **argv;
10223 #endif /* MAXSESS */
10225 report(LOG_DEBUG, "uid=%d euid=%d gid=%d egid=%d s=%d",
10226 - getuid(), geteuid(), getgid(), getegid(), s);
10227 + (int) getuid(), (int) geteuid(), (int) getgid(), (int) getegid(), s);
10231 struct sockaddr_in from;
10233 + socklen_t from_len;
10235 - struct hostent *hp = NULL;
10237 + check_handler_occured();
10239 bzero((char *) &from, sizeof(from));
10240 from_len = sizeof(from);
10242 + /* PERMIT interrupt of accept()! */
10243 +#ifdef HAVE_SIGINTERRUPT
10244 + siginterrupt(SIGUSR1, 1 /* flag */);
10245 + siginterrupt(SIGHUP , 1 /* flag */);
10249 newsockfd = accept(s, (struct sockaddr *) &from, &from_len);
10251 + /* DON'T interrupt! */
10252 +#ifdef HAVE_SIGINTERRUPT
10253 + siginterrupt(SIGUSR1, 0 /* flag */);
10254 + siginterrupt(SIGHUP , 0 /* flag */);
10257 + check_handler_occured();
10259 if (newsockfd < 0) {
10260 - if (errno == EINTR)
10261 + /* sometimes we may get even 'errno==0' when 'handler()' signal occured */
10262 + if (errno == EINTR || errno == 0)
10265 report(LOG_ERR, "accept: %s", sys_errlist[errno]);
10269 - if (lookup_peer) {
10270 - hp = gethostbyaddr((char *) &from.sin_addr.s_addr,
10271 - sizeof(from.sin_addr.s_addr), AF_INET);
10274 - if (session.peer) {
10275 - free(session.peer);
10277 - session.peer = tac_strdup(hp ? hp->h_name :
10278 - (char *) inet_ntoa(from.sin_addr));
10279 + prep_session_peer(&from);
10281 if (debug & DEBUG_PACKET_FLAG)
10282 report(LOG_DEBUG, "session request from %s sock=%d",
10283 @@ -521,8 +652,10 @@ getdtablesize()
10285 #endif /* GETDTABLESIZE */
10287 +static int bad_version_check TAC_ARGS((u_char *pak));
10289 /* Make sure version number is kosher. Return 0 if it is */
10292 bad_version_check(pak)
10295 @@ -555,17 +688,21 @@ u_char *pak;
10300 +static void start_session TAC_ARGS((void));
10305 - u_char *pak, *read_packet();
10310 session.seq_no = 0;
10311 session.aborted = 0;
10312 session.version = 0;
10314 + /* Now we are starting our new 'request' cycle */
10315 + cfg_request_scan_begin();
10317 pak = read_packet();
10320 @@ -608,9 +745,12 @@ start_session()
10324 +static void version TAC_ARGS((void));
10329 - fprintf(stdout, "tac_plus version %s\n", VERSION);
10330 + fprintf(stdout, "tac_plus version %s%s\n", VERSION, VERSION_TAIL);
10332 fprintf(stdout,"AIX\n");
10334 @@ -644,9 +784,6 @@ version()
10336 fprintf(stdout,"LINUX\n");
10338 -#ifdef LITTLE_ENDIAN
10339 - fprintf(stdout,"LITTLE_ENDIAN\n");
10342 fprintf(stdout,"LOG_LOCAL6\n");
10344 @@ -662,15 +799,9 @@ version()
10346 fprintf(stdout,"NETBSD\n");
10349 - fprintf(stdout,"NO_PWAGE\n");
10352 fprintf(stdout,"REAPCHILD\n");
10354 -#ifdef REARMSIGNAL
10355 - fprintf(stdout,"REARMSIGNAL\n");
10357 #ifdef SHADOW_PASSWORDS
10358 fprintf(stdout,"SHADOW_PASSWORDS\n");
10360 @@ -692,14 +823,8 @@ version()
10361 #ifdef SO_REUSEADDR
10362 fprintf(stdout,"SO_REUSEADDR\n");
10364 -#ifdef STDLIB_MALLOC
10365 - fprintf(stdout,"STDLIB_MALLOC\n");
10368 - fprintf(stdout,"STRCSPN\n");
10370 -#ifdef SYSLOG_IN_SYS
10371 - fprintf(stdout,"SYSLOG_IN_SYS\n");
10372 +#ifdef HAVE_STRCSPN
10373 + fprintf(stdout,"HAVE_STRCSPN\n");
10376 fprintf(stdout,"SYSV\n");
10377 @@ -713,15 +838,9 @@ version()
10378 #ifdef TACPLUS_USERID
10379 fprintf(stdout,"TACPLUS_USERID\n");
10382 - fprintf(stdout,"TRACE\n");
10385 fprintf(stdout,"UNIONWAIT\n");
10388 - fprintf(stdout,"VOIDSIG\n");
10391 fprintf(stdout,"_BSD1\n");
10393 diff --git a/main.h b/main.h
10394 new file mode 100644
10395 index 0000000..79c643a
10402 +#include "tac_plus.h"
10404 +#include <sys/types.h> /* for u_* */
10407 +#define NAS_PORT_MAX_LEN 255
10410 + int session_id; /* host specific unique session id */
10411 + int aborted; /* have we received an abort flag? */
10412 + int seq_no; /* seq. no. of last packet exchanged */
10413 + time_t last_exch; /* time of last packet exchange */
10414 + int sock; /* socket for this connection */
10415 + char *key; /* the key */
10416 + int keyline; /* line number key was found on */
10417 + char *peer; /* name of connected peer */
10418 + char *peer_addr; /* numerical name of connected peer */
10419 + /* it MAY (peer==peer_addr)! */
10420 + char *cfgfile; /* config file name */
10421 + char *acctfile; /* name of accounting file */
10422 + char *db_acct; /* name of db accounting string */
10423 + char port[NAS_PORT_MAX_LEN+1]; /* For error reporting */
10424 + u_char version; /* version of last packet read */
10427 +extern int debug; /* debugging flag */
10428 +extern int single; /* do not fork (for debugging) */
10429 +extern int console; /* log to console */
10430 +extern int parse_only; /* exit after parsing verbosely */
10431 +extern int sendauth_only; /* don't do sendauth */
10433 +/* Debugging flags */
10435 +#define DEBUG_PARSE_FLAG 2
10436 +#define DEBUG_FORK_FLAG 4
10437 +#define DEBUG_AUTHOR_FLAG 8
10438 +#define DEBUG_AUTHEN_FLAG 16
10439 +#define DEBUG_PASSWD_FLAG 32
10440 +#define DEBUG_ACCT_FLAG 64
10441 +#define DEBUG_CONFIG_FLAG 128
10442 +#define DEBUG_PACKET_FLAG 256
10443 +#define DEBUG_HEX_FLAG 512
10444 +#define DEBUG_MD5_HASH_FLAG 1024
10445 +#define DEBUG_XOR_FLAG 2048
10446 +#define DEBUG_CLEAN_FLAG 4096
10447 +#define DEBUG_SUBST_FLAG 8192
10448 +#define DEBUG_CFGEVAL_FLAG 16384
10449 +#define DEBUG_MAXSESS_FLAG 32768
10450 +#define DEBUG_LOCK_FLAG 65536
10453 +extern struct session session; /* the session */
10454 +extern int main TAC_ARGS((int argc, char **argv));
10457 +#endif /* MAIN_H */
10458 diff --git a/maxsess.c b/maxsess.c
10459 index 83e0815..aa81a9a 100644
10463 FITNESS FOR A PARTICULAR PURPOSE.
10467 #include "tac_plus.h"
10471 +#include <ctype.h>
10472 +#include <stdlib.h>
10473 +#include <sys/socket.h>
10474 +#include <netinet/in.h>
10475 +#include <arpa/inet.h>
10476 +#include <sys/types.h>
10477 +#include <sys/stat.h>
10478 +#ifdef HAVE_FCNTL_H
10479 +#include <fcntl.h>
10481 +#include <string.h>
10482 +#include <errno.h>
10483 +#ifdef HAVE_SYS_TIME_H
10484 +#include <sys/time.h>
10486 +#ifdef HAVE_UNISTD_H
10487 +#include <unistd.h>
10489 +#include <netdb.h>
10491 +#include "maxsess.h"
10492 +#include "report.h"
10493 +#include "utils.h"
10494 +#include "cfgfile.h"
10496 +#include "do_acct.h"
10497 +#include "parse.h"
10500 +void maxsess_loginit TAC_ARGS((void));
10506 +/* This is a shared file used to maintain a record of who's on
10508 +#define WHOLOG_DEFAULT "/var/log/tac_who.log"
10512 + * This is state kept per user/session
10515 + char username[64]; /* User name */
10516 + char NAS_name[32]; /* NAS user logged into */
10517 + char NAS_port[32]; /* ...port on that NAS */
10518 + char NAC_address[32]; /* ...IP address of NAS */
10522 char *wholog = WHOLOG_DEFAULT;
10524 * initialize wholog file for tracking of user logins/logouts from
10525 @@ -41,6 +94,8 @@ maxsess_loginit()
10529 +static char *portname TAC_ARGS((char *oldport));
10532 * Given a port description, return it in a canonical format.
10534 @@ -67,6 +122,8 @@ char *oldport;
10538 +static void write_record TAC_ARGS((char *name, FILE *fp, void *buf, int size, long int offset));
10541 * Seek to offset and write a buffer into the file pointed to by fp
10543 @@ -79,7 +136,7 @@ void *buf;
10546 if (fseek(fp, offset, SEEK_SET) < 0) {
10547 - report(LOG_ERR, "%s fd=%d Cannot seek to %d %s",
10548 + report(LOG_ERR, "%s fd=%d Cannot seek to %ld %s",
10549 name, fileno(fp), offset, sys_errlist[errno]);
10551 if (fwrite(buf, size, 1, fp) != 1) {
10552 @@ -88,6 +145,8 @@ char *name;
10556 +static void process_stop_record TAC_ARGS((struct identity *idp));
10559 process_stop_record(idp)
10560 struct identity *idp;
10561 @@ -133,6 +192,8 @@ struct identity *idp;
10565 +static void process_start_record TAC_ARGS((struct identity *idp));
10568 process_start_record(idp)
10569 struct identity *idp;
10570 @@ -215,10 +276,13 @@ struct identity *idp;
10574 +void loguser TAC_ARGS((struct acct_rec *rec));
10577 * Given a start or a stop accounting record, update the file of
10578 * records which tracks who's logged on and where.
10582 struct acct_rec *rec;
10584 @@ -260,10 +324,12 @@ struct acct_rec *rec;
10585 * Return -1 on error, eof or timeout. Otherwise return number of
10589 +static int timed_read TAC_ARGS((int fd, void *ptr, int nbytes, int timeout));
10592 timed_read(fd, ptr, nbytes, timeout)
10599 @@ -348,6 +414,8 @@ int timeout;
10600 * with a maximum possible width of 10.
10603 +static int ckfinger TAC_ARGS((char *user, char *nas, struct identity *idp));
10606 ckfinger(user, nas, idp)
10608 @@ -372,7 +440,7 @@ struct identity *idp;
10610 /* Get IP addr for the NAS */
10611 inaddr = inet_addr(nas);
10612 - if (inaddr != -1) {
10613 + if (inaddr != (u_long)-1) {
10614 /* A dotted decimal address */
10615 bcopy(&inaddr, &sin.sin_addr, sizeof(inaddr));
10616 sin.sin_family = AF_INET;
10617 @@ -492,6 +560,8 @@ struct identity *idp;
10621 +static int countusers_by_finger TAC_ARGS((struct identity *idp));
10624 * Verify how many sessions a user has according to the wholog file.
10625 * Use finger to contact each NAS that wholog says has this user
10626 @@ -565,6 +635,8 @@ struct identity *idp;
10630 +static int countuser TAC_ARGS((struct identity *idp));
10633 * Estimate how many sessions a named user currently owns by looking in
10635 @@ -604,6 +676,8 @@ struct identity *idp;
10639 +static int is_async TAC_ARGS((char *portname));
10643 * Tell if the named NAS port is an async-like device.
10644 @@ -622,6 +696,8 @@ char *portname;
10648 +int maxsess_check_count TAC_ARGS((char *user, struct author_data *data));
10651 * See if this user can have more sessions.
10653 @@ -636,7 +712,7 @@ struct author_data *data;
10654 /* No max session configured--don't check */
10657 - maxsess = cfg_get_intvalue(user, TAC_IS_USER, S_maxsess, TAC_PLUS_RECURSE);
10658 + maxsess = cfg_get_intvalue(S_user, user, S_maxsess, TAC_PLUS_RECURSE);
10660 if (debug & (DEBUG_MAXSESS_FLAG | DEBUG_AUTHOR_FLAG)) {
10661 report(LOG_DEBUG, "%s may run an unlimited number of sessions",
10662 @@ -680,13 +756,6 @@ struct author_data *data;
10664 #else /* MAXSESS */
10667 - * The following code is not needed or used. It exists solely to
10668 - * prevent compilers from "helpfully" complaining that this source
10669 - * file is empty when MAXSESS is not defined. This upsets novices
10670 - * building the software, and I get complaints
10673 -static int dummy = 0;
10674 +TAC_SOURCEFILE_EMPTY
10676 #endif /* MAXSESS */
10677 diff --git a/maxsess.h b/maxsess.h
10678 new file mode 100644
10679 index 0000000..c96d2b8
10684 +#define MAXSESS_H 1
10686 +#include "tac_plus.h"
10690 +#include "do_author.h"
10693 +/* This is a shared file used to maintain a record of who's on
10695 +extern char *wholog;
10700 +extern void maxsess_loginit TAC_ARGS((void));
10701 +extern void loguser TAC_ARGS((struct acct_rec *rec));
10702 +extern int maxsess_check_count TAC_ARGS((char *user, struct author_data *data));
10705 +#endif /* MAXSESS */
10707 +#endif /* MAXSESS_H */
10708 diff --git a/md4.c b/md4.c
10709 index d99c84c..5ac377d 100644
10712 @@ -43,19 +43,27 @@
10716 +#include "tac_plus.h"
10720 #include <string.h>
10724 #include "master.h"
10725 #include <ciscolib.h>
10729 typedef unsigned char *POINTER;
10730 typedef unsigned short int UINT2;
10731 typedef unsigned long int UINT4;
10733 -#define PROTO_LIST(list) ()
10735 +static void MD4Transform TAC_ARGS((UINT4 state[4], const unsigned char block[64]));
10736 +static void Encode TAC_ARGS((unsigned char *output, UINT4 *input, unsigned int len));
10737 +static void Decode TAC_ARGS((UINT4 *output, const unsigned char *input, unsigned int len));
10740 /* Constants for MD4Transform routine.
10742 @@ -72,12 +80,6 @@ typedef unsigned long int UINT4;
10746 -static void MD4Transform PROTO_LIST ((UINT4 [4], const unsigned char [64]));
10747 -static void Encode PROTO_LIST
10748 - ((unsigned char *, UINT4 *, unsigned int));
10749 -static void Decode PROTO_LIST
10750 - ((UINT4 *, const unsigned char *, unsigned int));
10752 static unsigned char PADDING[64] = {
10753 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10754 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10755 @@ -111,6 +113,9 @@ static unsigned char PADDING[64] = {
10757 /* MD4 initialization. Begins an MD4 operation, writing a new context.
10760 +void MD4Init TAC_ARGS((MD4_CTX *context));
10762 void MD4Init (context)
10763 MD4_CTX *context; /* context */
10765 @@ -128,6 +133,9 @@ MD4_CTX *context; /* context */
10766 operation, processing another message block, and updating the
10770 +void MD4Update TAC_ARGS((MD4_CTX *context, const unsigned char *input, unsigned int inputLen));
10772 void MD4Update (context, input, inputLen)
10773 MD4_CTX *context; /* context */
10774 const unsigned char *input; /* input block */
10775 @@ -168,6 +176,9 @@ unsigned int inputLen; /* length of input block */
10776 /* MD4 finalization. Ends an MD4 message-digest operation, writing the
10777 the message digest and zeroizing the context.
10780 +void MD4Final TAC_ARGS((unsigned char digest[16], MD4_CTX *context));
10782 void MD4Final (digest, context)
10783 unsigned char digest[16]; /* message digest */
10784 MD4_CTX *context; /* context */
10785 @@ -196,6 +207,9 @@ MD4_CTX *context; /* context */
10787 /* MD4 basic transformation. Transforms state based on block.
10790 +static void MD4Transform TAC_ARGS((UINT4 state[4], const unsigned char block[64]));
10792 static void MD4Transform (state, block)
10794 const unsigned char block[64];
10795 @@ -271,6 +285,9 @@ const unsigned char block[64];
10796 /* Encodes input (UINT4) into output (unsigned char). Assumes len is
10800 +static void Encode TAC_ARGS((unsigned char *output, UINT4 *input, unsigned int len));
10802 static void Encode (output, input, len)
10803 unsigned char *output;
10805 @@ -289,8 +306,10 @@ unsigned int len;
10806 /* Decodes input (unsigned char) into output (UINT4). Assumes len is
10809 -static void Decode (output, input, len)
10811 +static void Decode TAC_ARGS((UINT4 *output, const unsigned char *input, unsigned int len));
10813 +static void Decode (output, input, len)
10815 const unsigned char *input;
10817 @@ -301,3 +320,9 @@ unsigned int len;
10818 output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
10819 (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
10822 +#else /* MSCHAP */
10824 +TAC_SOURCEFILE_EMPTY
10826 +#endif /* MSCHAP */
10827 diff --git a/md4.h b/md4.h
10828 index d821229..38d0a81 100644
10835 +#include "tac_plus.h"
10840 Copyright (c) 1995-1998 by Cisco systems, Inc.
10843 documentation and/or software.
10849 typedef struct MD4Context {
10850 unsigned long int state[4]; /* state (ABCD) */
10851 @@ -51,11 +56,12 @@ typedef struct MD4Context {
10852 unsigned char buffer[64]; /* input buffer */
10862 -#endif /* _MD4_H_ */
10863 +extern void MD4Init TAC_ARGS((MD4_CTX *context));
10864 +extern void MD4Update TAC_ARGS((MD4_CTX *context, const unsigned char *input, unsigned int inputLen));
10865 +extern void MD4Final TAC_ARGS((unsigned char digest[16], MD4_CTX *context));
10868 +#endif /* MSCHAP */
10870 +#endif /* MD4_H */
10871 diff --git a/md5.c b/md5.c
10872 index 06225b0..32ca404 100644
10875 @@ -47,12 +47,20 @@
10876 * to contain all the information that RFC 1321's global.h contains.
10880 +#include "tac_plus.h"
10885 +static void MD5Transform TAC_ARGS((UINT4 *state, unsigned char *block));
10886 +static void Encode TAC_ARGS((unsigned char *output, UINT4 *input, unsigned int len));
10887 +static void Decode TAC_ARGS((UINT4 *output, unsigned char *input, unsigned int len));
10890 /* Constants for MD5Transform routine.
10901 -static void MD5Transform PROTO_LIST((UINT4[4], unsigned char[64]));
10902 -static void Encode PROTO_LIST
10903 - ((unsigned char *, UINT4 *, unsigned int));
10904 -static void Decode PROTO_LIST
10905 - ((UINT4 *, unsigned char *, unsigned int));
10907 -#if !defined(MD5_NEED_MEM_FUNCS)
10909 -#define MD5_memcpy(out,in,len) memcpy(out, in, len)
10910 -#define MD5_memset(ptr,val,len) memset(ptr, val, len)
10912 -#else /* !defined(MD5_NEED_MEM_FUNCS) */
10914 -static void MD5_memcpy PROTO_LIST((POINTER, POINTER, unsigned int));
10915 -static void MD5_memset PROTO_LIST((POINTER, int, unsigned int));
10917 -#endif /* !defined(MD5_NEED_MEM_FUNCS) */
10919 static unsigned char PADDING[64] = {
10920 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10921 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10922 @@ -129,6 +119,8 @@ Rotation is separate from addition to prevent recomputation.
10926 +void MD5Init TAC_ARGS((MD5_CTX *context));
10928 /* MD5 initialization. Begins an MD5 operation, writing a new context.
10931 @@ -143,6 +135,8 @@ MD5_CTX *context; /* context */
10932 context->state[3] = 0x10325476;
10935 +void MD5Update TAC_ARGS((MD5_CTX *context, unsigned char *input, unsigned int inputLen));
10937 /* MD5 block update operation. Continues an MD5 message-digest
10938 operation, processing another message block, and updating the
10940 @@ -168,8 +162,7 @@ unsigned int inputLen; /* length of input block */
10942 /* Transform as many times as possible. */
10943 if (inputLen >= partLen) {
10945 - ((POINTER) & context->buffer[index], (POINTER) input, partLen);
10946 + memcpy((POINTER) & context->buffer[index], (POINTER) input, partLen);
10947 MD5Transform(context->state, context->buffer);
10949 for (i = partLen; i + 63 < inputLen; i += 64)
10950 @@ -180,11 +173,12 @@ unsigned int inputLen; /* length of input block */
10953 /* Buffer remaining input */
10955 - ((POINTER) & context->buffer[index], (POINTER) & input[i],
10956 + memcpy((POINTER) & context->buffer[index], (POINTER) & input[i],
10960 +void MD5Final TAC_ARGS((unsigned char *digest, MD5_CTX *context));
10962 /* MD5 finalization. Ends an MD5 message-digest operation, writing the
10963 the message digest and zeroizing the context.
10965 @@ -211,9 +205,11 @@ MD5_CTX *context; /* context */
10966 Encode(digest, context->state, 16);
10968 /* Zeroize sensitive information. */
10969 - MD5_memset((POINTER) context, 0, sizeof(*context));
10970 + memset((POINTER) context, 0, sizeof(*context));
10973 +static void MD5Transform TAC_ARGS((UINT4 *state, unsigned char *block));
10975 /* MD5 basic transformation. Transforms state based on block.
10978 @@ -303,9 +299,11 @@ unsigned char block[64];
10981 /* Zeroize sensitive information. */
10982 - MD5_memset((POINTER) x, 0, sizeof(x));
10983 + memset((POINTER) x, 0, sizeof(x));
10986 +static void Encode TAC_ARGS((unsigned char *output, UINT4 *input, unsigned int len));
10988 /* Encodes input (UINT4) into output (unsigned char). Assumes len is
10991 @@ -325,6 +323,8 @@ unsigned int len;
10995 +static void Decode TAC_ARGS((UINT4 *output, unsigned char *input, unsigned int len));
10997 /* Decodes input (unsigned char) into output (UINT4). Assumes len is
11000 @@ -340,36 +340,3 @@ unsigned int len;
11001 output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) |
11002 (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24);
11005 -#if defined(MD5_NEED_MEM_FUNC)
11007 -/* Note: Replace "for loop" with standard memcpy if possible.
11010 -MD5_memcpy(output, input, len)
11017 - for (i = 0; i < len; i++)
11018 - output[i] = input[i];
11022 -/* Note: Replace "for loop" with standard memset if possible.
11025 -MD5_memset(output, value, len)
11032 - for (i = 0; i < len; i++)
11033 - ((char *) output)[i] = (char) value;
11036 -#endif /* defined(MD5_NEED_MEM_FUNC) */
11037 diff --git a/md5.h b/md5.h
11038 index 097156e..90f9021 100644
11045 +#include "tac_plus.h"
11048 Copyright (c) 1995-1998 by Cisco systems, Inc.
11051 * documentation and/or software.
11057 /* delineate the cisco changes to the RSA supplied module */
11058 #define CISCO_MD5_MODS
11059 @@ -53,16 +56,11 @@
11060 #if defined(CISCO_MD5_MODS)
11062 /* typedef a 32-bit type */
11063 -typedef unsigned long int UINT4;
11064 +typedef tac_uint32 UINT4;
11066 /* typedef a generic pointer type */
11067 typedef unsigned char *POINTER;
11069 -/* enable prototyping */
11070 -/* #define PROTO_LIST(x) x */
11071 -/* disable prototyping */
11072 -#define PROTO_LIST(x) ()
11074 #endif /* defined(CISCO_MD5_MODS) */
11077 @@ -72,10 +70,10 @@ typedef struct {
11078 unsigned char buffer[64]; /* input buffer */
11081 -void MD5Init PROTO_LIST ((MD5_CTX *));
11082 -void MD5Update PROTO_LIST
11083 - ((MD5_CTX *, unsigned char *, unsigned int));
11084 -void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
11086 +extern void MD5Init TAC_ARGS((MD5_CTX *context));
11087 +extern void MD5Update TAC_ARGS((MD5_CTX *context, unsigned char *input, unsigned int inputLen));
11088 +extern void MD5Final TAC_ARGS((unsigned char *digest, MD5_CTX *context));
11091 -#endif /* _MD5_H */
11092 +#endif /* MD5_H */
11093 diff --git a/mschap.h b/mschap.h
11094 index 192d9d2..d98b84b 100644
11099 +#define MSCHAP_H 1
11101 +#include "tac_plus.h"
11104 Copyright (c) 1995-1998 by Cisco systems, Inc.
11107 FITNESS FOR A PARTICULAR PURPOSE.
11111 #define MSCHAP_KEY "Contact Microsoft for the MSCHAP key"
11114 +#endif /* MSCHAP_H */
11115 diff --git a/packet.c b/packet.c
11116 index f3f7023..2e003d1 100644
11119 @@ -17,14 +17,51 @@
11120 FITNESS FOR A PARTICULAR PURPOSE.
11124 #include "tac_plus.h"
11126 +#include <stdlib.h>
11127 +#include <netinet/in.h> /* for ntohl() */
11128 +#include <errno.h>
11130 +#ifdef HAVE_SYS_TIME_H
11131 +#include <sys/time.h>
11133 +#include <sys/types.h>
11134 +#ifdef HAVE_UNISTD_H
11135 +#include <unistd.h>
11138 +#include "packet.h"
11139 +#include "utils.h"
11140 +#include "report.h"
11142 +#include "cfgfile.h"
11143 +#include "encrypt.h"
11145 +#include "do_author.h"
11148 +static int write_packet TAC_ARGS((u_char *pak));
11154 +#define TAC_PLUS_READ_TIMEOUT 180 /* seconds */
11155 +#define TAC_PLUS_WRITE_TIMEOUT 180 /* seconds */
11158 /* Everything to do with reading and writing packets */
11160 +void send_acct_reply TAC_ARGS((unsigned status, const char *msg, const char *data));
11162 /* send an accounting response packet */
11164 send_acct_reply(status, msg, data)
11166 - char *msg, *data;
11167 +unsigned status; /* promoted "u_char" type */
11173 @@ -73,13 +110,16 @@ send_acct_reply(status, msg, data)
11177 +void send_author_reply TAC_ARGS((unsigned status, const char *msg, const char *data, int arg_cnt, /* const */ char **args));
11179 /* send an authorization reply packet */
11181 send_author_reply(status, msg, data, arg_cnt, args)
11185 +unsigned status; /* promoted "u_char" type */
11190 +/* const */ char **args;
11194 @@ -159,8 +199,11 @@ char **args;
11195 /* Send an authentication reply packet indicating an error has
11196 occurred. msg is a null terminated character string */
11198 +void send_authen_error TAC_ARGS((const char *msg));
11201 send_authen_error(msg)
11207 @@ -176,13 +219,16 @@ char *msg;
11209 /* create and send an authentication reply packet from tacacs+ to a NAS */
11211 +void send_authen_reply TAC_ARGS((int status, const char *msg, unsigned msg_len, const unsigned char *data, unsigned data_len, unsigned flags));
11214 send_authen_reply(status, msg, msg_len, data, data_len, flags)
11222 +unsigned msg_len; /* promoted "u_short" type */
11223 +const unsigned char *data;
11224 +unsigned data_len; /* promoted "u_short" type */
11225 +unsigned flags; /* promoted "u_char" type */
11229 @@ -228,12 +274,14 @@ u_char flags;
11233 +u_char *get_authen_continue TAC_ARGS((void));
11235 /* read an authentication GETDATA packet from a NAS. Return 0 on failure */
11237 get_authen_continue()
11240 - u_char *pak, *read_packet();
11242 struct authen_cont *cont;
11245 @@ -255,10 +303,10 @@ get_authen_continue()
11246 cont->user_msg_len = ntohs(cont->user_msg_len);
11247 cont->user_data_len = ntohs(cont->user_data_len);
11249 - if (TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE +
11250 + if ((unsigned long)(TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE +
11251 cont->user_msg_len +
11252 - cont->user_data_len !=
11253 - ntohl(hdr->datalength)) {
11254 + cont->user_data_len) !=
11255 + (unsigned long) ntohl(hdr->datalength)) {
11256 char *m = "Illegally sized authentication cont packet";
11257 report(LOG_ERR, "%s: %s", session.peer, m);
11258 send_authen_error(m);
11259 @@ -278,7 +326,9 @@ get_authen_continue()
11260 * Return -1 on error, eof or timeout. Otherwise return number of
11264 +static int sockread TAC_ARGS((int fd, u_char *ptr, int nbytes, int timeout));
11267 sockread(fd, ptr, nbytes, timeout)
11270 @@ -354,7 +404,9 @@ int timeout;
11271 * Return -1 on error, eof or timeout. Otherwise return number of
11272 * bytes written. */
11275 +static int sockwrite TAC_ARGS((int fd, u_char *ptr, int bytes, int timeout));
11278 sockwrite(fd, ptr, bytes, timeout)
11281 @@ -416,16 +468,32 @@ int timeout;
11282 return (bytes - remaining);
11285 +static const char *get_session_key TAC_ARGS((void));
11287 +static const char *
11290 + const char *retval = NULL;
11292 + if ((retval = cfg_get_host_key(session.peer_addr)))
11294 + if (session.peer_addr != session.peer
11295 + && (retval = cfg_get_host_key(session.peer )))
11297 + return (session.key);
11300 /* read a packet from the wire, and decrypt it. Increment the global
11301 seq_no return NULL on failure */
11303 +u_char *read_packet TAC_ARGS((void));
11309 u_char *pkt, *data;
11313 if (debug & DEBUG_PACKET_FLAG)
11314 report(LOG_DEBUG, "Waiting for packet");
11315 @@ -451,7 +519,7 @@ read_packet()
11316 len < TAC_PLUS_HDR_SIZE || len > 0x10000) {
11318 "%s: Illegal data size: %lu\n",
11319 - session.peer, ntohl(hdr.datalength));
11320 + session.peer, (unsigned long) ntohl(hdr.datalength));
11323 pkt = (u_char *) tac_malloc(len);
11324 @@ -463,9 +531,9 @@ read_packet()
11325 data = pkt + TAC_PLUS_HDR_SIZE;
11327 /* read the rest of the packet data */
11328 - if (sockread(session.sock, data, ntohl(hdr.datalength),
11329 + if ((unsigned long)sockread(session.sock, data, ntohl(hdr.datalength),
11330 TAC_PLUS_READ_TIMEOUT) !=
11331 - ntohl(hdr.datalength)) {
11332 + (unsigned long) ntohl(hdr.datalength)) {
11333 report(LOG_ERR, "%s: start_session: bad socket read", session.peer);
11336 @@ -480,10 +548,7 @@ read_packet()
11339 /* decrypt the data portion */
11340 - if ( !(tkey=(char *)cfg_get_host_key(session.peer)) )
11341 - tkey = session.key;
11343 - if (md5_xor((HDR *)pkt, data, tkey)) {
11344 + if (md5_xor((HDR *)pkt, data, get_session_key())) {
11345 report(LOG_ERR, "%s: start_session error decrypting data",
11348 @@ -498,14 +563,16 @@ read_packet()
11352 +static int write_packet TAC_ARGS((u_char *pak));
11354 /* write a packet to the wire, encrypting it */
11359 HDR *hdr = (HDR *) pak;
11364 len = TAC_PLUS_HDR_SIZE + ntohl(hdr->datalength);
11366 @@ -513,10 +580,7 @@ u_char *pak;
11367 data = pak + TAC_PLUS_HDR_SIZE;
11369 /* encrypt the data portion */
11370 - if ( !(tkey=(char *)cfg_get_host_key(session.peer)) )
11371 - tkey = session.key;
11373 - if (md5_xor((HDR *)pak, data, tkey)) {
11374 + if (md5_xor((HDR *)pak, data, get_session_key())) {
11375 report(LOG_ERR, "%s: write_packet: error encrypting data", session.peer);
11378 @@ -528,6 +592,9 @@ u_char *pak;
11382 +void send_error_reply TAC_ARGS((int type, char *msg));
11385 send_error_reply(type, msg)
11388 diff --git a/packet.h b/packet.h
11389 new file mode 100644
11390 index 0000000..83a4d9c
11395 +#define PACKET_H 1
11397 +#include "tac_plus.h"
11399 +#include <sys/types.h> /* for u_* */
11402 +/* All tacacs+ packets have the same header format */
11404 +struct tac_plus_pak_hdr {
11407 +#define TAC_PLUS_MAJOR_VER_MASK 0xf0
11408 +#define TAC_PLUS_MAJOR_VER 0xc0
11410 +#define TAC_PLUS_MINOR_VER_0 0x0
11411 +#define TAC_PLUS_VER_0 (TAC_PLUS_MAJOR_VER | TAC_PLUS_MINOR_VER_0)
11413 +#define TAC_PLUS_MINOR_VER_1 0x01
11414 +#define TAC_PLUS_VER_1 (TAC_PLUS_MAJOR_VER | TAC_PLUS_MINOR_VER_1)
11418 +#define TAC_PLUS_AUTHEN 1
11419 +#define TAC_PLUS_AUTHOR 2
11420 +#define TAC_PLUS_ACCT 3
11422 + u_char seq_no; /* packet sequence number */
11423 + u_char encryption; /* packet is encrypted or cleartext */
11425 +#define TAC_PLUS_ENCRYPTED 0x0 /* packet is encrypted */
11426 +#define TAC_PLUS_CLEAR 0x1 /* packet is not encrypted */
11428 + int session_id; /* session identifier FIXME: Is this needed? */
11429 + int datalength; /* length of encrypted data following this
11431 + /* datalength bytes of encrypted data */
11434 +#define TAC_PLUS_HDR_SIZE 12
11436 +typedef struct tac_plus_pak_hdr HDR;
11438 +/* Authentication packet NAS sends to us */
11440 +struct authen_start {
11443 +#define TAC_PLUS_AUTHEN_LOGIN 0x1
11444 +#define TAC_PLUS_AUTHEN_CHPASS 0x2
11445 +#define TAC_PLUS_AUTHEN_SENDPASS 0x3 /* deprecated */
11446 +#define TAC_PLUS_AUTHEN_SENDAUTH 0x4
11450 +#define TAC_PLUS_PRIV_LVL_MIN 0x0
11451 +#define TAC_PLUS_PRIV_LVL_MAX 0xf
11453 + u_char authen_type;
11455 +#define TAC_PLUS_AUTHEN_TYPE_ASCII 1
11456 +#define TAC_PLUS_AUTHEN_TYPE_PAP 2
11457 +#define TAC_PLUS_AUTHEN_TYPE_CHAP 3
11458 +#define TAC_PLUS_AUTHEN_TYPE_ARAP 4
11460 +#define TAC_PLUS_AUTHEN_TYPE_MSCHAP 5
11461 +#endif /* MSCHAP */
11465 +#define TAC_PLUS_AUTHEN_SVC_LOGIN 1
11466 +#define TAC_PLUS_AUTHEN_SVC_ENABLE 2
11467 +#define TAC_PLUS_AUTHEN_SVC_PPP 3
11468 +#define TAC_PLUS_AUTHEN_SVC_ARAP 4
11469 +#define TAC_PLUS_AUTHEN_SVC_PT 5
11470 +#define TAC_PLUS_AUTHEN_SVC_RCMD 6
11471 +#define TAC_PLUS_AUTHEN_SVC_X25 7
11472 +#define TAC_PLUS_AUTHEN_SVC_NASI 8
11476 + u_char rem_addr_len;
11478 + /* <user_len bytes of char data> */
11479 + /* <port_len bytes of char data> */
11480 + /* <rem_addr_len bytes of u_char data> */
11481 + /* <data_len bytes of u_char data> */
11484 +#define TAC_AUTHEN_START_FIXED_FIELDS_SIZE 8
11486 +/* Authentication continue packet NAS sends to us */
11487 +struct authen_cont {
11488 + u_short user_msg_len;
11489 + u_short user_data_len;
11492 +#define TAC_PLUS_CONTINUE_FLAG_ABORT 0x1
11494 + /* <user_msg_len bytes of u_char data> */
11495 + /* <user_data_len bytes of u_char data> */
11498 +#define TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE 5
11500 +/* Authentication reply packet we send to NAS */
11501 +struct authen_reply {
11504 +#define TAC_PLUS_AUTHEN_STATUS_PASS 1
11505 +#define TAC_PLUS_AUTHEN_STATUS_FAIL 2
11506 +#define TAC_PLUS_AUTHEN_STATUS_GETDATA 3
11507 +#define TAC_PLUS_AUTHEN_STATUS_GETUSER 4
11508 +#define TAC_PLUS_AUTHEN_STATUS_GETPASS 5
11509 +#define TAC_PLUS_AUTHEN_STATUS_RESTART 6
11510 +#define TAC_PLUS_AUTHEN_STATUS_ERROR 7
11511 +#define TAC_PLUS_AUTHEN_STATUS_FOLLOW 0x21
11515 +#define TAC_PLUS_AUTHEN_FLAG_NOECHO 0x1
11518 + u_short data_len;
11520 + /* <msg_len bytes of char data> */
11521 + /* <data_len bytes of u_char data> */
11524 +#define TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE 6
11526 +/* An authorization request packet */
11528 + u_char authen_method;
11530 + u_char authen_type;
11535 + u_char rem_addr_len;
11536 + u_char arg_cnt; /* the number of args */
11538 + /* <arg_cnt u_chars containing the lengths of args 1 to arg n> */
11539 + /* <user_len bytes of char data> */
11540 + /* <port_len bytes of char data> */
11541 + /* <rem_addr_len bytes of u_char data> */
11542 + /* <char data for each arg> */
11545 +#define TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE 8
11547 +/* An authorization reply packet */
11548 +struct author_reply {
11552 + u_short data_len;
11554 + /* <arg_cnt u_chars containing the lengths of arg 1 to arg n> */
11555 + /* <msg_len bytes of char data> */
11556 + /* <data_len bytes of char data> */
11557 + /* <char data for each arg> */
11560 +#define TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE 6
11565 +#define TAC_PLUS_ACCT_FLAG_MORE 0x1
11566 +#define TAC_PLUS_ACCT_FLAG_START 0x2
11567 +#define TAC_PLUS_ACCT_FLAG_STOP 0x4
11568 +#define TAC_PLUS_ACCT_FLAG_WATCHDOG 0x8
11570 + u_char authen_method;
11572 + u_char authen_type;
11573 + u_char authen_service;
11576 + u_char rem_addr_len;
11577 + u_char arg_cnt; /* the number of cmd args */
11578 + /* one u_char containing size for each arg */
11579 + /* <user_len bytes of char data> */
11580 + /* <port_len bytes of char data> */
11581 + /* <rem_addr_len bytes of u_char data> */
11582 + /* char data for args 1 ... n */
11585 +#define TAC_ACCT_REQ_FIXED_FIELDS_SIZE 9
11587 +struct acct_reply {
11589 + u_short data_len;
11592 +#define TAC_PLUS_ACCT_STATUS_SUCCESS 0x1
11593 +#define TAC_PLUS_ACCT_STATUS_ERROR 0x2
11594 +#define TAC_PLUS_ACCT_STATUS_FOLLOW 0x21
11598 +#define TAC_ACCT_REPLY_FIXED_FIELDS_SIZE 5
11601 +extern void send_acct_reply TAC_ARGS((unsigned status, const char *msg, const char *data));
11602 +extern void send_author_reply TAC_ARGS((unsigned status, const char *msg, const char *data, int arg_cnt, /* const */ char **args));
11603 +extern void send_authen_error TAC_ARGS((const char *msg));
11604 +extern void send_authen_reply TAC_ARGS((int status, const char *msg, unsigned msg_len, const unsigned char *data, unsigned data_len, unsigned flags));
11605 +extern u_char *get_authen_continue TAC_ARGS((void));
11606 +extern u_char *read_packet TAC_ARGS((void));
11607 +extern void send_error_reply TAC_ARGS((int type, char *msg));
11610 +#endif /* PACKET_H */
11611 diff --git a/parse.c b/parse.c
11612 index 6ac6908..b9f3360 100644
11617 /* Keywords of the configuration language */
11620 #include "tac_plus.h"
11622 +#include "parse.h"
11623 +#include "utils.h"
11624 +#include "report.h"
11628 static void *wordtable[HASH_TAB_SIZE]; /* Table of keyword declarations */
11631 @@ -31,6 +38,8 @@ struct keyword {
11633 typedef struct keyword KEYWORD;
11635 +static void declare TAC_ARGS((char *name, int value));
11638 declare(name, value)
11640 @@ -53,6 +62,8 @@ declare(name, value)
11642 /* Declare keywords of the "configuration language". */
11644 +void parser_init TAC_ARGS((void));
11649 @@ -85,7 +96,6 @@ parser_init()
11650 declare("group", S_group);
11651 declare("global", S_global);
11652 declare("host", S_host);
11653 - declare("type", S_type);
11654 declare("ip", S_ip);
11655 declare("ipx", S_ipx);
11656 declare("key", S_key);
11657 @@ -115,12 +125,23 @@ parser_init()
11658 declare("service", S_svc);
11659 declare("user", S_user);
11660 declare("time", S_time);
11661 + declare("and", S_and);
11662 + declare("closeparen", S_closeparen);
11663 + declare("enlist", S_enlist);
11664 + declare("first", S_first);
11665 + declare("not", S_not);
11666 + declare("openparen", S_openparen);
11667 + declare("or", S_or);
11668 + declare("recursive", S_recursive);
11669 + declare("when", S_when);
11672 +int keycode TAC_ARGS((const char *keyword));
11674 /* Return a keyword code if a keyword is recognized. 0 otherwise */
11678 +const char *keyword;
11680 KEYWORD *k = hash_lookup(wordtable, keyword);
11682 @@ -129,7 +150,9 @@ char *keyword;
11683 return (S_unknown);
11687 +const char *codestring TAC_ARGS((int type));
11693 @@ -156,8 +179,6 @@ int type;
11702 @@ -250,5 +271,23 @@ int type;
11708 + case S_closeparen:
11711 + return("enlist");
11716 + case S_openparen:
11720 + case S_recursive:
11721 + return("recursive");
11726 diff --git a/parse.h b/parse.h
11727 index e5be7f7..34d72ee 100644
11734 +#include "tac_plus.h"
11737 Copyright (c) 1995-1998 by Cisco systems, Inc.
11740 FITNESS FOR A PARTICULAR PURPOSE.
11743 -/* Dummy password, if nopasswd is specified */
11744 -extern char *nopasswd_str;
11746 /* Keywords & values */
11748 @@ -82,9 +85,24 @@ extern char *nopasswd_str;
11750 #define S_db_accounting 45
11758 +#define S_closeparen 50
11759 +#define S_enlist 51
11760 +#define S_first 52
11762 +#define S_openparen 54
11764 +#define S_recursive 56
11768 +extern void parser_init TAC_ARGS((void));
11769 +extern int keycode TAC_ARGS((const char *keyword));
11770 +extern const char *codestring TAC_ARGS((int type));
11773 +#endif /* PARSE_H */
11774 diff --git a/programs.c b/programs.c
11775 index bce0178..ac42b23 100644
11778 @@ -19,10 +19,29 @@
11780 /* Routines to fork children and communicate with them via pipes */
11783 #include "tac_plus.h"
11784 -#include "sys/wait.h"
11786 +#include <ctype.h>
11787 +#include <stdlib.h>
11788 +#include <sys/wait.h>
11789 +#ifdef HAVE_UNISTD_H
11790 #include <unistd.h>
11791 -#include "signal.h"
11793 +#include <signal.h>
11794 +#ifdef HAVE_SYSLOG_H
11795 +#include <syslog.h>
11797 +#ifdef HAVE_SYS_SYSLOG_H
11798 +#include <sys/syslog.h>
11801 +#include "programs.h"
11802 +#include "utils.h"
11803 +#include "report.h"
11804 +#include "do_author.h" /* for "struct author_data" */
11808 /* Support for dollar variables. Look in the authorization data and
11809 return strings representing values found there. If not found, return
11810 @@ -38,6 +57,8 @@ type -- (1 to 4)
11811 service -- (1 to 7)
11812 status -- (pass, fail, error, unknown) */
11814 +static char *lookup TAC_ARGS((char *sym, struct author_data *data));
11819 @@ -96,12 +117,14 @@ struct author_data *data;
11820 values for the various $ variables by looking in the authorization
11823 +static char *substitute TAC_ARGS((const char *string, struct author_data *data));
11826 substitute(string, data)
11828 +const char *string;
11829 struct author_data *data;
11833 char out[MAX_INPUT_LINE_LEN], *outp;
11834 char sym[MAX_INPUT_LINE_LEN], *symp;
11835 char *value, *valuep;
11836 @@ -129,7 +152,7 @@ struct author_data *data;
11839 /* copy symbol into sym */
11840 - while (*cp && isalpha(*cp))
11841 + while (*cp && isalpha((int) *cp))
11845 @@ -160,6 +183,8 @@ struct author_data *data;
11846 /* Wait for a (child) pid to terminate. Return its status. Probably
11847 horribly implementation dependent. */
11849 +static int waitfor TAC_ARGS((int pid));
11854 @@ -189,6 +214,8 @@ int pid;
11855 return (WEXITSTATUS(status));
11858 +static int write_args TAC_ARGS((int fd, char **args, int arg_cnt));
11860 /* Write an argv array of strings to fd, adding a newline to each one */
11862 write_args(fd, args, arg_cnt)
11863 @@ -211,6 +238,8 @@ char **args;
11867 +static void close_fds TAC_ARGS((int fd1, int fd2, int fd3));
11869 /* Close the three given file-descruptors */
11871 close_fds(fd1, fd2, fd3)
11872 @@ -230,6 +259,8 @@ close_fds(fd1, fd2, fd3)
11873 /* Fork a command. Return read and write file descriptors in readfdp
11874 and writefdp. Return the pid or -1 if unsuccessful */
11876 +static int my_popen TAC_ARGS((char *cmd, int *readfdp, int *writefdp, int *errorfdp));
11879 my_popen(cmd, readfdp, writefdp, errorfdp)
11881 @@ -297,6 +328,8 @@ int *readfdp, *writefdp, *errorfdp;
11882 return(0); /* keep Codecenter quiet */
11885 +static int read_string TAC_ARGS((int fd, char *string, int len));
11887 /* read the file descriptor and stuff the data into the given array for
11888 * the number of bytes given. Throw the rest away.
11890 @@ -305,7 +338,7 @@ read_string (fd, string, len)
11899 @@ -324,6 +357,8 @@ char *string;
11900 the count of lines seen so far. When eof is read, the array is
11901 allocated, and the recursion unravels */
11903 +static char **read_args TAC_ARGS((int n, int fd));
11908 @@ -356,12 +391,16 @@ int n, fd;
11909 standard input and read its standard output into outarray. Return
11910 the commands final status when it terminates */
11912 +int call_pre_process TAC_ARGS((const char *string, struct author_data *data, char ***outargsp, int *outargs_cntp, char *error, int err_len));
11915 call_pre_process(string, data, outargsp, outargs_cntp, error, err_len)
11916 -char *string, *error;
11917 +const char *string;
11918 struct author_data *data;
11920 -int *outargs_cntp, err_len;
11921 +int *outargs_cntp;
11926 int readfd, writefd, errorfd;
11927 @@ -402,8 +441,8 @@ int *outargs_cntp, err_len;
11929 read_string(errorfd, error, err_len);
11930 if (error[0] != '\0') {
11931 - report(LOG_ERR, "Error from program (%d): \"%s\" ",
11932 - strlen(error), error);
11933 + report(LOG_ERR, "Error from program (%u): \"%s\" ",
11934 + (unsigned) strlen(error), error);
11937 /* count the args */
11938 @@ -422,9 +461,11 @@ int *outargs_cntp, err_len;
11939 standard input and read its standard output into outarray. Return
11940 the commands final status when it terminates */
11942 +int call_post_process TAC_ARGS((const char *string, struct author_data *data, char ***outargsp, int *outargs_cntp));
11945 call_post_process(string, data, outargsp, outargs_cntp)
11947 +const char *string;
11948 struct author_data *data;
11951 diff --git a/programs.h b/programs.h
11952 new file mode 100644
11953 index 0000000..31ebef3
11957 +#ifndef PROGRAMS_H
11958 +#define PROGRAMS_H 1
11960 +#include "tac_plus.h"
11963 +struct author_data;
11965 +extern int call_pre_process TAC_ARGS((const char *string, struct author_data *data, char ***outargsp, int *outargs_cntp, char *error, int err_len));
11966 +extern int call_post_process TAC_ARGS((const char *string, struct author_data *data, char ***outargsp, int *outargs_cntp));
11969 +#endif /* PROGRAMS_H */
11970 diff --git a/pw.c b/pw.c
11971 index 96c761e..a749262 100644
11974 @@ -20,15 +20,26 @@
11975 /* Tacacs+ password lookup routine for those systems which don't have
11976 setpwfile. Not for use on /etc/passwd files */
11979 #include "tac_plus.h"
11981 +#include <stdlib.h>
11983 #include <string.h>
11986 +#include "report.h"
11990 static struct passwd pw_passwd;
11992 +struct passwd *tac_passwd_lookup TAC_ARGS((const char *name, const char *file));
11995 tac_passwd_lookup(name, file)
11996 - char *name, *file;
12000 FILE *passwd_fp = NULL;
12002 @@ -113,10 +124,12 @@ tac_passwd_lookup(name, file)
12004 pw_passwd.pw_name = uname;
12005 pw_passwd.pw_passwd = password;
12007 +#ifdef HAVE_PASSWD_PW_AGE
12008 pw_passwd.pw_age = NULL;
12010 +#ifdef HAVE_PASSWD_PW_COMMENT
12011 pw_passwd.pw_comment = NULL;
12012 -#endif /* NO_PWAGE */
12014 pw_passwd.pw_gecos = gecos;
12015 pw_passwd.pw_dir = homedir;
12016 pw_passwd.pw_shell = shell;
12017 diff --git a/pw.h b/pw.h
12018 new file mode 100644
12019 index 0000000..44dc425
12026 +#include "tac_plus.h"
12029 +extern struct passwd *tac_passwd_lookup TAC_ARGS((const char *name, const char *file));
12033 diff --git a/pwlib.c b/pwlib.c
12034 index 75f90b1..70a468e 100644
12037 @@ -17,39 +17,61 @@
12038 FITNESS FOR A PARTICULAR PURPOSE.
12042 #include "tac_plus.h"
12043 -#include "expire.h"
12044 -#include "time_limit.h"
12046 +#ifdef HAVE_UNISTD_H
12047 +#include <unistd.h>
12050 +#include <sys/types.h>
12051 +#include <string.h>
12052 +#include <errno.h>
12053 +#include <stdlib.h>
12056 #ifdef SHADOW_PASSWORDS
12057 +#ifdef HAVE_SHADOW_H
12058 #include <shadow.h>
12064 -tac_pam_auth(char *UserName,char *Password,struct authen_data *data,char *Service);
12065 -#endif /* USE_PAM */
12066 +#include "pwlib.h"
12067 +#include "expire.h"
12068 +#include "time_limit.h"
12069 +#include "report.h"
12070 +#include "utils.h"
12071 +#include "cfgfile.h"
12073 +#include "choose_authen.h" /* for "struct authen_data" */
12074 +#include "packet.h"
12076 +#include "parse.h"
12078 -/* For database verification */
12080 +#include "tac_pam.h"
12086 -/* For LDAP verification */
12087 +#include "db.h" /* For database verification */
12092 +#include "ldap_author.h" /* For LDAP verification */
12096 +static int passwd_file_verify TAC_ARGS((const char *user, const char *supplied_passwd, struct authen_data *data, const char *filename));
12099 /* Generic password verification routines for des, file and cleartext
12102 -static int passwd_file_verify();
12104 /* Adjust data->status depending on whether a user has expired or not */
12106 +void set_expiration_status TAC_ARGS((const char *exp_date, struct authen_data *data));
12109 set_expiration_status(exp_date, data)
12111 +const char *exp_date;
12112 struct authen_data *data;
12115 @@ -105,18 +127,18 @@ struct authen_data *data;
12117 Return 1 if password is valid */
12119 +int verify TAC_ARGS((const char *name, const char *passwd, struct authen_data *data, int recurse));
12122 verify(name, passwd, data, recurse)
12123 -char *name, *passwd;
12125 +const char *passwd;
12126 struct authen_data *data;
12131 - char *cfg_passwd;
12133 + const char *exp_date, *cfg_passwd, *p, *timestamp;
12135 - timestamp = (char *)cfg_get_timestamp(name, recurse);
12136 + timestamp = cfg_get_timestamp(name, recurse);
12137 if ( timestamp != NULL ) {
12138 if( time_limit_process(timestamp) == 0 ) {
12139 if ( debug & DEBUG_AUTHEN_FLAG )
12140 @@ -144,18 +166,18 @@ int recurse;
12141 has been issued, attempt to use this password file */
12144 - char *file = cfg_get_authen_default();
12145 + const char *file = cfg_get_authen_default();
12146 switch (cfg_get_authen_default_method()) {
12152 return (passwd_file_verify(name, passwd, data, file));
12158 /* ugly check for database connect string */
12159 - if( strstr(file, "://") ){
12160 + if( strstr(file, "://") ) {
12161 if (debug & DEBUG_PASSWD_FLAG)
12162 report(LOG_DEBUG,"%s %s: DB access to %s for user %s",session.peer, session.port, file, name);
12163 if (!db_verify(name, passwd, file)) {
12164 @@ -188,8 +210,8 @@ int recurse;
12167 if (debug & DEBUG_PASSWD_FLAG)
12168 - report(LOG_DEBUG, "PAM verify daemon %s == NAS %s", p,passwd);
12169 - if (tac_pam_auth(name, passwd, data,file)) {
12170 + report(LOG_DEBUG, "PAM verify daemon [PAM] == NAS %s", passwd);
12171 + if (tac_pam_auth(name, passwd, data, file)) {
12172 if (debug & DEBUG_PASSWD_FLAG)
12173 report(LOG_DEBUG, "PAM default authentication fail");
12174 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
12175 @@ -210,9 +232,8 @@ int recurse;
12176 /* otherwise, we fail */
12177 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
12184 /* We have a configured password. Deal with it depending on its
12186 @@ -323,11 +344,15 @@ int recurse;
12190 +static int etc_passwd_file_verify TAC_ARGS((const char *user, const char *supplied_passwd, struct authen_data *data));
12192 /* verify that this user/password is valid per /etc/passwd.
12193 - Return 0 if invalid. */
12194 + * Return 0 if invalid.
12197 etc_passwd_file_verify(user, supplied_passwd, data)
12198 -char *user, *supplied_passwd;
12200 +const char *supplied_passwd;
12201 struct authen_data *data;
12204 @@ -409,11 +434,14 @@ struct authen_data *data;
12205 /* verify that this user/password is valid per a passwd(5) style
12206 database. Return 0 if invalid. */
12208 +static int passwd_file_verify TAC_ARGS((const char *user, const char *supplied_passwd, struct authen_data *data, const char *filename));
12211 passwd_file_verify(user, supplied_passwd, data, filename)
12212 -char *user, *supplied_passwd;
12214 +const char *supplied_passwd;
12215 struct authen_data *data;
12217 +const char *filename;
12221 @@ -467,9 +495,12 @@ char *filename;
12222 * return 1 if verified, 0 otherwise.
12225 +int des_verify TAC_ARGS((const char *users_passwd, const char *encrypted_passwd));
12228 des_verify(users_passwd, encrypted_passwd)
12229 -char *users_passwd, *encrypted_passwd;
12230 +const char *users_passwd;
12231 +const char *encrypted_passwd;
12235 diff --git a/pwlib.h b/pwlib.h
12236 new file mode 100644
12237 index 0000000..92b54af
12244 +#include "tac_plus.h"
12247 +struct authen_data;
12249 +extern void set_expiration_status TAC_ARGS((const char *exp_date, struct authen_data *data));
12250 +extern int verify TAC_ARGS((const char *name, const char *passwd, struct authen_data *data, int recurse));
12251 +extern int des_verify TAC_ARGS((const char *users_passwd, const char *encrypted_passwd));
12254 +#endif /* PWLIB_H */
12255 diff --git a/report.c b/report.c
12256 index a458617..d46abfd 100644
12259 @@ -17,20 +17,37 @@
12260 FITNESS FOR A PARTICULAR PURPOSE.
12264 #include "tac_plus.h"
12265 -#include <stdio.h>
12268 +#include <stdio.h>
12269 #include <sys/types.h>
12272 +#include <sys/stat.h>
12273 +#ifdef HAVE_FCNTL_H
12274 +#include <fcntl.h>
12278 -#include <stdarg.h> /* ANSI C, variable length args */
12280 -#include <varargs.h> /* has 'vararg' definitions */
12281 +#include <string.h>
12282 +#ifdef HAVE_UNISTD_H
12283 +#include <unistd.h>
12285 +#ifdef HAVE_SYSLOG_H
12286 +#include <syslog.h>
12288 +#ifdef HAVE_SYS_SYSLOG_H
12289 +#include <sys/syslog.h>
12292 +#include "report.h"
12293 +#include "utils.h"
12300 +#define LOGFILE_DEFAULT "/var/log/tac_plus.log"
12303 FILE *ostream = NULL;
12305 @@ -45,21 +62,30 @@ char *logfile = LOGFILE_DEFAULT;
12306 * All other priorities are always logged to syslog.
12309 +void report TAC_ARGS((int priority, const char *fmt, ...)) G_GNUC_PRINTF(2, 3);
12313 +#include <stdarg.h> /* ANSI C, variable length args */
12315 -report(int priority, char *fmt,...)
12317 +report(int priority, const char *fmt,...)
12319 +#else /* __STDC__ */
12321 +#include <varargs.h> /* has 'vararg' definitions */
12324 report(priority, fmt, va_alist)
12328 va_dcl /* no terminating semi-colon */
12331 +#endif /* __STDC__ */
12333 char msg[255]; /* temporary string */
12334 - char *fp, *bufp, *charp;
12335 - int len, m, i, n;
12337 + char *bufp, *charp = NULL /* GCC paranoia */;
12338 + int len, m = 0 /* GCC paranoia */, i, n;
12342 @@ -119,6 +145,9 @@ va_dcl /* no terminating semi-colon */
12343 m = strlen(digits);
12347 + syslog(LOG_ERR, "Unknown format character '%c', ignoring it", *fp);
12351 if ((len + m + 1) >= n) {
12352 @@ -167,7 +196,7 @@ va_dcl /* no terminating semi-colon */
12355 tac_lockfd(logfile, logfd);
12356 - sprintf(buf, "%s [%d]: ", ct, getpid());
12357 + sprintf(buf, "%s [%d]: ", ct, (int) getpid());
12358 write(logfd, buf, strlen(buf));
12359 if (priority == LOG_ERR)
12360 write(logfd, "Error ", 6);
12361 @@ -190,6 +219,8 @@ va_dcl /* no terminating semi-colon */
12362 syslog(priority, "%s", msg);
12365 +void report_hex TAC_ARGS((int priority, u_char *p, int len));
12367 /* format a hex dump for syslog */
12369 report_hex(priority, p, len)
12370 @@ -225,6 +256,8 @@ int len;
12374 +void report_string TAC_ARGS((int priority, u_char *p, int len));
12376 /* format a non-null terminated string for syslog */
12378 report_string(priority, p, len)
12379 @@ -251,10 +284,11 @@ int len;
12380 report(priority, "%s", buf);
12383 +void tac_regerror TAC_ARGS((const char *s));
12391 report(LOG_ERR, "in regular expression %s", s);
12394 diff --git a/report.h b/report.h
12395 new file mode 100644
12396 index 0000000..5e5d1bb
12401 +#define REPORT_H 1
12403 +#include "tac_plus.h"
12405 +#include <stdio.h>
12406 +#include <sys/types.h> /* for u_* */
12407 +#ifdef HAVE_SYSLOG_H
12408 +#include <syslog.h> /* for LOG_* level values */
12410 +#ifdef HAVE_SYS_SYSLOG_H
12411 +#include <sys/syslog.h> /* for LOG_* level values */
12415 +extern FILE *ostream; /* for logging to console */
12416 +extern char *logfile;
12419 +extern void report TAC_ARGS((int priority, const char *fmt, ...)) G_GNUC_PRINTF(2, 3);
12420 +extern void report_hex TAC_ARGS((int priority, u_char *p, int len));
12421 +extern void report_string TAC_ARGS((int priority, u_char *p, int len));
12422 +extern void tac_regerror TAC_ARGS((const char *s));
12425 +#endif /* REPORT_H */
12426 diff --git a/sendauth.c b/sendauth.c
12427 index 68e5482..2076dc9 100644
12430 @@ -17,21 +17,43 @@
12431 FITNESS FOR A PARTICULAR PURPOSE.
12435 #include "tac_plus.h"
12437 +#include <stdlib.h>
12439 +#include "sendauth.h"
12440 #include "expire.h"
12442 +#include "report.h"
12443 +#include "cfgfile.h"
12444 +#include "utils.h"
12445 +#include "pwlib.h"
12446 +#include "choose_authen.h" /* for "struct authen_data" */
12447 +#include "do_author.h" /* for "struct identity" */
12448 +#include "packet.h"
12451 -static int do_sendauth_fn();
12452 -static void outbound_chap();
12454 -static void outbound_mschap();
12455 -#endif /* MSCHAP */
12456 -void outbound_pap();
12457 +#include "default_fn.h"
12461 +static int do_sendauth_fn TAC_ARGS((struct authen_data *data));
12462 +static void outbound_chap TAC_ARGS((struct authen_data *data));
12463 +static void outbound_pap TAC_ARGS((struct authen_data *data));
12466 +static void outbound_mschap TAC_ARGS((struct authen_data *data));
12470 +int sendauth_fn TAC_ARGS((struct authen_data *data));
12472 int sendauth_fn(data)
12473 struct authen_data *data;
12479 name = data->NAS_id->username;
12480 @@ -39,8 +61,9 @@ struct authen_data *data;
12481 if (STREQ(name, DEFAULT_USERNAME)) {
12482 /* This username is only valid for authorization */
12483 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
12486 - status = do_sendauth_fn(data);
12487 + retval = do_sendauth_fn(data);
12491 @@ -71,7 +94,7 @@ struct authen_data *data;
12492 (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ?
12493 "accepted" : "rejected");
12500 @@ -84,11 +107,13 @@ struct authen_data *data;
12501 * Return 0 if data->status is valid, otherwise 1
12504 +static int do_sendauth_fn TAC_ARGS((struct authen_data *data));
12507 do_sendauth_fn(data)
12508 struct authen_data *data;
12510 - char *name, *exp_date;
12511 + const char *name, *exp_date;
12513 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
12515 @@ -129,11 +154,13 @@ struct authen_data *data;
12520 +static void outbound_pap TAC_ARGS((struct authen_data *data));
12524 struct authen_data *data;
12526 - char *secret, *p, *name;
12527 + const char *secret, *p, *name;
12529 name = data->NAS_id->username;
12531 @@ -163,17 +190,19 @@ struct authen_data *data;
12535 - data->server_data = tac_strdup(p);
12536 - data->server_dlen = strlen(data->server_data);
12537 + data->server_data = (unsigned char *) tac_strdup(p);
12538 + data->server_dlen = strlen((char *) data->server_data);
12539 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
12542 +static void outbound_chap TAC_ARGS((struct authen_data *data));
12545 outbound_chap(data)
12546 struct authen_data *data;
12548 - char *name, *secret, *chal, digest[MD5_LEN];
12550 + const char *name, *secret, *chal, *p;
12551 + char digest[MD5_LEN];
12554 int chal_len, inlen;
12555 @@ -262,12 +291,13 @@ struct authen_data *data;
12559 +static void outbound_mschap TAC_ARGS((struct authen_data *data));
12562 outbound_mschap(data)
12563 struct authen_data *data;
12565 - char *name, *secret, *chal;
12567 + const char *name, *secret, *chal, *p;
12571 diff --git a/sendauth.h b/sendauth.h
12572 new file mode 100644
12573 index 0000000..d3e2fbc
12577 +#ifndef SENDAUTH_H
12578 +#define SENDAUTH_H 1
12580 +#include "tac_plus.h"
12583 +struct authen_data;
12585 +extern int sendauth_fn TAC_ARGS((struct authen_data *data));
12588 +#endif /* SENDAUTH_H */
12589 diff --git a/sendpass.c b/sendpass.c
12590 index f7f0b3c..9d8ab00 100644
12593 @@ -17,11 +17,24 @@
12594 FITNESS FOR A PARTICULAR PURPOSE.
12598 #include "tac_plus.h"
12600 +#include "sendpass.h"
12601 #include "expire.h"
12602 +#include "report.h"
12603 +#include "utils.h"
12604 +#include "cfgfile.h"
12605 +#include "choose_authen.h" /* for "struct authen_data" */
12606 +#include "do_author.h" /* for "struct identity" */
12608 +#include "packet.h"
12613 +static int do_sendpass_fn TAC_ARGS((struct authen_data *data));
12616 +int sendpass_fn TAC_ARGS((struct authen_data *data));
12618 int sendpass_fn(data)
12619 struct authen_data *data;
12620 @@ -63,17 +76,17 @@ struct authen_data *data;
12621 * Any strings pointed to by authen_data must come from the heap. They
12622 * will get freed by the caller.
12624 - * Return 0 if data->status is valid, otherwise 1 */
12625 + * Return 0 if data->status is valid, otherwise 1
12628 +static int do_sendpass_fn TAC_ARGS((struct authen_data *data));
12631 do_sendpass_fn(data)
12632 struct authen_data *data;
12636 + const char *name, *exp_date, *secret, *p;
12641 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
12643 @@ -159,8 +172,8 @@ struct authen_data *data;
12647 - data->server_data = tac_strdup(p);
12648 - data->server_dlen = strlen(data->server_data);
12649 + data->server_data = (unsigned char *) tac_strdup(p);
12650 + data->server_dlen = strlen((char *) data->server_data);
12651 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
12652 if (expired == PW_EXPIRING) {
12653 data->server_msg = tac_strdup("Secret will expire soon");
12654 diff --git a/sendpass.h b/sendpass.h
12655 new file mode 100644
12656 index 0000000..7481cff
12660 +#ifndef SENDPASS_H
12661 +#define SENDPASS_H 1
12663 +#include "tac_plus.h"
12666 +struct authen_data;
12668 +extern int sendpass_fn TAC_ARGS((struct authen_data *data));
12671 +#endif /* SENDPASS_H */
12672 diff --git a/skey_fn.c b/skey_fn.c
12673 index d3c9860..0a74fa8 100644
12676 @@ -17,17 +17,22 @@
12677 FITNESS FOR A PARTICULAR PURPOSE.
12682 #include "tac_plus.h"
12688 +#include "skey_fn.h"
12689 #include "expire.h"
12692 /* internal state variables */
12693 #define STATE_AUTHEN_START 0 /* no requests issued */
12694 #define STATE_AUTHEN_GETUSER 1 /* username has been requested */
12695 #define STATE_AUTHEN_GETPASS 2 /* password has been requested */
12699 struct private_data {
12701 char password[MAX_PASSWD_LEN + 1];
12702 @@ -37,6 +42,8 @@ struct private_data {
12703 /* Use s/key to verify a supplied password using state set up earlier
12704 when the username was supplied */
12706 +static int skey_verify TAC_ARGS((char *passwd, struct authen_data *data));
12709 skey_verify(passwd, data)
12711 @@ -73,6 +80,8 @@ struct authen_data *data;
12712 * Return 0 if data->status is valid, otherwise 1
12715 +int skey_fn TAC_ARGS((struct authen_data *data));
12719 struct authen_data *data;
12720 @@ -222,12 +231,9 @@ struct authen_data *data;
12726 -/* The following code is not needed or used. It exists solely to
12727 - prevent compilers from "helpfully" complaining that this source
12728 - file is empty, which upsets novices building the software */
12731 -static int dummy = 0;
12732 +TAC_SOURCEFILE_EMPTY
12735 diff --git a/skey_fn.h b/skey_fn.h
12736 new file mode 100644
12737 index 0000000..1b7474a
12742 +#define SKEY_FN_H 1
12744 +#include "tac_plus.h"
12749 +extern int skey_fn TAC_ARGS((struct authen_data *data));
12754 +#endif /* SKEY_FN_H */
12755 diff --git a/tac_pam.c b/tac_pam.c
12756 index bf1b215..4f088a0 100644
12763 * A simple pam authentication routine written by
12764 * Max Liccardo <ravel@tiscalinet.it>
12765 * PAM_RUSER=username/rem_addr.
12770 This program was contributed by Shane Watts
12771 [modifications by AGM]
12773 @@ -14,23 +12,39 @@
12774 # check authorization
12775 check_user auth required /usr/lib/security/pam_unix_auth.so
12776 check_user account required /usr/lib/security/pam_unix_acct.so
12781 +#include "tac_plus.h"
12786 #include <stdlib.h>
12787 #include <string.h>
12788 #include <security/pam_appl.h>
12789 -#include "tac_plus.h"
12795 +#include "tac_pam.h"
12796 +#include "report.h"
12797 +#include "utils.h"
12798 +#include "choose_authen.h" /* for "struct authen_data" */
12799 +#include "do_author.h" /* for "struct identity" */
12804 + const char *UserName;
12805 + const char *Passwd;
12809 -static int fconv(int num_msg, const struct pam_message **msg,
12810 - struct pam_response **resp,void *appdata_ptr)
12811 +static int fconv TAC_ARGS((int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr));
12813 +static int fconv(num_msg, msg, resp, appdata_ptr)
12815 +const struct pam_message **msg;
12816 +struct pam_response **resp;
12817 +void *appdata_ptr;
12820 UserCred *lUserCred;
12821 @@ -38,19 +52,16 @@ static int fconv(int num_msg, const struct pam_message **msg,
12823 lUserCred = appdata_ptr;
12825 - if(lUserCred == NULL)
12827 + if(lUserCred == NULL) {
12828 report(LOG_ERR,"argh....maybe a SunOs 5.6 ???");
12829 return(PAM_CONV_ERR);
12832 + *resp = (struct pam_response *) tac_malloc(num_msg * sizeof(struct pam_response));
12834 - *resp = (struct pam_response *) calloc(num_msg,sizeof(struct pam_response));
12835 + for (i=0; i<num_msg; i++) {
12836 + switch(msg[i]->msg_style) {
12838 - for(i=0;i<num_msg;i++)
12840 - switch(msg[i]->msg_style)
12842 case PAM_PROMPT_ECHO_OFF:
12843 resp[i]->resp = strdup(lUserCred->Passwd);
12845 @@ -60,6 +71,7 @@ static int fconv(int num_msg, const struct pam_message **msg,
12849 + resp[i]->resp = NULL;
12850 report(LOG_DEBUG,"conv default");
12853 @@ -70,12 +82,16 @@ static int fconv(int num_msg, const struct pam_message **msg,
12858 +int tac_pam_auth TAC_ARGS((const char *aszUserName, const char *aszPassword, struct authen_data *data, const char *aszService));
12861 -tac_pam_auth(char *aszUserName,char *aszPassword,struct authen_data *data,char *aszService)
12862 +tac_pam_auth(aszUserName, aszPassword, data, aszService)
12863 +const char *aszUserName;
12864 +const char *aszPassword;
12865 +struct authen_data *data;
12866 +const char *aszService;
12868 - pam_handle_t *pamh=NULL;
12869 + pam_handle_t *pamh = NULL;
12871 char *lpszRemoteUser; /* Username/NAC address */
12872 struct pam_conv s_conv;
12873 @@ -89,17 +105,13 @@ tac_pam_auth(char *aszUserName,char *aszPassword,struct authen_data *data,char *
12874 s_conv.appdata_ptr = (void *) &s_UserCred;
12877 - if((lpszRemoteUser = calloc(strlen(aszUserName)+strlen(data->NAS_id->NAC_address)+2,sizeof(char))) == NULL)
12879 - report(LOG_ERR,"cannot malloc");
12882 + lpszRemoteUser = tac_malloc((strlen(aszUserName)+1+strlen(data->NAS_id->NAC_address)+1) * sizeof(char));
12884 retval = pam_start(aszService,aszUserName , &s_conv, &pamh);
12886 - if (retval != PAM_SUCCESS)
12888 + if (retval != PAM_SUCCESS) {
12889 report(LOG_ERR, "cannot start pam-authentication");
12890 + free(lpszRemoteUser);
12894 @@ -130,10 +142,15 @@ tac_pam_auth(char *aszUserName,char *aszPassword,struct authen_data *data,char *
12895 * Devrim SERAL <devrim@tef.gazi.edu.tr>
12898 +int tac_pam_authorization TAC_ARGS((const char *aszUserName, struct author_data *data, const char *aszService));
12901 -tac_pam_authorization (char *aszUserName,struct author_data *data,char *aszService)
12902 +tac_pam_authorization(aszUserName, data, aszService)
12903 +const char *aszUserName;
12904 +struct author_data *data;
12905 +const char *aszService;
12907 - pam_handle_t *pamh=NULL;
12908 + pam_handle_t *pamh = NULL;
12910 char *lpszRemoteUser; /* Username/NAC address */
12911 struct pam_conv s_conv;
12912 @@ -145,24 +162,18 @@ tac_pam_authorization (char *aszUserName,struct author_data *data,char *aszServi
12913 s_conv.conv = fconv;
12914 s_conv.appdata_ptr = (void *) &s_UserCred;
12916 - if (aszService== NULL)
12918 + if (aszService== NULL) {
12919 report(LOG_ERR,"Service Name doesn't available So authorize him");
12924 - if((lpszRemoteUser = calloc(strlen(aszUserName)+strlen(data->id->NAC_address)+2,sizeof(char))) == NULL)
12926 - report(LOG_ERR,"cannot malloc");
12929 + lpszRemoteUser = tac_malloc((strlen(aszUserName)+strlen(data->id->NAC_address)+2) * sizeof(char));
12931 retval = pam_start(aszService,aszUserName , &s_conv, &pamh);
12933 - if (retval != PAM_SUCCESS)
12935 + if (retval != PAM_SUCCESS) {
12936 report(LOG_ERR, "cannot start pam-authentication");
12937 + free(lpszRemoteUser);
12941 @@ -177,11 +188,12 @@ tac_pam_authorization (char *aszUserName,struct author_data *data,char *aszServi
12943 retval = pam_acct_mgmt(pamh, 0); /* Is user permit to gain access system */
12945 - if(retval != PAM_SUCCESS)
12946 + if (retval != PAM_SUCCESS)
12947 report(LOG_ERR, "Pam Account Managment:%s",pam_strerror(pamh,retval));
12950 if (debug & DEBUG_AUTHOR_FLAG)
12951 report(LOG_DEBUG, "PAM authorization allow user");
12954 if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */
12956 @@ -191,9 +203,8 @@ tac_pam_authorization (char *aszUserName,struct author_data *data,char *aszServi
12957 return ( retval == PAM_SUCCESS ? 0:1 ); /* indicate success */
12960 +#else /* USE_PAM */
12962 -#endif /* USE_PAM */
12966 +TAC_SOURCEFILE_EMPTY
12968 +#endif /* USE_PAM */
12969 diff --git a/tac_pam.h b/tac_pam.h
12970 new file mode 100644
12971 index 0000000..c8306ba
12976 +#define TAC_PAM_H 1
12978 +#include "tac_plus.h"
12983 +struct authen_data;
12984 +struct author_data;
12986 +extern int tac_pam_auth TAC_ARGS((const char *aszUserName, const char *aszPassword, struct authen_data *data, const char *aszService));
12987 +extern int tac_pam_authorization TAC_ARGS((const char *aszUserName, struct author_data *data, const char *aszService));
12990 +#endif /* USE_PAM */
12992 +#endif /* TAC_PAM_H */
12993 diff --git a/tac_plus.1 b/tac_plus.1
12994 index 579c7ee..69f3502 100644
12997 @@ -111,6 +111,8 @@ the following values are recognised:
13001 +2 config file parsing debugging
13002 +4 process forking debugging
13003 8 authorisation debugging
13004 16 authentication debugging
13005 32 password file processing debugging
13006 @@ -120,6 +122,11 @@ Value Meaning
13007 512 encryption/decryption
13008 1024 MD5 hash algorithm debugging
13009 2048 very low level encryption/decryption
13010 +4096 config file memory allocation freeing
13011 +8192 pre/post authorization program arguments substitutions
13012 +16384 config file expressions with entity tracing
13013 +32768 maxsess (concurrent logins) debugging
13014 +65536 file locking progress reporting
13018 diff --git a/tac_plus.cfg b/tac_plus.cfg
13019 index 31e53f5..d217258 100644
13022 @@ -51,4 +51,3 @@ user = DEFAULT {
13024 # time = "Wd1800-1817|!Wd1819-2000"
13027 diff --git a/tac_plus.h b/tac_plus.h
13028 index 99d95e0..1bb658f 100644
13032 +#ifndef TAC_PLUS_H
13033 +#define TAC_PLUS_H 1
13036 Copyright (c) 1995-1998 by Cisco systems, Inc.
13039 WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
13040 FITNESS FOR A PARTICULAR PURPOSE.
13042 -/* For autoconfig */
13045 +#ifdef HAVE_CONFIG_H
13046 #include "config.h"
13051 * If you are defining a system from scratch, the following may be useful.
13053 /* Do you need tacacs+ versions of bzero etc. */
13054 /* #define NEED_BZERO */
13056 -/* Define this if you have shadow passwords in /etc/passwd and
13057 - * /etc/shadow. Note that you usually need to be root to read
13059 -/*#define SHADOW_PASSWORDS*/
13061 -/* Define this if your malloc is defined in malloc.h instead of stdlib.h */
13062 -/* #define STDLIB_MALLOC */
13064 /* Define this if your wait call status is a union as opposed to an int */
13065 /* #define UNIONWAIT */
13067 -/* Define this if your signal() uses a function returning void instead
13070 -/* #define VOIDSIG */
13072 -/* Define this if your password file does not contain age and comment fields. */
13073 -/* #define NO_PWAGE */
13075 /* Define this if you need a getdtablesize routine defined */
13076 /* #define GETDTABLESIZE */
13078 @@ -64,23 +55,14 @@
13080 /* #define ARAP_DES */
13082 -/* Define this if you find that your daemon quits after being sent more than
13083 - * one SIGUSR1. Some systems need to explicitly rearm signals after they've been
13086 -/* #define REARMSIGNAL */
13088 -#define VERSION "F4.0.3.alpha.v8 (Extended Tac_plus)"
13089 +#define VERSION_TAIL " (Extended Tac_plus)"
13092 * System definitions.
13096 -#define STDLIB_MALLOC
13098 #define CONST_SYSERRLIST
13103 @@ -97,15 +79,10 @@
13105 #define _BSD_INCLUDES
13114 -#include <unistd.h>
13115 -#define REARMSIGNAL
13117 #define CONST_SYSERRLIST
13119 @@ -122,30 +99,17 @@
13121 #define GETDTABLESIZE
13123 -#define SHADOW_PASSWORDS
13125 -#define REARMSIGNAL
13126 #endif /* SOLARIS */
13130 #define GETDTABLESIZE
13132 -#define SYSLOG_IN_SYS
13133 -#define REARMSIGNAL
13137 #define CONST_SYSERRLIST
13138 -#define STDLIB_MALLOC
13145 -#define STDLIB_MALLOC
13150 @@ -153,36 +117,26 @@
13151 #define MSCHAP_DIGEST_LEN 49
13152 #endif /* MSCHAP */
13154 -#include <string.h>
13155 -#include <sys/types.h>
13156 -#include <sys/socket.h>
13157 -#include <sys/ioctl.h>
13158 -#include <sys/file.h>
13159 -#include <sys/time.h>
13160 -#include <netinet/in.h>
13162 -#include <stdio.h>
13163 -#include <errno.h>
13165 -#include <netdb.h>
13167 -#ifdef SYSLOG_IN_SYS
13168 -#include <syslog.h>
13170 -#include <sys/syslog.h>
13175 -#include <unistd.h>
13178 +#ifdef HAVE_FCNTL_H
13181 #define index strchr
13182 -#else /* ! SYSV */
13183 -#include <strings.h>
13186 +/* Sometimes are bzero/bcopy/bcmp declared as prototypes with non-void argument
13187 + * pointers. In such case we would generate too much warnings.
13189 +#include <string.h>
13190 +#ifdef HAVE_STRINGS_H
13191 +#include <strings.h>
13194 +#define bzero(s, n) bzero((void *)(s), (size_t)(n))
13195 +#define bcopy(src, dest, n) bcopy((const void *)(src), (void *)(dest), (size_t)(n))
13196 +#define bcmp(s1, s2, n) bcmp((const void *)(s1), (const void *)(s2), (size_t)(n))
13199 #ifndef TACPLUS_PIDFILE
13200 #define TACPLUS_PIDFILE "/var/run/tac_plus.pid"
13202 @@ -193,559 +147,94 @@
13203 * know what you are doing.
13206 -#define DOLLARSIGN '$'
13209 - * XTACACSP protocol defintions
13213 - * This structure describes an authentication method.
13214 - * authen_name contains the name of the authentication method.
13215 - * authen_func is a pointer to the authentication function.
13216 - * authen_method numeric value of authentication method
13218 +/* Stolen from pbmplus.h of netpbm: */
13220 -#define AUTHEN_NAME_SIZE 128
13222 +#define TAC_ARGS(alist) alist
13223 +#else /*__STDC__*/
13224 +#define TAC_ARGS(alist) ()
13225 +#endif /*__STDC__*/
13227 -struct authen_type {
13228 - char authen_name[AUTHEN_NAME_SIZE];
13229 - int (*authen_func)();
13232 +/* Stolen from glib of Gnome/GTK+ environment: */
13235 - * This structure describes a principal that is to be authenticated.
13236 - * username is the principals name (ASCII, null terminated)
13237 - * NAS_name is the name of the NAS where the user is
13238 - * NAS_port is the port on the NAS where the user is
13239 - * NAC_address is the remote user location. This may be
13240 - * a remote IP address or a caller-ID or ...
13241 - * priv_lvl user's requested privilege level.
13242 +/* Provide macros to feature the GCC function attribute.
13249 - char *NAC_address;
13254 - * The authen_data structure is the data structure for passing
13255 - * information to and from the authentication function
13256 - * (authen_type.authen_func).
13257 +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
13258 +#define G_GNUC_PRINTF( format_idx, arg_idx ) \
13259 + __attribute__((format (printf, format_idx, arg_idx)))
13260 +#define G_GNUC_NORETURN \
13261 + __attribute__((noreturn))
13262 +#define G_GNUC_CONST \
13263 + __attribute__((const))
13264 +#define G_GNUC_UNUSED \
13265 + __attribute__((unused))
13266 +#else /* !__GNUC__ */
13267 +#define G_GNUC_PRINTF( format_idx, arg_idx )
13268 +#define G_GNUC_NORETURN
13269 +#define G_GNUC_CONST
13270 +#define G_GNUC_UNUSED
13271 +#endif /* !__GNUC__ */
13273 +/* Provide convenience macros for handling structure
13274 + * fields through their offsets.
13275 + * Project tac_plus changed "gulong" to "glong" to be able to recover
13276 + * original structure base from pointer to its member.
13278 +#define G_STRUCT_OFFSET(struct_type, member) \
13279 + ((long) ((char*) &((struct_type*) 0)->member))
13280 +#define G_STRUCT_MEMBER_P(struct_p, struct_offset) \
13281 + ((void*) ((char*) (struct_p) + (long) (struct_offset)))
13282 +#define G_STRUCT_MEMBER(member_type, struct_p, struct_offset) \
13283 + (*(member_type*) G_STRUCT_MEMBER_P ((struct_p), (struct_offset)))
13285 -struct authen_data {
13286 - struct identity *NAS_id; /* user identity */
13287 - char *server_msg; /* null-terminated output msg */
13289 - int server_dlen; /* output data length */
13290 - char *server_data; /* output data */
13292 - char *client_msg; /* null-terminated input msg a user typed */
13293 +/* reversed, in fact: for inside "member_p" calculate "struct" address */
13294 +#define TAC_MEMBER_STRUCT(struct_type, member_p, member) \
13295 + (G_STRUCT_MEMBER(struct_type,member_p,-G_STRUCT_OFFSET(struct_type,member)))
13297 - int client_dlen; /* input data length */
13298 - char *client_data; /* input data */
13300 - void *method_data; /* opaque private method data */
13301 - int action; /* what's to be done */
13302 - int service; /* calling service */
13303 - int status; /* Authen status */
13304 - int type; /* Authen type */
13305 - u_char flags; /* input & output flags fields */
13309 -/* return values for choose_authen(); */
13311 -#define CHOOSE_FAILED -1 /* failed to choose an authentication function */
13312 -#define CHOOSE_OK 0 /* successfully chose an authentication function */
13313 -#define CHOOSE_GETUSER 1 /* need a username before choosing */
13314 -#define CHOOSE_BADTYPE 2 /* Invalid preferred authen function specified */
13318 - * This structure is the data structure for passing information to
13319 - * and from the authorization function (do_author()).
13320 +/* <sys/param.h> may define MAX & MIN without checking whether they
13321 + * were previously already defined:
13323 -struct author_data {
13324 - struct identity *id; /* user id */
13325 - int authen_method; /* authentication method */
13327 -#define AUTHEN_METH_NONE 0x01
13328 -#define AUTHEN_METH_KRB5 0x02
13329 -#define AUTHEN_METH_LINE 0x03
13330 -#define AUTHEN_METH_ENABLE 0x04
13331 -#define AUTHEN_METH_LOCAL 0x05
13332 -#define AUTHEN_METH_TACACSPLUS 0x06
13333 -#define AUTHEN_METH_RCMD 0x20
13335 - int authen_type; /* authentication type see authen_type */
13336 - int service; /* calling service */
13337 - char *msg; /* optional NULL-terminated return message */
13338 - char *admin_msg; /* optional NULL-terminated admin message */
13339 - int status; /* return status */
13341 -#define AUTHOR_STATUS_PASS_ADD 0x01
13342 -#define AUTHOR_STATUS_PASS_REPL 0x02
13343 -#define AUTHOR_STATUS_FAIL 0x10
13344 -#define AUTHOR_STATUS_ERROR 0x11
13346 - int num_in_args; /* input arg count */
13347 - char **input_args; /* input arguments */
13348 - int num_out_args; /* output arg cnt */
13349 - char **output_args; /* output arguments */
13353 -/* An API accounting record structure */
13355 - int acct_type; /* start, stop, update */
13357 -#define ACCT_TYPE_START 1
13358 -#define ACCT_TYPE_STOP 2
13359 -#define ACCT_TYPE_UPDATE 3
13361 - struct identity *identity;
13362 - int authen_method;
13364 - int authen_service;
13365 - char *msg; /* output field */
13366 - char *admin_msg; /* output field */
13371 -#ifndef TAC_PLUS_PORT
13372 -#define TAC_PLUS_PORT 49
13373 +#ifdef HAVE_SYS_PARAM_H
13374 +#include <sys/param.h>
13377 -/* Define tac_plus name for hosts.* files */
13379 -#define TACNAME "tac_plus"
13380 +/* Provide definitions for some commonly used macros.
13381 + * Some of them are only provided if they haven't already
13382 + * been defined. It is assumed that if they are already
13383 + * defined then the current definition is correct.
13386 +#define NULL ((void*) 0)
13389 -#define TAC_PLUS_READ_TIMEOUT 180 /* seconds */
13390 -#define TAC_PLUS_WRITE_TIMEOUT 180 /* seconds */
13392 -#define NAS_PORT_MAX_LEN 255
13395 - int session_id; /* host specific unique session id */
13396 - int aborted; /* have we received an abort flag? */
13397 - int seq_no; /* seq. no. of last packet exchanged */
13398 - time_t last_exch; /* time of last packet exchange */
13399 - int sock; /* socket for this connection */
13400 - char *key; /* the key */
13401 - int keyline; /* line number key was found on */
13402 - char *peer; /* name of connected peer */
13403 - char *cfgfile; /* config file name */
13404 - char *acctfile; /* name of accounting file */
13405 - char *db_acct; /* name of db accounting string */
13406 - char port[NAS_PORT_MAX_LEN+1]; /* For error reporting */
13407 - u_char version; /* version of last packet read */
13410 -extern struct session session; /* the session */
13412 -/* Global variables */
13414 -extern int debug; /* debugging flag */
13415 -extern int logging; /* syslog logging flag */
13416 -extern int single; /* do not fork (for debugging) */
13417 -extern int console; /* log to console */
13418 -extern FILE *ostream; /* for logging to console */
13419 -extern int parse_only; /* exit after parsing verbosely */
13420 -extern int sendauth_only; /* don't do sendauth */
13422 -/* All tacacs+ packets have the same header format */
13424 -struct tac_plus_pak_hdr {
13427 -#define TAC_PLUS_MAJOR_VER_MASK 0xf0
13428 -#define TAC_PLUS_MAJOR_VER 0xc0
13430 -#define TAC_PLUS_MINOR_VER_0 0x0
13431 -#define TAC_PLUS_VER_0 (TAC_PLUS_MAJOR_VER | TAC_PLUS_MINOR_VER_0)
13433 -#define TAC_PLUS_MINOR_VER_1 0x01
13434 -#define TAC_PLUS_VER_1 (TAC_PLUS_MAJOR_VER | TAC_PLUS_MINOR_VER_1)
13438 +#define MAX(a, b) (((a) > (b)) ? (a) : (b))
13440 -#define TAC_PLUS_AUTHEN 1
13441 -#define TAC_PLUS_AUTHOR 2
13442 -#define TAC_PLUS_ACCT 3
13444 - u_char seq_no; /* packet sequence number */
13445 - u_char encryption; /* packet is encrypted or cleartext */
13447 -#define TAC_PLUS_ENCRYPTED 0x0 /* packet is encrypted */
13448 -#define TAC_PLUS_CLEAR 0x1 /* packet is not encrypted */
13450 - int session_id; /* session identifier FIXME: Is this needed? */
13451 - int datalength; /* length of encrypted data following this
13453 - /* datalength bytes of encrypted data */
13456 -#define HASH_TAB_SIZE 157 /* user and group hash table sizes */
13458 -#define TAC_PLUS_HDR_SIZE 12
13460 -typedef struct tac_plus_pak_hdr HDR;
13462 -/* Authentication packet NAS sends to us */
13464 -struct authen_start {
13467 -#define TAC_PLUS_AUTHEN_LOGIN 0x1
13468 -#define TAC_PLUS_AUTHEN_CHPASS 0x2
13469 -#define TAC_PLUS_AUTHEN_SENDPASS 0x3 /* deprecated */
13470 -#define TAC_PLUS_AUTHEN_SENDAUTH 0x4
13472 +#define MIN(a, b) (((a) < (b)) ? (a) : (b))
13476 -#define TAC_PLUS_PRIV_LVL_MIN 0x0
13477 -#define TAC_PLUS_PRIV_LVL_MAX 0xf
13478 +/* The following code is not needed or used. It exists solely to
13479 + prevent compilers from "helpfully" complaining that this source
13480 + file is empty, which upsets novices building the software */
13482 - u_char authen_type;
13483 +#define TAC_SOURCEFILE_EMPTY \
13484 + static int dummy_unused G_GNUC_UNUSED = 0;
13486 -#define TAC_PLUS_AUTHEN_TYPE_ASCII 1
13487 -#define TAC_PLUS_AUTHEN_TYPE_PAP 2
13488 -#define TAC_PLUS_AUTHEN_TYPE_CHAP 3
13489 -#define TAC_PLUS_AUTHEN_TYPE_ARAP 4
13491 -#define TAC_PLUS_AUTHEN_TYPE_MSCHAP 5
13492 -#endif /* MSCHAP */
13496 -#define TAC_PLUS_AUTHEN_SVC_LOGIN 1
13497 -#define TAC_PLUS_AUTHEN_SVC_ENABLE 2
13498 -#define TAC_PLUS_AUTHEN_SVC_PPP 3
13499 -#define TAC_PLUS_AUTHEN_SVC_ARAP 4
13500 -#define TAC_PLUS_AUTHEN_SVC_PT 5
13501 -#define TAC_PLUS_AUTHEN_SVC_RCMD 6
13502 -#define TAC_PLUS_AUTHEN_SVC_X25 7
13503 -#define TAC_PLUS_AUTHEN_SVC_NASI 8
13507 - u_char rem_addr_len;
13509 - /* <user_len bytes of char data> */
13510 - /* <port_len bytes of char data> */
13511 - /* <rem_addr_len bytes of u_char data> */
13512 - /* <data_len bytes of u_char data> */
13515 -#define TAC_AUTHEN_START_FIXED_FIELDS_SIZE 8
13517 -/* Authentication continue packet NAS sends to us */
13518 -struct authen_cont {
13519 - u_short user_msg_len;
13520 - u_short user_data_len;
13523 -#define TAC_PLUS_CONTINUE_FLAG_ABORT 0x1
13525 - /* <user_msg_len bytes of u_char data> */
13526 - /* <user_data_len bytes of u_char data> */
13529 -#define TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE 5
13531 -/* Authentication reply packet we send to NAS */
13532 -struct authen_reply {
13535 -#define TAC_PLUS_AUTHEN_STATUS_PASS 1
13536 -#define TAC_PLUS_AUTHEN_STATUS_FAIL 2
13537 -#define TAC_PLUS_AUTHEN_STATUS_GETDATA 3
13538 -#define TAC_PLUS_AUTHEN_STATUS_GETUSER 4
13539 -#define TAC_PLUS_AUTHEN_STATUS_GETPASS 5
13540 -#define TAC_PLUS_AUTHEN_STATUS_RESTART 6
13541 -#define TAC_PLUS_AUTHEN_STATUS_ERROR 7
13542 -#define TAC_PLUS_AUTHEN_STATUS_FOLLOW 0x21
13546 -#define TAC_PLUS_AUTHEN_FLAG_NOECHO 0x1
13549 - u_short data_len;
13551 - /* <msg_len bytes of char data> */
13552 - /* <data_len bytes of u_char data> */
13555 -#define TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE 6
13557 -/* An authorization request packet */
13559 - u_char authen_method;
13561 - u_char authen_type;
13566 - u_char rem_addr_len;
13567 - u_char arg_cnt; /* the number of args */
13569 - /* <arg_cnt u_chars containing the lengths of args 1 to arg n> */
13570 - /* <user_len bytes of char data> */
13571 - /* <port_len bytes of char data> */
13572 - /* <rem_addr_len bytes of u_char data> */
13573 - /* <char data for each arg> */
13576 -#define TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE 8
13578 -/* An authorization reply packet */
13579 -struct author_reply {
13583 - u_short data_len;
13585 - /* <arg_cnt u_chars containing the lengths of arg 1 to arg n> */
13586 - /* <msg_len bytes of char data> */
13587 - /* <data_len bytes of char data> */
13588 - /* <char data for each arg> */
13591 -#define TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE 6
13596 -#define TAC_PLUS_ACCT_FLAG_MORE 0x1
13597 -#define TAC_PLUS_ACCT_FLAG_START 0x2
13598 -#define TAC_PLUS_ACCT_FLAG_STOP 0x4
13599 -#define TAC_PLUS_ACCT_FLAG_WATCHDOG 0x8
13601 - u_char authen_method;
13603 - u_char authen_type;
13604 - u_char authen_service;
13607 - u_char rem_addr_len;
13608 - u_char arg_cnt; /* the number of cmd args */
13609 - /* one u_char containing size for each arg */
13610 - /* <user_len bytes of char data> */
13611 - /* <port_len bytes of char data> */
13612 - /* <rem_addr_len bytes of u_char data> */
13613 - /* char data for args 1 ... n */
13616 -#define TAC_ACCT_REQ_FIXED_FIELDS_SIZE 9
13618 -struct acct_reply {
13620 - u_short data_len;
13623 -#define TAC_PLUS_ACCT_STATUS_SUCCESS 0x1
13624 -#define TAC_PLUS_ACCT_STATUS_ERROR 0x2
13625 -#define TAC_PLUS_ACCT_STATUS_FOLLOW 0x21
13629 -#define TAC_ACCT_REPLY_FIXED_FIELDS_SIZE 5
13630 +#define DOLLARSIGN '$'
13632 /* Odds and ends */
13633 -#define TAC_PLUS_MAX_ITERATIONS 50
13635 -#define MIN(a,b) ((a)<(b)?(a):(b))
13636 #define STREQ(a,b) (strcmp(a,b)==0)
13637 #define MAX_INPUT_LINE_LEN 255
13639 -/* Debugging flags */
13641 -#define DEBUG_PARSE_FLAG 2
13642 -#define DEBUG_FORK_FLAG 4
13643 -#define DEBUG_AUTHOR_FLAG 8
13644 -#define DEBUG_AUTHEN_FLAG 16
13645 -#define DEBUG_PASSWD_FLAG 32
13646 -#define DEBUG_ACCT_FLAG 64
13647 -#define DEBUG_CONFIG_FLAG 128
13648 -#define DEBUG_PACKET_FLAG 256
13649 -#define DEBUG_HEX_FLAG 512
13650 -#define DEBUG_MD5_HASH_FLAG 1024
13651 -#define DEBUG_XOR_FLAG 2048
13652 -#define DEBUG_CLEAN_FLAG 4096
13653 -#define DEBUG_SUBST_FLAG 8192
13654 -#define DEBUG_PROXY_FLAG 16384
13655 -#define DEBUG_MAXSESS_FLAG 32768
13656 -#define DEBUG_LOCK_FLAG 65536
13658 -extern char *codestring();
13659 -extern int keycode();
13661 -#define TAC_IS_USER 1
13662 -#define TAC_PLUS_RECURSE 1
13663 -#define TAC_PLUS_NORECURSE 0
13665 -#define DEFAULT_USERNAME "DEFAULT"
13667 -#include "parse.h"
13672 -#define N_optarg 51
13673 -#define N_svc_exec 52
13674 -#define N_svc_slip 53
13675 -#define N_svc_ppp 54
13676 -#define N_svc_arap 55
13677 -#define N_svc_cmd 56
13678 -#define N_permit 57
13682 -/* A parse tree node */
13684 - int type; /* node type (arg, svc, proto) */
13685 - void *next; /* pointer to next node in chain */
13686 - void *value; /* node value */
13687 - void *value1; /* node value */
13688 - int dflt; /* default value for node */
13689 - int line; /* line number declared on */
13692 -typedef struct node NODE;
13699 -typedef union v VALUE;
13702 -extern void accounting();
13705 -extern void report_string();
13706 -extern void report_hex();
13708 -extern void report(int priority, char *fmt,...);
13710 -extern void report();
13714 -extern u_char *get_authen_continue();
13715 -extern int send_authen_reply();
13718 -extern char *tac_malloc();
13719 -extern char *tac_strdup();
13720 -extern char *tac_make_string();
13721 -extern char *tac_find_substring();
13722 -extern char *tac_realloc();
13725 -extern char *summarise_outgoing_packet_type();
13726 -extern char *summarise_incoming_packet_type();
13729 -extern void author();
13732 -extern void *hash_add_entry();
13733 -extern void **hash_get_entries();
13734 -extern void *hash_lookup();
13737 -extern int cfg_get_intvalue();
13738 -extern char * cfg_get_pvalue();
13739 -extern char *cfg_get_authen_default();
13740 -extern int cfg_get_authen_default_method();
13741 -extern char **cfg_get_svc_attrs();
13742 -extern NODE *cfg_get_cmd_node();
13743 -extern NODE *cfg_get_svc_node();
13744 -extern char *cfg_get_expires();
13745 -extern char *cfg_get_login_secret();
13746 -extern int cfg_get_user_nopasswd();
13747 -extern char *cfg_get_arap_secret();
13748 -extern char *cfg_get_chap_secret();
13750 -extern char *cfg_get_mschap_secret();
13751 -#endif /* MSCHAP */
13752 -extern char *cfg_get_pap_secret();
13753 -extern char *cfg_get_opap_secret();
13754 -extern char *cfg_get_global_secret();
13756 -extern char *cfg_get_pam_service();
13758 -extern void cfg_clean_config();
13759 -extern char *cfg_nodestring();
13762 -extern struct passwd *tac_passwd_lookup();
13765 -extern void parser_init();
13768 -extern void set_expiration_status();
13770 /* miscellaneous */
13771 #ifdef CONST_SYSERRLIST
13772 extern const char *const sys_errlist[];
13774 extern char *sys_errlist[];
13777 -extern int sendauth_fn();
13778 -extern int sendpass_fn();
13779 -extern int enable_fn();
13780 -extern int default_fn();
13781 -extern int default_v0_fn();
13782 -extern int skey_fn();
13784 -extern void mschap_lmchallengeresponse();
13785 -extern void mschap_ntchallengeresponse();
13786 -#endif /* MSCHAP */
13790 -extern void maxsess_loginit();
13791 -extern int maxsess_check_count();
13794 - * This is a shared file used to maintain a record of who's on
13796 -#define WHOLOG_DEFAULT "/var/log/tac_who.log"
13797 -extern char *wholog;
13799 - * This is state kept per user/session
13802 - char username[64]; /* User name */
13803 - char NAS_name[32]; /* NAS user logged into */
13804 - char NAS_port[32]; /* ...port on that NAS */
13805 - char NAC_address[32]; /* ...IP address of NAS */
13808 -#endif /* MAXSESS */
13811 -extern int tac_pam_authorization();
13814 -#define LOGFILE_DEFAULT "/var/log/tac_plus.log"
13816 -extern struct timeval started_at;
13817 -extern char *logfile;
13818 -extern char *wtmpfile;
13819 -extern int wtmpfd;
13820 +#endif /* TAC_PLUS_H */
13821 diff --git a/tac_plus.pam b/tac_plus.pam
13822 new file mode 100644
13823 index 0000000..fc135fb
13828 +auth required /lib/security/pam_pwdb.so shadow
13829 +account required /lib/security/pam_pwdb.so
13830 +password required /lib/security/pam_pwdb.so nullok use_authtok shadow
13831 +session required /lib/security/pam_pwdb.so
13832 diff --git a/tac_plus.spec.in b/tac_plus.spec.in
13833 new file mode 100644
13834 index 0000000..6df6899
13836 +++ b/tac_plus.spec.in
13838 +# This is tac_plus rpm spec file
13840 +%define ver @VERSION@
13842 +%define prefix /usr
13844 +Summary: Cisco Tacacs+ Daemon
13848 +Copyright: Cisco systems, Inc.
13849 +Group: Networking/Daemons
13850 +Source: http://www.gazi.edu.tr/tacacs/src/tac_plus-%{ver}.tar.gz
13851 +Url: http://www.gazi.edu.tr/tacacs/
13852 +Packager: Jan Kratochvil <short@ucw.cz>
13853 +BuildRoot: /var/tmp/@PACKAGE@-%{ver}-%{rel}-root
13854 +#Docdir: %{prefix}/doc
13856 +%define __libtoolize true # we don't need it, is is otherwise run automatically
13857 + # don't %undefine it, there is expansion bug at least in rpm-4.0-4
13860 +TACACS+ daemon using with Cisco's NASs (Or other vendors) for AAA (Authentication , Authorization and Accounting) propose.
13867 +# configure script have some options describe below
13868 +# --with-pam : For PAM support
13869 +# --with-db : If you like to use db feature you must enable it
13870 +# --with-mysql: For MySQL database support
13871 +# --with-mysql-prefix: If you install MySQL libs other than /usr/lib
13872 +# --enable-maxsess: For check concurrent logins (It's uses finger!!)
13873 +# --with-pgsql With PgSQL Support
13874 +# --with-pgsql-prefix=PREFIX PgSQL prefix [default=/usr]
13875 +# --with-tacuid: If you like to run tac_plus specify UID
13876 +# --with-tacgid: If you like to run tac_plus specify GID
13877 +# --with-tacplus_pid=PREFIX Tac_plus pid file location [default=/var/run]
13878 +# --with-libwrap[=PATH] Compile in libwrap (tcp_wrappers) support
13880 +%configure --with-pam --with-db
13884 +rm -rf "$RPM_BUILD_ROOT"
13886 +install -d "$RPM_BUILD_ROOT"/%{_sysconfdir}/{tacacs,logrotate.d,pam.d,rc.d/{init.d,rc{0,1,2,3,4,5,6}.d}}
13887 +install -c -m 0755 tac_plus.init "$RPM_BUILD_ROOT"/etc/rc.d/init.d/tac_plus
13888 +install -b -c -m 0644 tac_plus.pam "$RPM_BUILD_ROOT"/etc/pam.d/pap
13889 +install -b -c -m 0644 tac_plus.rotate "$RPM_BUILD_ROOT"/etc/logrotate.d/tac_plus
13892 +rm -rf "$RPM_BUILD_ROOT"
13895 +/sbin/chkconfig --add tac_plus
13898 +if [ $1 = 0 ]; then
13899 + if [ -f /var/lock/subsys/tac_plus ]; then
13900 + %{_sysconfdir}/rc.d/init.d/tac_plus stop
13902 + /sbin/chkconfig --del tac_plus
13906 +%defattr(-, root, root)
13907 +%config %{_sysconfdir}/tacacs/tac_plus.cfg
13908 +%config %{_sysconfdir}/pam.d/pap
13909 +%config %{_sysconfdir}/logrotate.d/tac_plus
13910 +%doc users_guide CHANGES convert.pl
13911 +%doc README.LDAP README.PAM tac_plus.sql
13912 +%dir %{_sysconfdir}/tacacs
13913 +%attr(750,root,root) %{_sysconfdir}/rc.d/init.d/tac_plus
13914 +%attr(750,root,root) %{_bindir}/generate_passwd
13915 +%attr(750,root,root) %{_sbindir}/tac_plus
13916 +%attr(644,root,root) %{_mandir}/man1/*
13919 +* Mon Jul 9 2001 Jan Kratochvil <short@ucw.cz>
13920 +- following changes supported by GTS (www.gts.com), cooperation by:
13921 + Pavel Ruzicka <pavel.ruzicka@gtsgroup.cz>
13922 + Michael Macek <michael.macek@gtsgroup.cz>
13923 +- multiple "member" keyword memberships supported
13924 +- "enlist" keyword supported to specify reverse memberships
13925 +- "host" entity unified with "user"/"group" entities
13926 +- "when" blocks implemented for NAS host based configuration
13927 +- "authorization = recursive" implemented for full recursivity
13928 +- line-trailing white spaces removed
13929 +- function prototypes cleanup and K&R C compatibility
13930 +- maintainer compilation is pedantic now, compiler warnings cleanup
13931 +- uncomplete transition from system-name conditions to autoconf style
13932 +- all Makefile options moved to configure.in
13933 +- Makefile.in rewritten to automake Makefile.am
13934 +- autogen script included for easy maintainer rebuilds
13935 +- tac_plus.h split to headers for each particular source file
13936 +- system regex is now preferred, own regex is just fallback
13937 +- several files renamed to prevent auto*/system headers conflicts
13939 +* Sun Mar 25 2001 Devrim SERAL<devrim@gazi.edu.tr>
13940 +- Added PostgreSQL authentication and accounting function
13941 +- Added tcpwrapper feature
13942 +- Added LDAP Authentication from Harpes Patrick (patrick.harpes@tudor.lu)
13943 +- Added more options to configure script
13944 +- Added time_limit function for control user loging time
13945 +- And more control for buffer overflow
13947 +* Fri Nov 17 2000 Devrim SERAL<devrim@tef.gazi.edu.tr>
13948 +- packet.c is pached for overflow problem
13949 +- Fix some log files name
13950 +- Add new config parameters for database accounting
13951 +- MySQL authentication code is functional
13952 +- MySQL accounting code ready but not well tested
13954 +* Mon Mar 10 2000 Devrim SERAL<devrim@tef.gazi.edu.tr>
13955 +- I am add PAM patch from Max Liccardo <ravel@tiscalinet.it>
13956 +- Change PAM code to authorize user
13957 +- Add db support from fil@artelecom.ru
13958 +- I am write MySQL authentication code
13959 +- MySQL code is still experimental
13961 +* Tue Nov 15 1999 Devrim SERAL<devrim@tef.gazi.edu.tr>
13962 +- Take out documentation
13963 +- Add more functional parameters tac_plus script
13964 +- Change some code to authenticate with /etc/shadow
13965 +- Fix some file permissions (Like accounting logs file)
13967 +* Sun Oct 24 1999 D'mon <dimone@ikar.ugol.ru>
13968 +- I moved to RedHat 6.0 =)
13969 +- changes of the package internals!
13971 +* Mon Oct 18 1999 D'mon <dimone@ikar.ugol.ru>
13972 +- massive remake to suit RedHat 5.2 standard
13973 +- patch for RedHat 5.2
13975 +* Wed Aug 4 1999 Erhan Bilgili <erhan@altay.adm.deu.edu.tr>
13976 +- fixes for the RPM_OPT_FLAGS
13977 +- change the buildroot to /var/tmp/tacacsd
13979 +* Wed Aug 4 1999 Devrim SERAL<devrim@tef.gazi.edu.tr>
13980 +- I just re-did the spec file
13981 +- And added Tacac FAQ
13983 diff --git a/tac_regexp.c b/tac_regexp.c
13984 index 9c0357a..390c5f8 100644
13988 * precedence is structured in regular expressions. Serious changes in
13989 * regular-expression syntax might require a total rethink.
13993 +#include "tac_plus.h"
13995 +#ifdef WITH_INCLUDED_REGEX
13998 -#include "regexp.h"
13999 -#include "regmagic.h"
14000 +#include <string.h>
14001 +#include <stdlib.h> /* malloc() can be found in <stdlib.h> OR <malloc.h> */
14002 +#ifdef HAVE_MALLOC_H
14003 +#include <malloc.h>
14006 +#include "tac_regexp.h"
14007 +#include "tac_regmagic.h"
14008 +#include "report.h" /* for regerror() */
14012 * The "internal use only" fields in regexp.h are present to pass info from
14013 @@ -149,7 +163,7 @@
14014 #define UCHARAT(p) ((int)*(p)&CHARBITS)
14017 -#define FAIL(m) { regerror(m); return(NULL); }
14018 +#define FAIL(m) { tac_regerror(m); return(NULL); }
14019 #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
14020 #define META "^$.[()|?+*\\"
14022 @@ -164,7 +178,7 @@
14024 * Global work variables for regcomp().
14026 -static char *regparse; /* Input-scan pointer. */
14027 +static const char *regparse; /* Input-scan pointer. */
14028 static int regnpar; /* () count. */
14029 static char regdummy;
14030 static char *regcode; /* Code-emit pointer; ®dummy = don't. */
14031 @@ -173,23 +187,24 @@ static long regsize; /* Code size. */
14033 * Forward declarations for regcomp()'s friends.
14036 -#define STATIC static
14038 -STATIC char *reg();
14039 -STATIC char *regbranch();
14040 -STATIC char *regpiece();
14041 -STATIC char *regatom();
14042 -STATIC char *regnode();
14043 -STATIC char *regnext();
14044 -STATIC void regc();
14045 -STATIC void reginsert();
14046 -STATIC void regtail();
14047 -STATIC void regoptail();
14049 -STATIC int strcspn();
14050 +static char *reg TAC_ARGS((int paren, int *flagp));
14051 +static char *regbranch TAC_ARGS((int *flagp));
14052 +static char *regpiece TAC_ARGS((int *flagp));
14053 +static char *regatom TAC_ARGS((int *flagp));
14054 +static char *regnode TAC_ARGS((int op));
14055 +static void regc TAC_ARGS((int b));
14056 +static void reginsert TAC_ARGS((int op, char *opnd));
14057 +static void regtail TAC_ARGS((char *p, char *val));
14058 +static void regoptail TAC_ARGS((char *p, char *val));
14059 +static int regtry TAC_ARGS((tac_regexp *prog, const char *string));
14060 +static int regmatch TAC_ARGS((char *prog));
14061 +static int regrepeat TAC_ARGS((char *p));
14062 +static char *regnext TAC_ARGS((register char *p));
14063 +#ifndef HAVE_STRCSPN
14064 +static int strcspn TAC_ARGS((char *s1, char *s2));
14069 - regcomp - compile a regular expression into internal code
14071 @@ -205,16 +220,18 @@ STATIC int strcspn();
14072 * Beware that the optimization-preparation code in here knows about some
14073 * of the structure of the compiled regexp.
14079 +tac_regexp *tac_regcomp TAC_ARGS((const char *exp));
14085 - register regexp *r;
14086 + register tac_regexp *r;
14087 register char *scan;
14088 register char *longest;
14091 - extern char *malloc();
14094 FAIL("NULL argument");
14095 @@ -233,7 +250,7 @@ char *exp;
14096 FAIL("regexp too big");
14098 /* Allocate space. */
14099 - r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
14100 + r = (tac_regexp *)malloc(sizeof(tac_regexp) + (unsigned)regsize);
14102 FAIL("out of space");
14104 @@ -272,7 +289,7 @@ char *exp;
14107 for (; scan != NULL; scan = regnext(scan))
14108 - if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
14109 + if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= (unsigned)len) {
14110 longest = OPERAND(scan);
14111 len = strlen(OPERAND(scan));
14113 @@ -293,6 +310,9 @@ char *exp;
14114 * is a trifle forced, but the need to tie the tails of the branches to what
14115 * follows makes it hard to avoid.
14118 +static char *reg TAC_ARGS((int paren, int *flagp));
14122 int paren; /* Parenthesized? */
14123 @@ -301,7 +321,7 @@ int *flagp;
14124 register char *ret;
14126 register char *ender;
14127 - register int parno;
14128 + register int parno = 0 /* GCC paranoia */;
14131 *flagp = HASWIDTH; /* Tentatively. */
14132 @@ -365,6 +385,9 @@ int *flagp;
14134 * Implements the concatenation operator.
14137 +static char *regbranch TAC_ARGS((int *flagp));
14142 @@ -404,6 +427,9 @@ int *flagp;
14143 * It might seem that this node could be dispensed with entirely, but the
14144 * endmarker role is not redundant.
14147 +static char *regpiece TAC_ARGS((int *flagp));
14152 @@ -468,6 +494,9 @@ int *flagp;
14153 * faster to run. Backslashed characters are exceptions, each becoming a
14154 * separate node; the code is simpler that way and it's not worth fixing.
14157 +static char *regatom TAC_ARGS((int *flagp));
14162 @@ -577,9 +606,12 @@ int *flagp;
14164 - regnode - emit a node
14167 +static char *regnode TAC_ARGS((int op));
14169 static char * /* Location. */
14172 +int op; /* promoted "char" type */
14174 register char *ret;
14175 register char *ptr;
14176 @@ -602,9 +634,12 @@ char op;
14178 - regc - emit (if appropriate) a byte of code
14181 +static void regc TAC_ARGS((int b));
14186 +int b; /* promoted "char" type */
14188 if (regcode != ®dummy)
14190 @@ -617,9 +652,12 @@ char b;
14192 * Means relocating the operand.
14195 +static void reginsert TAC_ARGS((int op, char *opnd));
14198 reginsert(op, opnd)
14200 +int op; /* promoted "char" type */
14203 register char *src;
14204 @@ -646,6 +684,9 @@ char *opnd;
14206 - regtail - set the next-pointer at the end of a node chain
14209 +static void regtail TAC_ARGS((char *p, char *val));
14214 @@ -678,6 +719,9 @@ char *val;
14216 - regoptail - regtail on operand of first argument; nop if operandless
14219 +static void regoptail TAC_ARGS((char *p, char *val));
14224 @@ -696,44 +740,40 @@ char *val;
14226 * Global work variables for regexec().
14228 -static char *reginput; /* String-input pointer. */
14229 -static char *regbol; /* Beginning of input, for ^ check. */
14230 -static char **regstartp; /* Pointer to startp array. */
14231 -static char **regendp; /* Ditto for endp. */
14232 +static const char *reginput; /* String-input pointer. */
14233 +static const char *regbol; /* Beginning of input, for ^ check. */
14234 +static const char **regstartp; /* Pointer to startp array. */
14235 +static const char **regendp; /* Ditto for endp. */
14240 -STATIC int regtry();
14241 -STATIC int regmatch();
14242 -STATIC int regrepeat();
14245 int regnarrate = 0;
14247 -STATIC char *regprop();
14248 +static char *regprop TAC_ARGS((char *op));
14249 +static void regdump TAC_ARGS((tac_regexp *r));
14253 - regexec - match a regexp against a string
14256 +int tac_regexec TAC_ARGS((register tac_regexp *prog, register const char *string));
14259 -regexec(prog, string)
14260 -register regexp *prog;
14261 -register char *string;
14262 +tac_regexec(prog, string)
14263 +register tac_regexp *prog;
14264 +register const char *string;
14266 - register char *s;
14267 - extern char *strchr();
14268 + register const char *s;
14270 /* Be paranoid... */
14271 if (prog == NULL || string == NULL) {
14272 - regerror("NULL parameter");
14273 + tac_regerror("NULL parameter");
14277 /* Check validity of program. */
14278 if (UCHARAT(prog->program) != MAGIC) {
14279 - regerror("corrupted program");
14280 + tac_regerror("corrupted program");
14284 @@ -779,14 +819,17 @@ register char *string;
14286 - regtry - try match at specific point
14289 +static int regtry TAC_ARGS((tac_regexp *prog, const char *string));
14291 static int /* 0 failure, 1 success */
14292 regtry(prog, string)
14296 +const char *string;
14299 - register char **sp;
14300 - register char **ep;
14301 + register const char **sp;
14302 + register const char **ep;
14305 regstartp = prog->startp;
14306 @@ -816,13 +859,15 @@ char *string;
14307 * need to know whether the rest of the match failed) by a loop instead of
14311 +static int regmatch TAC_ARGS((char *prog));
14313 static int /* 0 failure, 1 success */
14317 register char *scan; /* Current node. */
14318 char *next; /* Next node. */
14319 - extern char *strchr();
14323 @@ -888,7 +933,7 @@ char *prog;
14327 - register char *save;
14328 + register const char *save;
14330 no = OP(scan) - OPEN;
14332 @@ -916,7 +961,7 @@ char *prog;
14336 - register char *save;
14337 + register const char *save;
14339 no = OP(scan) - CLOSE;
14341 @@ -935,7 +980,7 @@ char *prog;
14345 - register char *save;
14346 + register const char *save;
14348 if (OP(next) != BRANCH) /* No choice. */
14349 next = OPERAND(scan); /* Avoid recursion. */
14350 @@ -956,7 +1001,7 @@ char *prog;
14352 register char nextch;
14354 - register char *save;
14355 + register const char *save;
14359 @@ -985,7 +1030,7 @@ char *prog;
14360 return(1); /* Success! */
14363 - regerror("memory corruption");
14364 + tac_regerror("memory corruption");
14368 @@ -997,21 +1042,23 @@ char *prog;
14369 * We get here only if there's trouble -- normally "case END" is
14370 * the terminating point.
14372 - regerror("corrupted pointers");
14373 + tac_regerror("corrupted pointers");
14378 - regrepeat - repeatedly match something simple, report how many
14381 +static int regrepeat TAC_ARGS((char *p));
14387 register int count = 0;
14388 - register char *scan;
14389 + register const char *scan;
14390 register char *opnd;
14391 - extern char *strchr();
14395 @@ -1039,7 +1086,7 @@ char *p;
14398 default: /* Oh dear. Called inappropriately. */
14399 - regerror("internal foulup");
14400 + tac_regerror("internal foulup");
14401 count = 0; /* Best compromise. */
14404 @@ -1051,6 +1098,9 @@ char *p;
14406 - regnext - dig the "next" pointer out of a node
14409 +static char *regnext TAC_ARGS((register char *p));
14414 @@ -1072,19 +1122,19 @@ register char *p;
14418 -STATIC char *regprop();
14421 - regdump - dump a regexp onto stdout in vaguely comprehensible form
14425 +static void regdump TAC_ARGS((tac_regexp *r));
14433 register char op = EXACTLY; /* Arbitrary non-END op. */
14434 register char *next;
14435 - extern char *strchr();
14438 s = r->program + 1;
14439 @@ -1121,6 +1171,9 @@ regexp *r;
14441 - regprop - printable representation of opcode
14444 +static char *regprop TAC_ARGS((char *op));
14449 @@ -1192,7 +1245,7 @@ char *op;
14453 - regerror("corrupted opcode");
14454 + tac_regerror("corrupted opcode");
14458 @@ -1207,12 +1260,14 @@ char *op;
14459 * about it; at least one public-domain implementation of those (highly
14460 * useful) string routines has been published on Usenet.
14463 +#ifndef HAVE_STRCSPN
14465 * strcspn - find length of initial segment of s1 consisting entirely
14466 * of characters not from s2
14469 +static int strcspn TAC_ARGS((char *s1, char *s2));
14474 @@ -1231,4 +1286,10 @@ char *s2;
14479 +#endif /* HAVE_STRCSPN */
14481 +#else /* WITH_INCLUDED_REGEX */
14483 +TAC_SOURCEFILE_EMPTY
14485 +#endif /* WITH_INCLUDED_REGEX */
14486 diff --git a/tac_regexp.h b/tac_regexp.h
14487 index b23d97e..7a1a884 100644
14491 +#ifndef TAC_REGEXP_H
14492 +#define TAC_REGEXP_H 1
14494 +#include "tac_plus.h"
14496 +#ifdef WITH_INCLUDED_REGEX
14499 Copyright (c) 1995-1998 by Cisco systems, Inc.
14502 FITNESS FOR A PARTICULAR PURPOSE.
14507 * Definitions etc. for regexp(3) routines.
14509 @@ -24,17 +32,21 @@
14510 * not the System V one.
14513 -typedef struct regexp {
14514 - char *startp[NSUBEXP];
14515 - char *endp[NSUBEXP];
14516 +typedef struct tac_regexp {
14517 + const char *startp[NSUBEXP];
14518 + const char *endp[NSUBEXP];
14519 char regstart; /* Internal use only. */
14520 char reganch; /* Internal use only. */
14521 char *regmust; /* Internal use only. */
14522 int regmlen; /* Internal use only. */
14523 char program[1]; /* Unwarranted chumminess with compiler. */
14528 +extern tac_regexp *tac_regcomp TAC_ARGS((const char *exp));
14529 +extern int tac_regexec TAC_ARGS((register tac_regexp *prog, register const char *string));
14532 +#endif /* WITH_INCLUDED_REGEX */
14534 -extern regexp *regcomp();
14535 -extern int regexec();
14536 -extern void regsub();
14537 -extern void regerror();
14538 +#endif /* TAC_REGEXP_H */
14539 diff --git a/tac_regmagic.h b/tac_regmagic.h
14540 index 0b18b0a..ff321df 100644
14541 --- a/tac_regmagic.h
14542 +++ b/tac_regmagic.h
14544 +#ifndef REGMAGIC_H
14545 +#define REGMAGIC_H 1
14547 +#include "tac_plus.h"
14550 Copyright (c) 1995-1998 by Cisco systems, Inc.
14553 FITNESS FOR A PARTICULAR PURPOSE.
14558 * The first byte of the regexp internal "program" is actually this magic
14559 * number; the start node begins in the second byte.
14564 +#endif /* REGMAGIC_H */
14565 diff --git a/tcpwrap.c b/tcpwrap.c
14566 index ef3d3ad..744a1df 100644
14570 Writen by Devrim SERAL<devrim@gazi.edu.tr>. This file protected by
14571 GNU Copyright agreement.
14575 +#include "tac_plus.h"
14580 -#include "tac_plus.h"
14582 -int allow_severity = LOG_INFO;
14583 +#include "tcpwrap.h"
14584 +#include "report.h"
14585 +#include "packet.h"
14586 +#include "do_author.h" /* for "struct identity" */
14590 +int allow_severity = LOG_INFO; /* *_severity accessed from libwrap */
14591 int deny_severity = LOG_WARNING;
14597 +/* Define tac_plus name for hosts.* files */
14598 +#define TACNAME "tac_plus"
14601 +int check_from_wrap TAC_ARGS((struct identity *datap));
14604 check_from_wrap(datap)
14605 struct identity *datap;
14607 struct request_info req;
14609 - request_init(&req, RQ_DAEMON,TACNAME,RQ_CLIENT_ADDR,datap->NAS_name , NULL);
14610 + request_init(&req, RQ_FILE,session.sock,RQ_DAEMON,TACNAME,RQ_CLIENT_ADDR,datap->NAS_name , NULL);
14611 fromhost(&req); /* validate client host info */
14612 if (!hosts_access(&req))
14614 @@ -34,4 +54,9 @@ struct identity *datap;
14619 +#else /* TCPWRAPPER */
14621 +TAC_SOURCEFILE_EMPTY
14623 #endif /* TCPWRAPPER */
14624 diff --git a/tcpwrap.h b/tcpwrap.h
14625 new file mode 100644
14626 index 0000000..e8e9455
14631 +#define TCPWRAP_H 1
14633 +#include "tac_plus.h"
14640 +extern int check_from_wrap TAC_ARGS((struct identity *datap));
14643 +#endif /* TCPWRAPPER */
14645 +#endif /* TCPWRAP_H */
14646 diff --git a/time_limit.c b/time_limit.c
14647 index 08f6c55..75062f2 100644
14650 @@ -25,180 +25,224 @@ Software Foundation; either version 2, or (at your option) any later version.
14654 -#include"time_limit.h"
14656 #include "tac_plus.h"
14659 +#include <stdlib.h>
14660 +#include <string.h>
14661 +#include <ctype.h>
14664 +#include "time_limit.h"
14665 +#include "report.h"
14667 +#include "utils.h"
14670 +static int str_token_proc TAC_ARGS((char *str));
14671 +static int process TAC_ARGS((char *str));
14672 +static int time_calc TAC_ARGS((char *str, int lct));
14673 +static int antoi TAC_ARGS((char *str, int n));
14676 +static char* week_days[] = {"SU","MO","TU","WE","TH","FR","SA","WK","WD","AL"};
14677 +static long week_day_val[] = {1, 2, 4, 8, 16, 32, 64, 62, 65, 127};
14679 +static int problem = 0;
14682 +int time_limit_process TAC_ARGS((const char *str));
14685 time_limit_process(str)
14692 + char *tmp_str, *str_copy;
14694 -tmp_str=(char *)strtok(str,",|");
14695 -while ( tmp_str != NULL) {
14696 - ret|=str_token_proc(tmp_str);
14697 - tmp_str=(char *)strtok(NULL,",");
14698 + str_copy = tac_strdup(str);
14699 + tmp_str = (char *) strtok(str_copy,",|");
14701 + while ( tmp_str != NULL) {
14702 + ret |= str_token_proc(tmp_str);
14703 + tmp_str = (char *) strtok(NULL,",");
14712 +static int str_token_proc TAC_ARGS((char *str));
14715 str_token_proc(str)
14719 + int inv = 0, ret;
14721 -/* Pass space characters */
14722 -while (isspace(*str)) str++;
14723 + /* Pass space characters */
14724 + while (isspace((int) *str))
14736 + ret=process(str);
14740 if ( debug & DEBUG_AUTHEN_FLAG )
14741 report(LOG_DEBUG,"Timestamp format incorrect");
14757 +static void str_up TAC_ARGS((char *str));
14764 + if (islower((int) *str))
14765 + *str = toupper((int) *str);
14771 +static int process TAC_ARGS((char *str));
14777 -int count=0,ret=0,i,j,localtm;
14778 -char *head,*buf,*gec;
14781 + int count = 0, ret = 0, i, j, localtm;
14782 + char *head, *buf, *gec;
14786 -/* Pass space characters */
14787 -while (isspace(*str)) str++;
14788 + /* Pass space characters */
14789 + while (isspace((int) *str))
14795 -/* Count alphanumeric char */
14796 -while (isalpha(*str)) {
14797 + /* Count alphanumeric char */
14798 + while (isalpha((int) *str)) {
14804 -if ( count==0 || count%2 ) {
14805 + if ( count==0 || count%2 ) {
14811 -buf=(char *)malloc(count+1);
14812 -strncpy(buf,head,count);
14815 + buf = (char *) tac_malloc(count+1);
14816 + strncpy(buf, head, count);
14820 -for(i=1;i<=(count/2);i++) {
14821 - for (j=0;j<NUM;j++) {
14822 - if(!strncmp(gec,week_days[j],2)) {
14823 - ret=ret^week_day_val[j];
14825 + for (i=1; i<=(count/2); i++) {
14826 + for (j=0; j<NUM; j++)
14827 + if(!strncmp(gec,week_days[j],2))
14828 + ret ^= week_day_val[j];
14834 -/* We finished to use buffer so free it */
14836 + /* We finished to use buffer so free it */
14840 -tms=localtime(&sec);
14841 -localtm=(tms->tm_hour)*60+tms->tm_min;
14842 -ret=( week_day_val[tms->tm_wday] & ret ) && time_calc(str,localtm);
14843 + sec = time(NULL);
14844 + tms = localtime(&sec);
14845 + localtm = (tms->tm_hour)*60 + tms->tm_min;
14846 + ret = ( week_day_val[tms->tm_wday] & ret ) && time_calc(str,localtm);
14861 - if(islower(*str)) *str=toupper(*str);
14867 -time_calc(str,lct)
14868 +static int time_calc TAC_ARGS((char *str, int lct));
14871 +time_calc(str, lct)
14875 -char *t1,*t2,*head;
14876 -int say1,say2,count=0;
14877 + char *t1, *t2, *head;
14878 + int say1, say2, count=0;
14883 - while (isdigit(*head) || *head=='-') {
14884 + while (isdigit((int) *head) || *head=='-') {
14889 -if (*str=='\0' || count!= TPL ) {
14890 + if ( *str=='\0' || count!= TPL ) {
14896 - t1=(char *) malloc(count);
14897 - strncpy(t1,str,count); /*Put str value to t1*/
14898 + t1 = (char *) tac_malloc(count);
14899 + strncpy(t1, str, count); /* Put str value to t1 */
14901 - t2=(char *) strstr(t1,"-"); /* Find next time part */
14902 + t2 = (char *) strstr(t1,"-"); /* Find next time part */
14915 -if ( strlen(t1)<4 || strlen(t2)<4 ) {
14916 + if ( strlen(t1)<4 || strlen(t2)<4 ) {
14921 - say1=antoi(t1,2)*60+antoi(t1+2,2);
14922 - say2=antoi(t2,2)*60+antoi(t2+2,2);
14924 + say1 = antoi(t1,2)*60 + antoi(t1+2,2);
14925 + say2 = antoi(t2,2)*60 + antoi(t2+2,2);
14931 - if( (lct>=say1) && (lct<=say2) ) return(1);
14934 - if( (lct>=say1) || (lct<=say2) ) return(1);
14935 + if (say1 <= say2) {
14936 + if( (lct>=say1) && (lct<=say2) )
14939 + if( (lct>=say1) || (lct<=say2) )
14947 +static int antoi TAC_ARGS((char *str, int n));
14962 - buf=(char *) malloc(n);
14963 - strncpy(buf,str,n);
14965 + buf = (char *) tac_malloc(n);
14966 + strncpy(buf, str, n);
14973 diff --git a/time_limit.h b/time_limit.h
14974 index e8bb6fb..eac2096 100644
14978 -#include<stdlib.h>
14982 -#include<string.h>
14983 +#ifndef TIME_LIMIT_H
14984 +#define TIME_LIMIT_H 1
14986 +#include "tac_plus.h"
14990 #define TPL 9 /* time part len */
14992 -/*Global variables */
14993 -static char* week_days[]={"SU","MO","TU","WE","TH","FR","SA","WK","WD","AL"};
14994 -static long week_day_val[]={1,2,4,8,16,32,64,62,65,127};
14996 -extern int time_limit_process();
14997 +extern int time_limit_process TAC_ARGS((const char *str));
15000 +#endif /* TIME_LIMIT_H */
15001 diff --git a/users_guide b/users_guide
15002 index 2626115..c1a8cfd 100644
15005 @@ -337,6 +337,83 @@ and specify as many groupwide characteristics in the group declaration
15006 as possible. Then, individual user declarations can be used to
15007 override the group settings for selected users as needed.
15009 +MEMBERSHIP IN MULTIPLE GROUPS
15010 +-----------------------------
15012 +Besides the descibed single-membership of user to some group, you may also find
15013 +useful if user (or host) belongs to multiple groups at once. You can naturally
15014 +specify multiple "member = group_X" commands for such user:
15017 + # fred is a member of both groups: admins_company_A, admins_company_B
15018 + member = admins_company_A
15019 + member = admins_company_B
15022 +group = admins_company_A {
15023 + # group admins_company_A is not a member of any group
15024 + member = admins_company_A_privilege_X
15025 + member = admins_company_A_privilege_Y
15027 +group = admins_company_A_privilege_X {
15029 +group = admins_company_A_privilege_Y {
15032 +group = admins_company_B {
15033 + # group admins_company_B is not a member of any group
15036 +Here it is important to respect the ordering of "member" commands: Any
15037 +searching for attributes/values is done by Depth-First Search - so Daemon would
15038 +first try to look all members of admins_company_A and THEN (after it would
15039 +failed to find any) it would start to searching through admins_company_B. The
15040 +searching through the proposed example would be done in the following order:
15044 + admins_company_A_privilege_X
15045 + admins_company_A_privilege_Y
15048 +Sometimes you would want to only list some members (users, hosts or groups) but
15049 +you don't want to specify any attributes for them. You would be able to do it:
15051 +group = city_X_NASes {
15053 +host first.NAS.X.city {
15054 + member = city_X_NASes
15056 +host second.NAS.X.city {
15057 + member = city_X_NASes
15060 +But you will probably find more comfortable to use "enlist" keyword. It has
15061 +the same functionality but it goes from the other way:
15063 + member: current entity is connected as CHILD to the specified PARENT entity
15064 + enlist: specified entity is connected as CHILD to the current one as PARENT
15066 +The example would be re-written using "enlist" keyword as:
15068 +group = city_X_NASes {
15069 + enlist = host first.NAS.X.city
15070 + enlist = host second.NAS.X.city
15073 +As you can see, "enlist" doesn't require the existence of the given entity as
15074 +it would loose its primary purpose. If the entity doesn't exist it will be
15075 +automatically created (as empty one) - this doesn't apply to "member"! Any
15076 +argument to "member" MUST already exist. "enlist" is provided to save you from
15077 +writing a lot of empty definition lines like:
15079 +host = first.NAS.X.city {
15082 +All forward references are not a problem, you can still make membership or
15083 +enlistment on the top of the file with the entity which will be defined on the
15084 +end of the configuration file.
15086 CONFIGURING USER AUTHENTICATION
15087 -------------------------------
15089 @@ -1013,6 +1090,229 @@ group = admin {
15093 +CONFIGURATION RESPECTING NAS HOST OF THE USER
15094 +---------------------------------------------
15096 +Sometimes you would want to modify the configuration file according to the
15097 +source NAS where the user is being authenticated/authorized. For example if you
15098 +are big ISP you want to permit administrator of company X to be able to monitor
15099 +status of the links on NAS in company X but, of course, she should be able to
15100 +monitor any other links on any other NAS of the same ISP. As all the NASes are
15101 +authorized from the same Daemon, it seems as a problem. (You can workaround it
15102 +by using custom authorization program - see "USING PROGRAMS TO DO
15103 +AUTHORIZATION" section below - but it is not nice solution.)
15105 +For this purposes there exists another entity 'host':
15109 + host 198.133.219.25
15110 + host nas.cisco.com
15112 +As you can see you may use either IP address or DNS name. Anyway, we strongly
15113 +recommend to always use only IP addresses - DNS subsystem may fail or it may be
15114 +forged by the enemy.
15116 +You have two methods of utilizing the differences between NASes:
15118 +1) Current user is always automatically enlisted (=given membership to) to its
15119 + current NAS host. This looks weird as only groups can have members but this
15120 + is the only exception to this rule, current NAS host can really have a
15123 + ( user "current_user" | user DEFAULT )
15125 + +-- host "current_NAS_IP_address"
15127 + | +- group DEFAULT
15129 + +-- host "current_NAS_hostname"
15131 + | +-- group DEFAULT
15133 + +-- group DEFAULT
15135 + Each link only exists in the case it there exist both its peers, of course.
15136 + user/group DEFAULT is written here only for the completeness of the chart.
15137 + DEFAULT is discussed elsewhere in this documentation.
15139 + According to the shown ordering, attributes/values in the host of current
15140 + NAS identified by its IP address has _higher_ precence over the attributes
15141 + in the current NAS identified by its (reverse-resolved) hostname.
15143 + According to this auto-connections, you can for example permit some command
15144 + to ALL the users on such NAS:
15147 + login = cleartext LLLL
15149 +host = machine.A.company {
15155 + In this configuration file ALL the valid users can do "write terminal" when
15156 + logged in on NAS "machine.A.company".
15158 +2) Sometimes you need to do the authorization specific only to some users on
15159 + some NASes. For example to permit "write terminal" ONLY to user fred
15160 + connected to NAS "machine.A.company". That means that you want to forbid it
15161 + to user fred on any other NAS and yuo also want to forbid it to all the
15162 + other users on NAS "machine.A.company". (Line "authorization = recursive" is
15163 + required but read the following section "FULL RECURSIVITY" to know all its
15166 +authorization = recursive
15168 + login = cleartext LLLL
15170 +host = machine.A.company {
15171 + when = user fred {
15178 + This file has the same effect as:
15180 +authorization = recursive
15182 + login = cleartext LLLL
15183 + when = host machine.A.company {
15190 + You can see the (nested) command "when" can limit the scope of existence of
15191 + its contents. Definition of "host machine.A.company" with empty block (no
15192 + attributes) isn't needed as "when" line will automatically create hosts not
15193 + defined elsewhere, in the same style as "enlist" keyword creates them. Any
15194 + "user"s or "group"s referenced by "when" MUST be defined, such entities are
15195 + never created automatically!
15197 + Unfortunately you cannot use "when" to limit any items, just a few of them
15203 +cmd arguments (to limit specific "permit"/"deny" lines)
15204 +service (or incl. "protocol" specification)
15205 +service AV pairs (to limit specific "attr=value" lines)
15206 +when (enabling pure nesting of "when" blocks)
15208 + Full flexibility to limit any contents may be done in future (needs complete
15209 + cfgfile.c rewrite) but currently it is not supported. Fortunately you can
15210 + get the same behaviour by appropriate usage of "member" keyword - all the
15211 + attributes to be conditioned are put into separate group and you limit only
15212 + the "member" keyword to such group.
15214 + "when" command has the form "when = CONDITION { BLOCK }", CONDITION can be:
15216 +user USR i.e. that current user is "USR")
15217 +host HOSTNAME i.e. that current user is on NAS "HOSTNAME")
15218 +group GRP i.e. current user belongs to the group "GRP",
15219 + All possible "when" conditions to reach such belonging
15220 + have to be successfuly met to make this condition successful.
15221 + Realize that "member" can be limited by "when" keyword.
15222 +CONDITION and CONDITION and CONDITION ...
15223 +CONDITION or CONDITION or CONDITION ...
15227 + You can see that you CANNOT use for example "user A and user B or user C",
15228 + such condition would have ambiguous precedence of operators, you must
15229 + explicitly write: ( user A and user B ) or user C
15230 + or: user A and ( user B or user C )
15232 + Both parentheses have to be written as separate words, NOT "(user A)"
15233 + but "( user A )" instead.
15234 + (Proper solution would also need the complete cfgfile.c rewrite.)
15236 + "not" operator has the highest precendence, so: not user A or user B
15237 + has the same meaning as: ( not user A ) or user B
15239 + Sometimes the "when" condition is so-called unresolvable. Example:
15243 + when = group GRP {
15248 + It is looping, when we would be the member of GRP, we would be really the
15249 + member of GRP but otherwise sould wouldn't be the member of GRP. Weird?
15250 + Yes, such case is considered as configuration bug, it is reported as:
15252 + Unable to resolve expression from line 243, some looping occured
15254 + Generally such unresolvable conditional expression is considered as UNKNOWN
15255 + and the "when" keyword is then evaluated as "false" (=skip it's block).
15256 + This MAY produce unwanted privilege access (if you were conditionally
15257 + forbidding some privileges) so always watch out all the error messages in
15258 + logs! (You should generally do default deny and specifically only "permit"
15259 + all the privileges so the unintentional unresolvable expressions shouldn't
15260 + hurt you in real.)
15265 +We have written in the previous examples line:
15267 +authorization = recursive
15269 +This changes some behaviour of Daemon:
15271 +1) Looping of memberships: By default any looped memberships are reported as
15272 + error with message: recursively defined groups: ...
15274 + After "authorization = recursive" any looping is silently accepted as it
15275 + would be sometimes hard to prevent it in some complex configurations.
15276 + Searching is done in normal Depth-First Search, but traversion is
15277 + backtracked one step when the entity was already visited. Simply it will
15278 + work 'magically', just safely ignore the fact.
15280 +2) "default service = default" is supported only with:
15281 + authorization = recursive
15282 + This isn't any real change, just some formality. In fact each entity block
15283 + has "default service = default" in effect as default (in the case you don't
15284 + write any "default service =" assign).
15286 + "authorization = recursive" is enforced here due to the change of Daemon
15287 + behaviour: In non-recursive (old) case the Daemon assumes "deny .*" as the
15288 + last line of "cmd" block. This makes proper NAS-host based permissions
15289 + impossible. In "authorization = recursive" mode it requires appropriate
15290 + "permit" or "deny" line to apply - otherwise the Depth-First Search through
15291 + the entities will continue to find another applicable "cmd" block (toplevel
15292 + "default authorization" may get into effect as the last resort).
15294 + "default service" keyword takes then another meaning: In non-recursive mode
15295 + it will mean "if the command wasn't found". In fully-recursive mode it will
15296 + mean "if any cmd block didn't decide".
15298 + Please keep in mind that "service =" (with its possible "protocol =" mate)
15299 + has always the same behaviour, nothing is changed with "authorization =
15300 + recursive" enabled. Its functionality is already a bit complex (with AV
15301 + pairs get erased, which added, which copied, which are optional from NAS,
15302 + which optional from Daemon, whether to do default permit or deny etc.).
15303 + Fortunately we didn't found that there would be needed some extended
15304 + 'recursiveness' functionality of "service" for application of NAS-host based
15307 +3) "host" entities are not recursive at all (=its attributes aren't looked up
15308 + in its parent groups) without "authorization = recursive". This isn't any
15309 + much change as in the previous versions of Daemon "host" entity was either
15310 + completely unsupported or it was supported only with the only one attribute:
15312 + "key": Attribute defines different protocol key (instead of the specified
15313 + toplevel one) for the specified host. Its use is recommended to
15314 + improve overall network security (by using unique key for each NAS).
15316 USING PROGRAMS TO DO AUTHORIZATION
15317 ----------------------------------
15319 diff --git a/utils.c b/utils.c
15320 index b597e70..43b50f3 100644
15323 @@ -17,19 +17,36 @@
15324 FITNESS FOR A PARTICULAR PURPOSE.
15327 -#include "tac_plus.h"
15329 -#ifdef STDLIB_MALLOC
15330 +#include "tac_plus.h"
15332 -#include <stdlib.h>
15333 +#include <stdlib.h> /* malloc() can be found in <stdlib.h> OR <malloc.h> */
15334 +#ifdef HAVE_MALLOC_H
15335 +#include <malloc.h>
15337 +#include <string.h>
15338 +#ifdef HAVE_FCNTL_H
15339 +#include <fcntl.h> /* for "struct flock" */
15341 +#include <errno.h>
15342 +#ifdef HAVE_UNISTD_H
15343 +#include <unistd.h>
15345 +#ifdef HAVE_SYSLOG_H
15346 +#include <syslog.h>
15348 +#ifdef HAVE_SYS_SYSLOG_H
15349 +#include <sys/syslog.h>
15352 -#else /* !STDLIB_MALLOC */
15353 +#include "utils.h"
15354 +#include "report.h"
15357 -#include <malloc.h>
15359 -#endif /* STDLIB_MALLOC */
15360 +void *tac_malloc TAC_ARGS((int size));
15367 @@ -49,9 +66,11 @@ int size;
15372 +void *tac_realloc TAC_ARGS((void *ptr, int size));
15375 tac_realloc(ptr, size)
15381 @@ -70,6 +89,9 @@ int size;
15385 +void tac_exit TAC_ARGS((int status)) G_GNUC_NORETURN;
15391 @@ -78,9 +100,11 @@ int status;
15395 +char *tac_strdup TAC_ARGS((const char *p));
15402 char *n = strdup(p);
15404 @@ -91,6 +115,8 @@ char *p;
15408 +char *tac_make_string TAC_ARGS((u_char *p, int len));
15411 tac_make_string(p, len)
15413 @@ -116,9 +142,13 @@ int len;
15414 /* return a pointer to the end of substring in string, or NULL. Substring
15415 must begin at start of string.
15419 +const char *tac_find_substring TAC_ARGS((const char *substring, const char *string));
15422 tac_find_substring(substring, string)
15423 -char *substring, *string;
15424 +const char *substring;
15425 +const char *string;
15429 @@ -190,6 +220,8 @@ bcmp(s1,s2,n)
15430 are at the mercy of SUN's lockd, which is probably a bad idea
15433 +int tac_lockfd TAC_ARGS((char *filename, int lockfd));
15436 tac_lockfd (filename, lockfd)
15438 @@ -273,7 +305,8 @@ int lockfd;
15439 are at the mercy of SUN's lockd, which is probably a bad idea
15443 +#if 0 /* unused */
15445 tac_unlockfd (filename,lockfd)
15448 @@ -303,3 +336,184 @@ int lockfd;
15452 +#endif /* unused */
15454 +/* Management of bidirectional lists.
15457 +#ifdef TAC_LIST_PARANOIA
15459 +static void tac_list_check_magic TAC_ARGS((const struct tac_list *list));
15462 +tac_list_check_magic(list)
15463 +const struct tac_list *list;
15465 + if (list->_magic != TAC_LIST_MAGIC)
15466 + report(LOG_ERR, "MAGIC fail for tac_list");
15469 +static void tac_list_node_check_magic TAC_ARGS((const struct tac_list_node *node));
15472 +tac_list_node_check_magic(node)
15473 +const struct tac_list_node *node;
15475 + if (node->_magic != TAC_LIST_NODE_MAGIC)
15476 + report(LOG_ERR, "MAGIC fail for tac_list_node");
15478 +#else /* TAC_LIST_PARANOIA */
15480 +#define tac_list_check_magic(list)
15481 +#define tac_list_node_check_magic(node)
15483 +#endif /* TAC_LIST_PARANOIA */
15486 +void tac_list_init TAC_ARGS((struct tac_list *list));
15489 +tac_list_init(list)
15490 +struct tac_list *list;
15492 +#ifdef TAC_LIST_PARANOIA
15493 + list->_magic = TAC_LIST_MAGIC;
15495 + list->_head = NULL;
15496 + list->_tail = NULL;
15498 + tac_list_check_magic(list);
15501 +void tac_list_node_init TAC_ARGS((struct tac_list_node *node));
15504 +tac_list_node_init(node)
15505 +struct tac_list_node *node;
15507 +#ifdef TAC_LIST_PARANOIA
15508 + node->_magic = TAC_LIST_NODE_MAGIC;
15510 + node->_list = NULL;
15512 + tac_list_node_check_magic(node);
15515 +struct tac_list *tac_list_node_get_list TAC_ARGS((struct tac_list_node *node));
15518 +tac_list_node_get_list(node)
15519 +struct tac_list_node *node;
15521 + tac_list_node_check_magic(node);
15523 + return (node->_list);
15526 +struct tac_list_node *tac_list_first_node TAC_ARGS((struct tac_list *list));
15528 +struct tac_list_node *
15529 +tac_list_first_node(list)
15530 +struct tac_list *list;
15532 + tac_list_check_magic(list);
15534 + return (list->_head);
15537 +#if 0 /* unused */
15538 +struct tac_list_node *tac_list_last_node TAC_ARGS((struct tac_list *list));
15540 +struct tac_list_node *
15541 +tac_list_last_node(list)
15542 +struct tac_list *list;
15544 + tac_list_check_magic(list);
15546 + return (list->_tail);
15548 +#endif /* unused */
15550 +void tac_list_addhead TAC_ARGS((struct tac_list *list, struct tac_list_node *node));
15553 +tac_list_addhead(list, node)
15554 +struct tac_list *list;
15555 +struct tac_list_node *node;
15557 + tac_list_check_magic(list);
15558 + tac_list_node_check_magic(node);
15560 + if ((node->_next = list->_head))
15561 + node->_next->_prev = node;
15562 + list->_head = node;
15563 + node->_prev = NULL;
15564 + if (!list->_tail)
15565 + list->_tail = node;
15566 + node->_list = list;
15569 +void tac_list_addtail TAC_ARGS((struct tac_list *list, struct tac_list_node *node));
15572 +tac_list_addtail(list, node)
15573 +struct tac_list *list;
15574 +struct tac_list_node *node;
15576 + tac_list_check_magic(list);
15577 + tac_list_node_check_magic(node);
15579 + if ((node->_prev = list->_tail))
15580 + node->_prev->_next = node;
15581 + list->_tail = node;
15582 + node->_next = NULL;
15583 + if (!list->_head)
15584 + list->_head = node;
15585 + node->_list = list;
15588 +struct tac_list_node *tac_list_node_next TAC_ARGS((struct tac_list_node *node));
15590 +struct tac_list_node *
15591 +tac_list_node_next(node)
15592 +struct tac_list_node *node;
15594 + tac_list_node_check_magic(node);
15596 + return (node->_next);
15599 +#if 0 /* unused */
15600 +struct tac_list_node *tac_list_node_prev TAC_ARGS((struct tac_list_node *node));
15602 +struct tac_list_node *
15603 +tac_list_node_prev(node)
15604 +struct tac_list_node *node;
15606 + tac_list_node_check_magic(node);
15608 + return (node->_prev);
15610 +#endif /* unused */
15612 +void tac_list_node_remove TAC_ARGS((struct tac_list_node *node));
15615 +tac_list_node_remove(node)
15616 +struct tac_list_node *node;
15618 + tac_list_node_check_magic(node);
15619 + tac_list_check_magic(node->_list);
15622 + node->_next->_prev = node->_prev;
15624 + node->_list->_tail = node->_prev;
15627 + node->_prev->_next = node->_next;
15629 + node->_list->_head = node->_next;
15631 + node->_list = NULL;
15633 diff --git a/utils.h b/utils.h
15634 new file mode 100644
15635 index 0000000..f8c39e8
15642 +#include "tac_plus.h"
15644 +#include <sys/types.h> /* for u_* */
15649 +#define TAC_LIST_PARANOIA 1
15652 +/* Bidirectional lists */
15654 +#ifdef TAC_LIST_PARANOIA
15655 +#define TAC_LIST_MAGIC (0xBEF78147U)
15656 +#define TAC_LIST_NODE_MAGIC (0x297DA735U)
15660 +#ifdef TAC_LIST_PARANOIA
15663 + struct tac_list_node *_head, *_tail;
15666 +struct tac_list_node {
15667 +#ifdef TAC_LIST_PARANOIA
15670 + struct tac_list_node *_next, *_prev;
15671 + struct tac_list *_list;
15675 +extern void *tac_malloc TAC_ARGS((int size));
15676 +extern void *tac_realloc TAC_ARGS((void *ptr, int size));
15677 +extern void tac_exit TAC_ARGS((int status)) G_GNUC_NORETURN;
15678 +extern char *tac_strdup TAC_ARGS((const char *p));
15679 +extern char *tac_make_string TAC_ARGS((u_char *p, int len));
15680 +extern const char *tac_find_substring TAC_ARGS((const char *substring, const char *string));
15681 +extern int tac_lockfd TAC_ARGS((char *filename, int lockfd));
15683 +/* Bidirectional lists: */
15685 +extern void tac_list_init TAC_ARGS((struct tac_list *list));
15686 +extern void tac_list_node_init TAC_ARGS((struct tac_list_node *node));
15687 +extern struct tac_list *tac_list_node_get_list TAC_ARGS((struct tac_list_node *node));
15688 +struct tac_list_node *tac_list_first_node TAC_ARGS((struct tac_list *list));
15689 +struct tac_list_node *tac_list_last_node TAC_ARGS((struct tac_list *list));
15690 +extern void tac_list_addhead TAC_ARGS((struct tac_list *list, struct tac_list_node *node));
15691 +extern void tac_list_addtail TAC_ARGS((struct tac_list *list, struct tac_list_node *node));
15692 +extern struct tac_list_node *tac_list_node_next TAC_ARGS((struct tac_list_node *node));
15693 +extern struct tac_list_node *tac_list_node_prev TAC_ARGS((struct tac_list_node *node));
15694 +extern void tac_list_node_remove TAC_ARGS((struct tac_list_node *node));
15697 +#endif /* UTILS_H */