openpgp: 7E25094870599135A83DD2C6C446E92ECE0D66B2
[www.jankratochvil.net.git] / project / tac_plus / tac_plus-F4.0.3.alpha.8.gts4.diff
1 diff --git a/.exrc b/.exrc
2 new file mode 100644
3 index 0000000..d51ef7d
4 --- /dev/null
5 +++ b/.exrc
6 @@ -0,0 +1,2 @@
7 +set tabstop=8
8 +set shiftwidth=4
9 diff --git a/Makefile.am b/Makefile.am
10 new file mode 100644
11 index 0000000..8d609b1
12 --- /dev/null
13 +++ b/Makefile.am
14 @@ -0,0 +1,126 @@
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.
18 +#
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.
27 +#
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.
33 +
34 +
35 +AUTOMAKE_OPTIONS       = foreign
36 +
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
43 +EXTRA_DIST             = \
44 +       CHANGES                 \
45 +       README.LDAP             \
46 +       README.PAM              \
47 +       users_guide             \
48 +       tac_plus.spec.in        \
49 +       convert.pl              \
50 +       tac_plus.cfg            \
51 +       tac_plus.init           \
52 +       tac_plus.rotate         \
53 +       tac_plus.sql            \
54 +       tac_plus.pam            \
55 +       $(tacacssysconf_DATA)   \
56 +       $(man_MANS)             \
57 +       $(noinst_MANS)
58 +
59 +generate_passwd_SOURCES        = generate_passwd.c
60 +
61 +tac_plus_SOURCES       = \
62 +       acct.c          acct.h          \
63 +       authen.c        authen.h        \
64 +       author.c        author.h        \
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     \
72 +       dump.c          dump.h          \
73 +       enable.c        enable.h        \
74 +       encrypt.c       encrypt.h       \
75 +       expire.c        expire.h        \
76 +       hash.c          hash.h          \
77 +       main.c          main.h          \
78 +       md5.c           md5.h           \
79 +       packet.c        packet.h        \
80 +       parse.c         parse.h         \
81 +       programs.c      programs.h      \
82 +       pw.c            pw.h            \
83 +       pwlib.c         pwlib.h         \
84 +       report.c        report.h        \
85 +       sendauth.c      sendauth.h      \
86 +       sendpass.c      sendpass.h      \
87 +       time_limit.c    time_limit.h    \
88 +       utils.c         utils.h         \
89 +       mschap.h        \
90 +       tac_regmagic.h  \
91 +       tac_plus.h
92 +
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)
98 +use                    = @COND_USE@
99 +use_o                  = $(filter %.o,$(use:.c=.o))
100 +
101 +cond_DB                = db.c          db.h
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
113 +
114 +cond   = \
115 +       $(cond_DB)              \
116 +       $(cond_DB_MYSQL)        \
117 +       $(cond_DB_NULL)         \
118 +       $(cond_DB_PGSQL)        \
119 +       $(cond_USE_LDAP)        \
120 +       $(cond_MAXSESS)         \
121 +       $(cond_MSCHAP)          \
122 +       $(cond_SKEY)            \
123 +       $(cond_USE_PAM)         \
124 +       $(cond_TCPWRAPPER)      \
125 +       $(cond_WITH_INCLUDED_REGEX)
126 +
127 +
128 +# These rules were not migrated from Makefile.in as I don't have
129 +# (and I don't know) 'purify' tool:
130 +#
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)
136 +# 
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
142 new file mode 100644
143 index 0000000..755b19e
144 --- /dev/null
145 +++ b/README.LDAP
146 @@ -0,0 +1,146 @@
147 +                   LDAP Authentification with Tacacs+
148 +                   ----------------------------------
149 +
150 +
151 +Author : Harpes Patrick (patrick.harpes@tudor.lu)
152 +         Jahnen Andreas (andreas.jahnen@tudor.lu)
153 +Date   : 16.03.2001
154 +
155 +License: 
156 +--------
157 +
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.     
162 +
163 +
164 +This document aim to describe how to perform LDAP authentification for tacacs+.
165 +
166 +
167 +Requirements:
168 +-------------
169 +
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/
172 +2) openldap package
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 
177 +   OpenLDAP)
178 +
179 +Overview:
180 +---------
181 +                                            ------------            ----------------
182 +                                            - Server   -            - Notes DOMINO -
183 +              ----------------              - running  -____LDAP____- LDAP Server  -
184 +              - CISCO Dialup -__tacacs+_____- tacacs+  -            -    or        -
185 +              -   Router     -              -          -            - other LDAP   -
186 +              ----------------              ------------            - Server       -
187 +                                                                    ---------------
188 +
189 +The CISCO router sends tacacs+ request to the tacacs+ server. This one uses the LDAP
190 +server to authentificate the user.
191 +
192 +
193 +HowTo configure the CISCO router?
194 +---------------------------------
195 +
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/
198 +
199 +HowTo install the tacacs+ package with LDAP support?
200 +----------------------------------------------------
201 +
202 +To enable the LDAP support on the tacacs+ package, you have to perform the following steps:
203 +
204 +   1. Install the Open LDAP package (version 2.0.7) (www.openldap.org)
205 +      Refer to the INSTALL document to build this package.
206 +
207 +   2. Unpack the tacacs+ package in /usr/local/src
208 +      # tar -zxvf  tac_plus.F4.0.3-v8.alpha.tar.gz  
209 +
210 +   3. Use the configure script to create the Makefiles
211 +
212 +      # cd /usr/local/src/tac_plus.F5.0.0.alpha/   
213 +      # ./configure --with-ldap
214 +
215 +      You can use ./configure --help to get more options
216 +
217 +   4. Compile the package
218 +
219 +      # make tac_plus
220 +
221 +   5. Set your LD_LIBRARY_PATH to include the LDAP libraries
222 +
223 +      # LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH
224 +
225 +
226 +HowTo configure tacacs+ for using the LDAP support
227 +--------------------------------------------------
228 +
229 +To use the LDAP authentification, use the following simple tacacs+ configuration file
230 +
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>"
234 +   user=DEFAULT {
235 +          service = ppp protocol = ip {
236 +          }
237 +   }
238 +
239 +
240 +For more information on the configuration file please use the complete tacacs+ documentation.
241 +
242 +
243 +How to start the tacacs+ daemon
244 +-------------------------------
245 +
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
249 +
250 +
251 +How to configure the LDAP server
252 +--------------------------------
253 +
254 +a) Notes Domino LDAP server
255 +---------------------------
256 +
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"). 
260 +
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.
266 +
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.
269 +
270 +
271 +b) Open LDAP
272 +------------
273 +
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.
276 +
277 +
278 +Security
279 +---------
280 +
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. 
283 +
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 
286 +passwords. 
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.
289 +
290 +Good luck,
291
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
295 --- a/README.PAM
296 +++ b/README.PAM
297 @@ -36,5 +36,3 @@ into tac_plus.conf.
298  
299  
300  Max Liccardo <ravel@tiscalinet.it>
301 -
302 -
303 diff --git a/acconfig.h b/acconfig.h
304 new file mode 100644
305 index 0000000..72e7998
306 --- /dev/null
307 +++ b/acconfig.h
308 @@ -0,0 +1,97 @@
309 +/*     acconfig.h
310 + *
311 + *     $Id$
312 + */
313 +
314 +#ifndef TAC_PLUS_CONFIG_H
315 +#define TAC_PLUS_CONFIG_H 1
316 +
317 +@TOP@
318 +
319 +
320 +/* --maintainer-mode
321 + * Sets "/etc/tacacs/tac_plus.cfg" as default config file
322 + */
323 +#undef MAINTAINER_MODE
324 +
325 +/* Missing socklen_t in <sys/socket.h>
326 + * We don't use 'typedef' to not to yet require <stddef.h> included here.
327 + */
328 +#undef socklen_t
329 +
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
332 + * /etc/shadow */
333 +#undef SHADOW_PASSWORDS
334 +
335 +/* Check for some fields in <pwd.h>/struct passwd and <utmp.h>/struct utmp
336 + */
337 +#undef HAVE_PASSWD_PW_AGE
338 +#undef HAVE_PASSWD_PW_COMMENT
339 +#undef HAVE_UTMP_UT_HOST
340 +
341 +/* All OSes detected by configure.in:
342 + */
343 +#undef LINUX
344 +#undef GLIBC
345 +#undef SOLARIS
346 +#undef FREEBSD
347 +#undef HPUX
348 +#undef AIX
349 +#undef MIPS
350 +
351 +/* --with-pam */
352 +#undef USE_PAM
353 +/* --with-ldap */
354 +#undef USE_LDAP
355 +/* --with-db */
356 +#undef DB
357 +/* --with-db */
358 +#undef DB_NULL
359 +/* --with-mysql */
360 +#undef DB_MYSQL
361 +/* --with-pgsql */
362 +#undef DB_PGSQL
363 +/* --enable-maxsess */
364 +#undef MAXSESS
365 +/* --with-libwrap */
366 +#undef TCPWRAPPER
367 +/* --with-skey */
368 +#undef SKEY
369 +/* --with-mschap[=des] */
370 +#undef MSCHAP
371 +#undef 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
379 +
380 +
381 +@BOTTOM@
382 +
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) */
389 +
390 +#if SIZEOF_UNSIGNED_SHORT == 4
391 +typedef unsigned short tac_uint32;
392 +#else
393 +#if SIZEOF_UNSIGNED_INT == 4
394 +typedef unsigned int tac_uint32;
395 +#else
396 +#if SIZEOF_UNSIGNED_LONG == 4
397 +typedef unsigned long tac_uint32;
398 +#else
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 */
403 +
404 +
405 +#endif /* TAC_PLUS_CONFIG_H */
406 diff --git a/acct.c b/acct.c
407 index 315064f..2145cef 100644
408 --- a/acct.c
409 +++ b/acct.c
410 @@ -17,18 +17,37 @@
411     FITNESS FOR A PARTICULAR PURPOSE.
412  */
413  
414 +
415  #include "tac_plus.h"
416  
417 +#include <stdlib.h>
418 +#include <netinet/in.h>                /* for ntohl() */
419 +
420 +#include "acct.h"
421 +#include "report.h"
422 +#include "packet.h"
423 +#include "utils.h"
424 +#include "do_acct.h"
425 +#include "main.h"
426 +#include "do_author.h"                 /* for "struct identity" */
427 +#include "cfgfile.h"
428 +
429 +#ifdef MAXSESS
430 +#include "maxsess.h"
431 +#endif
432 +#ifdef DB
433 +#include "db.h"
434 +#endif
435 +
436 +
437 +static void account TAC_ARGS((u_char *pak));
438 +
439 +
440  /*
441   *  Come here when we receive an Start Accounting packet
442   */
443  
444 -void account();
445 -
446 -/* For  DB accounting */
447 -#ifdef DB
448 -int db_acct();
449 -#endif /* DB */
450 +void accounting TAC_ARGS((u_char *pak));
451  
452  void
453  accounting(pak)
454 @@ -37,8 +56,8 @@ u_char *pak;
455      struct acct *acct_pak;
456      u_char *p;
457      HDR *hdr;
458 -    u_char *read_packet();
459 -    int i, len;
460 +    int i;
461 +    unsigned long len;
462  
463      if (debug & DEBUG_ACCT_FLAG)
464         report(LOG_DEBUG, "Start accounting request");
465 @@ -59,7 +78,7 @@ u_char *pak;
466         len += p[i];
467      }
468  
469 -    if (len != ntohl(hdr->datalength)) {
470 +    if (len != (unsigned long) ntohl(hdr->datalength)) {
471         send_error_reply(TAC_PLUS_ACCT, NULL);
472         return;
473      }
474 @@ -69,7 +88,9 @@ u_char *pak;
475      free(pak);
476  }
477  
478 -void
479 +static void account TAC_ARGS((u_char *pak));
480 +
481 +static void
482  account(pak)
483  u_char *pak;
484  {
485 @@ -123,6 +144,8 @@ u_char *pak;
486  
487      identity.priv_lvl = acct_pak->priv_lvl;
488  
489 +    cfg_request_identity(&identity);
490 +
491      rec.identity = &identity;
492  
493      /* Now process cmd args */
494 diff --git a/acct.h b/acct.h
495 new file mode 100644
496 index 0000000..0640ae6
497 --- /dev/null
498 +++ b/acct.h
499 @@ -0,0 +1,12 @@
500 +#ifndef ACCT_H
501 +#define ACCT_H 1
502 +
503 +#include "tac_plus.h"
504 +
505 +#include <sys/types.h>         /* for u_* */
506 +
507 +
508 +extern void accounting TAC_ARGS((u_char *pak));
509 +
510 +
511 +#endif /* ACCT_H */
512 diff --git a/authen.c b/authen.c
513 index a12745e..7c873fe 100644
514 --- a/authen.c
515 +++ b/authen.c
516 @@ -17,16 +17,43 @@
517     FITNESS FOR A PARTICULAR PURPOSE.
518  */
519  
520 +
521  #include "tac_plus.h"
522  
523 -static int choose();
524 -static void authenticate();
525 -static void do_start();
526 +#include <stdlib.h>
527 +#include <netinet/in.h>                /* for ntohl() */
528 +
529 +#include "authen.h"
530 +#include "packet.h"
531 +#include "report.h"
532 +#include "utils.h"
533 +#include "choose_authen.h"
534 +#include "do_author.h"         /* for "struct identity" */
535 +#include "main.h"
536 +#include "cfgfile.h"
537 +
538 +#ifdef TCPWRAPPER
539 +#include "tcpwrap.h"
540 +#endif
541 +
542 +
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));
546 +
547 +
548 +/* Configurable:
549 + */
550 +
551 +#define TAC_PLUS_MAX_ITERATIONS 50
552 +
553  
554  /*
555   *  Come here when we receive an authentication START packet
556   */
557  
558 +void authen TAC_ARGS((u_char *pak));
559 +
560  void
561  authen(pak)
562  u_char *pak;
563 @@ -39,9 +66,9 @@ u_char *pak;
564      start = (struct authen_start *) (pak + TAC_PLUS_HDR_SIZE);
565  
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)");
573         return;
574      }
575 @@ -65,6 +92,8 @@ u_char *pak;
576   * attempt to authenticate.
577   */
578  
579 +static void do_start TAC_ARGS((u_char *pak));
580 +
581  static void
582  do_start(pak)
583  u_char *pak;
584 @@ -109,6 +138,8 @@ u_char *pak;
585  
586      identity.priv_lvl = start->priv_lvl;
587  
588 +    cfg_request_identity(&identity);
589 +
590      /* The authen_data structure */
591  
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 */
596  
597 +static int choose TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
598 +
599  static int
600  choose(datap, typep)
601  struct authen_data *datap;
602 @@ -293,6 +326,8 @@ struct authen_type *typep;
603      /* NOTREACHED */
604  }
605  
606 +static void authenticate TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
607 +
608  /* Perform authentication assuming we have successfully chosen an
609     authentication method */
610  static void
611 @@ -303,7 +338,7 @@ struct authen_type *typep;
612      int iterations = 0;
613      u_char *reply, *p;
614      struct authen_cont *cont;
615 -    int (*func) ();
616 +    int (*func) TAC_ARGS((struct authen_data *data));
617  
618      if (debug & DEBUG_PACKET_FLAG)
619         report(LOG_DEBUG, "Calling authentication function");
620 @@ -469,4 +504,3 @@ struct authen_type *typep;
621         /* NOTREACHED */
622      }
623  }
624 -
625 diff --git a/authen.h b/authen.h
626 new file mode 100644
627 index 0000000..d89d9cc
628 --- /dev/null
629 +++ b/authen.h
630 @@ -0,0 +1,12 @@
631 +#ifndef AUTHEN_H
632 +#define AUTHEN_H 1
633 +
634 +#include "tac_plus.h"
635 +
636 +#include <sys/types.h>         /* for u_* */
637 +
638 +
639 +extern void authen TAC_ARGS((u_char *pak));
640 +
641 +
642 +#endif /* AUTHEN_H */
643 diff --git a/author.c b/author.c
644 index a9f2277..7a05db5 100644
645 --- a/author.c
646 +++ b/author.c
647 @@ -17,12 +17,27 @@
648     FITNESS FOR A PARTICULAR PURPOSE.
649  */
650  
651 +
652  #include "tac_plus.h"
653  
654 +#include <stdlib.h>
655 +#include <netinet/in.h>                /* for ntohl() */
656 +
657 +#include "author.h"
658 +#include "report.h"
659 +#include "packet.h"
660 +#include "utils.h"
661 +#include "do_author.h"
662 +#include "main.h"
663 +#include "cfgfile.h"
664 +
665 +
666  /*
667   *  Come here when we receive an authorization START packet
668   */
669  
670 +void author TAC_ARGS((u_char *pak));
671 +
672  void
673  author(pak)
674  u_char *pak;
675 @@ -34,7 +49,8 @@ u_char *pak;
676      u_char *p;
677      u_char *argsizep;
678      char **cmd_argp;
679 -    int i, len;
680 +    int i;
681 +    unsigned long len;
682  
683      if (debug & DEBUG_AUTHOR_FLAG)
684         report(LOG_DEBUG, "Start authorization request");
685 @@ -58,7 +74,7 @@ u_char *pak;
686         len += p[i];
687      }
688  
689 -    if (len != ntohl(hdr->datalength)) {
690 +    if (len != (unsigned long) ntohl(hdr->datalength)) {
691         send_error_reply(TAC_PLUS_AUTHOR, NULL);
692         return;
693      }
694 @@ -95,6 +111,8 @@ u_char *pak;
695  
696      identity.priv_lvl = apak->priv_lvl;
697  
698 +    cfg_request_identity(&identity);
699 +
700      /* The author_data structure */
701  
702      author_data.id = &identity;        /* user id */
703 diff --git a/author.h b/author.h
704 new file mode 100644
705 index 0000000..0e3a2ce
706 --- /dev/null
707 +++ b/author.h
708 @@ -0,0 +1,12 @@
709 +#ifndef AUTHOR_H
710 +#define AUTHOR_H 1
711 +
712 +#include "tac_plus.h"
713 +
714 +#include <sys/types.h>         /* for u_* */
715 +
716 +
717 +extern void author TAC_ARGS((u_char *pak));
718 +
719 +
720 +#endif /* AUTHOR_H */
721 diff --git a/autogen b/autogen
722 new file mode 100755
723 index 0000000..83862fd
724 --- /dev/null
725 +++ b/autogen
726 @@ -0,0 +1,47 @@
727 +#! /bin/sh
728 +#
729 +#      autogen
730 +#
731 +#      Copyright (C) 1999, 2000, 2001
732 +#      Partition Surprise Team <surprise-dev@lists.sourceforge.net>
733 +#
734 +#      $Id$
735 +#
736 +
737 +
738 +# Run this to generate all the initial makefiles, etc.
739 +
740 +set -e
741 +if test "x$1" = "xBASH" ;then
742 +  shift
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 "$@"
747 +      exit $?
748 +    fi
749 +  done
750 +  echo "ERROR: Unable to find 'bash' interpreter needed for self-execution!"
751 +  exit 1
752 +fi;fi
753 +
754 +defaultCONFDEFS="" # --enable-debug --without-efence
755 +project="tac_plus"
756 +automake_gnu=false
757 +want_tarZ=false
758 +want_gettext=false
759 +want_libtool=false
760 +#upload="vellum.cz:WWW/sw/"
761 +docdir=""
762 +subdirs=""
763 +
764 +CLEAN_LOCAL="
765 +  .print_userprogs
766 +  tac_plus
767 +  generate_passwd
768 +"
769 +
770 +ARGS_HELP_LOCAL="\
771 +"
772 +
773 +source ./autogen-body
774 diff --git a/autogen-body b/autogen-body
775 new file mode 100644
776 index 0000000..6856444
777 --- /dev/null
778 +++ b/autogen-body
779 @@ -0,0 +1,259 @@
780 +#
781 +#      autogen-body
782 +#
783 +#      Placed into the public domain by
784 +#      Partition Surprise Team <surprise-dev@lists.sourceforge.net>
785 +#
786 +#      $Id$
787 +#
788 +
789 +
790 +# Executable code to be included from ./autogen script
791 +
792 +# Expected variables:
793 +# defaultCONFDEFS, project, want_tarZ, upload, docdir, subdirs, CLEAN_LOCAL
794 +# function PREP_LOCAL
795 +
796 +set -e
797 +t=/tmp/autogen.$$
798 +autogen_failed=true
799 +cleaup_dir="$PWD"
800 +automake_reqd=""
801 +function cleanup
802 +{
803 +  cd "$cleanup_dir"
804 +  rm -f "$t.*"
805 +  if $automake_gnu;then for i in $automake_reqd;do if [ '!' -s "$i" ];then rm -f "$i";fi;done;fi
806 +}
807 +EXITmsg_do=true
808 +trap '
809 +  cleanup
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"
813 +      EXITmsg_do=false
814 +      fi
815 +    exit 1
816 +    fi
817 +  ' EXIT
818 +
819 +if [ "$1" = help -o "$1" = -h -o "$1" = --help ];then cat <<EOHELP
820 +Beware!: "autogen" is a tool only for maintainers.
821 +
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
831 +$ARGS_HELP_LOCAL
832 +EOHELP
833 +  autogen_failed=false
834 +  exit
835 +  fi
836 +
837 +
838 +if [ -f "$HOME/.$project.autogen" ];then
839 +  . "$HOME/.$project.autogen"
840 +  fi
841 +CONFDEFS="$defaultCONFDEFS $CONFDEFS"
842 +
843 +function funcdo
844 +{
845 +local func="$1";
846 +
847 +  shift
848 +  if declare -f "$func" >/dev/null;then
849 +local func_exit=false
850 +
851 +    "$func" "$@"
852 +    if $func_exit;then exit;fi
853 +  fi
854 +}
855 +funcdo ARGS_LOCAL "$@"
856 +
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
861 +    done
862 +  if [ $b = X ];then
863 +    echo Build directory not reachable, searched: $builds
864 +    exit 1
865 +    fi
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 .
879 +  ls -l $project-*
880 +  if [ "$1" = rpmup ];then
881 +    echo "Uploading $[`cat $project-*|wc -c`] bytes..."
882 +    if [ -n "$upload" ];then
883 +      scp -v $project-* "$upload"
884 +    else
885 +      echo "Upload not done."
886 +    fi
887 +  fi
888 +  autogen_failed=false
889 +  exit
890 +fi
891 +
892 +function subdo
893 +{
894 +  for i in _ $subdirs;do
895 +    if [ -d $i ];then
896 +      cd "$i"
897 +      ./autogen $subdir_args
898 +      cd ..
899 +      fi
900 +    done
901 +}
902 +subdir_args="${*:-dist}"
903 +if [ "$subdir_args" = "copy" ];then
904 +  subdir_args="copy dist"
905 +  fi
906 +
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).
911 +
912 +CLEANFILES="
913 +  *~ .#*
914 +  *.orig *.rej
915 +  core
916 +  Makefile Makefile.in
917 +  TAGS tags ID
918 +  .deps .libs
919 +  *.[oa] *.l[oa]
920 +
921 +  ./errs*
922 +  ./intl
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
928 +  ./install-sh
929 +  ./aclocal.m4
930 +  ./missing
931 +  ./mkinstalldirs
932 +  ./libtool ./ltconfig ./ltmain.sh
933 +  ./ChangeLog
934 +  ./ABOUT-NLS ./COPYING
935 +  ./$project-[0-9]* ./$project-devel-[0-9]*
936 +  ./$project.spec ./$project.m4 ./$project.spec.m4
937 +  macros/macros.dep
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
939 +
940 +  $CLEAN_LOCAL
941 +  "
942 +if [ -n "$docdir" ];then
943 +CLEANFILES="
944 +  $docdir/*.html
945 +  $docdir/*.info*
946 +  $docdir/*.txt
947 +  $docdir/*.tex
948 +  $docdir/*.sgml
949 +  $CLEANFILES"
950 +  fi
951 +if [ "$1" != sym ];then CLEANFILES="$CLEANFILES `find . -type l`";fi
952 +CLEANFILES="`echo "$CLEANFILES"|tr ' ' '\n'|sed 's,^\./\(.*/.*\)$,\1,'|sort|uniq|grep -v '^ *$'`"
953 +true >"$t.find"
954 +rm -f "$t.discard"
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"
959 +  fi;done
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
962 +    (cd $dir
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
968 +       rm -rf `
969 +         if [ "$1" = fullclean ];then cat .cvsignore
970 +         else grep -v '^\.cvsignore' <.cvsignore
971 +         fi`
972 +       fi
973 +     )
974 +    fi;done
975 +  done
976 +rm -f "$t.find" "$t.discard"
977 +if [ "$1" = tarprep ];then
978 +  autogen_failed=false
979 +  exit
980 +  fi
981 +if [ "$1" = tar ];then
982 +  subdir_args=tarprep
983 +  subdo
984 +  mydir="$(basename `pwd`)"
985 +  cd ..
986 +  tar cf - \
987 +    $(for fi in `find "$mydir" -name .cvsignore`;do sed "s,^,--exclude=`dirname $fi`/," <$fi;done) \
988 +    "$mydir"
989 +  autogen_failed=false
990 +  exit
991 +  fi
992 +if [ "$1" != "${1#*clean}" ];then
993 +  subdo
994 +  autogen_failed=false
995 +  exit 0
996 +  fi
997 +
998 +funcdo PREP_LOCAL "$@"
999 +subdo
1000 +
1001 +if [ "$1" = copy ];then COPY=--copy;shift
1002 +else unset COPY|cat  # |cat construction is used to not fail in "set -e" state
1003 +fi
1004 +
1005 +if test -d po;then
1006 +  touch po/POTFILES.in
1007 +fi
1008 +aclocal_opts=""
1009 +if test -d macros;then
1010 +  aclocal_opts="-I macros $aclocal_opts"
1011 +fi
1012 +aclocal $aclocal_opts
1013 +if $want_gettext;then
1014 +  gettextize $COPY
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
1017 +fi
1018 +if $want_libtool;then
1019 +  libtoolize $COPY
1020 +fi
1021 +autoheader
1022 +automake_opts=""
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
1027 +fi
1028 +automake --add-missing $COPY $automake_opts
1029 +cleanup
1030 +autoheader
1031 +autoconf
1032 +
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
1036 +  fi
1037 +
1038 +autogen_failed=false
1039 diff --git a/cfgeval.c b/cfgeval.c
1040 new file mode 100644
1041 index 0000000..f0aed72
1042 --- /dev/null
1043 +++ b/cfgeval.c
1044 @@ -0,0 +1,1900 @@
1045 +/*
1046 + * ???():
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.
1050 + *
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.
1059 + *
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.
1063 + */
1064 +
1065 +
1066 +#include "tac_plus.h"
1067 +
1068 +#include <stdlib.h>
1069 +
1070 +#include "cfgeval.h"
1071 +#include "cfgfile.h"
1072 +#include "main.h"
1073 +#include "parse.h"
1074 +#include "report.h"
1075 +#include "hash.h"
1076 +
1077 +
1078 +/* Configurable:
1079 + */
1080 +
1081 +/* Whether to do sanity checks */
1082 +#define SCAN_PARANOIA 1
1083 +
1084 +/* report even no-op scan up-to-date checks */
1085 +#define REPORT_CHECK_SCAN_VERBOSE 0
1086 +
1087 +
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));
1093 +
1094 +
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;
1103 +
1104 +
1105 +/* 'P[FA]_*' object printing section:
1106 + */
1107 +
1108 +static const char *eval_result_to_string TAC_ARGS((int valid, enum eval_result er));
1109 +
1110 +const char *
1111 +eval_result_to_string(valid, er)
1112 +int valid;
1113 +enum eval_result er;
1114 +{
1115 +    if (!valid)
1116 +       return ("!UPDATED");
1117 +
1118 +    switch (er) {
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 ***");
1123 +    }
1124 +    /* NOTREACHED */
1125 +}
1126 +
1127 +static const char *value_scan_func_result_to_string TAC_ARGS((enum value_scan_func_result vsfr));
1128 +
1129 +const char *
1130 +value_scan_func_result_to_string(vsfr)
1131 +enum value_scan_func_result vsfr;
1132 +{
1133 +    switch (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 ***");
1138 +    }
1139 +    /* NOTREACHED */
1140 +}
1141 +
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).
1145 + */
1146 +
1147 +#define PF_VSFR       "%s"
1148 +#define PA_VSFR(vsfr) (value_scan_func_result_to_string((vsfr)))
1149 +
1150 +#define PF_RESULT         "%s"
1151 +#define PA_RESULT(result) (eval_result_to_string(1 /* valid */, (result)))
1152 +
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*"
1158 +
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))
1165 +
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))
1170 +
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))))
1174 +
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)
1179 +
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)
1186 +
1187 +
1188 +/* '{unlink,free}_*()' section:
1189 + */
1190 +
1191 +void unlink_expr TAC_ARGS((struct expr *expr));
1192 +
1193 +/* never depend on "->parent" as it may not yet been filled! */
1194 +void
1195 +unlink_expr(expr)
1196 +struct expr *expr;
1197 +{
1198 +    if (!expr)
1199 +       return;         /* prevent possible DEBUG_CLEAN_FLAG report */
1200 +
1201 +    if (debug & DEBUG_CLEAN_FLAG) {
1202 +       if (expr->membership)
1203 +           report(LOG_DEBUG, "unlink_expr: (of membership): " PF_EXPR,
1204 +                   PA_EXPR(expr));
1205 +       else
1206 +           report(LOG_DEBUG, "unlink_expr: (standalone)");
1207 +    }
1208 +
1209 +    while (expr) {
1210 +
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 */
1214 +
1215 +       switch (expr->type) {
1216 +
1217 +       case S_not:
1218 +           unlink_expr(expr->u.not.child);
1219 +           break;
1220 +
1221 +       case S_and:
1222 +       case S_or:
1223 +           unlink_expr(expr->u.and_or.child_first);
1224 +           break;
1225 +
1226 +       case S_user:
1227 +       case S_host:
1228 +       case S_group:
1229 +           break;
1230 +
1231 +       default:
1232 +           report(LOG_ERR, "Illegal node type %d for unlink_expr", expr->type);
1233 +           return;
1234 +       }
1235 +
1236 +       expr = expr->next;
1237 +    }
1238 +}
1239 +
1240 +void free_expr TAC_ARGS((struct expr *expr));
1241 +
1242 +/* given 'expr' memory WILL be freed! */
1243 +/* never depend on "->parent" as it may not yet been filled! */
1244 +void
1245 +free_expr(expr)
1246 +struct expr *expr;
1247 +{
1248 +struct expr *expr_next;
1249 +
1250 +    if (!expr)
1251 +       return;         /* prevent possible DEBUG_CLEAN_FLAG report */
1252 +
1253 +    if (debug & DEBUG_CLEAN_FLAG)
1254 +       report(LOG_DEBUG, "free_expr: (may be unlinked)");
1255 +
1256 +    while (expr) {
1257 +       expr_next = expr->next;
1258 +       switch (expr->type) {
1259 +
1260 +       case S_not:
1261 +           free_expr(expr->u.not.child);
1262 +           break;
1263 +
1264 +       case S_and:
1265 +       case S_or:
1266 +           free_expr(expr->u.and_or.child_first);
1267 +           break;
1268 +
1269 +       case S_user:
1270 +       case S_host:
1271 +       case S_group:
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 */
1275 +           break;
1276 +
1277 +       default:
1278 +           report(LOG_ERR, "Illegal node type %d for free_expr", expr->type);
1279 +           return;
1280 +       }
1281 +
1282 +       free(expr);
1283 +       expr=expr_next;
1284 +    }
1285 +}
1286 +
1287 +static void unlink_membership TAC_ARGS((struct membership *membership));
1288 +
1289 +static void
1290 +unlink_membership(membership)
1291 +struct membership *membership;
1292 +{
1293 +    ENTITY *parent_entity;
1294 +
1295 +    if (debug & DEBUG_CFGEVAL_FLAG)
1296 +       report(LOG_DEBUG, "unlink_membership: " PF_MEMBERSHIP,
1297 +               PA_MEMBERSHIP(membership));
1298 +
1299 +    parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1300 +
1301 +    /* 'unlink_expr()' may want a lot of existing (linked) resources */
1302 +    unlink_expr(membership->when);
1303 +
1304 +    check_request_scan_membership(membership, 1);      /* invalidate */
1305 +    check_eval_scan_membership(membership, 1);         /* invalidate */
1306 +
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++;
1311 +    }
1312 +#endif
1313 +    parent_entity->to_child_membership_num--;
1314 +
1315 +    tac_list_node_remove(&membership->parent_node);
1316 +    tac_list_node_remove(&membership-> child_node);
1317 +}
1318 +
1319 +/* given 'membership' memory WILL be freed! */
1320 +
1321 +static void free_membership TAC_ARGS((struct membership *membership));
1322 +
1323 +static void
1324 +free_membership(membership)
1325 +struct membership *membership;
1326 +{
1327 +    if (debug & DEBUG_CLEAN_FLAG)
1328 +       report(LOG_DEBUG, "free_membership: (may be unlinked)");
1329 +
1330 +    free_expr(membership->when);
1331 +    free(membership);
1332 +}
1333 +
1334 +/* we are not allowed to free memory here, we are only 'scan_' additional 'free' */
1335 +
1336 +void scan_free_entity TAC_ARGS((ENTITY *entity));
1337 +
1338 +void
1339 +scan_free_entity(entity)
1340 +ENTITY *entity;
1341 +{
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;
1346 +
1347 +    if (debug & DEBUG_CLEAN_FLAG)
1348 +       report(LOG_DEBUG, "scan_free_entity: " PF_ENTITY,
1349 +               PA_ENTITY(entity));
1350 +
1351 +    /* Be careful to keep '->next' ptr before we destroy the structure! */
1352 +
1353 +    for (
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
1357 +           ) {
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);
1362 +    }
1363 +    for (
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
1367 +           ) {
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);
1372 +    }
1373 +}
1374 +
1375 +struct expr *new_expr TAC_ARGS((int type));
1376 +
1377 +struct expr *
1378 +new_expr(type)
1379 +int type;
1380 +{
1381 +    struct expr *expr;
1382 +
1383 +    expr = (struct expr *) tac_malloc(sizeof(struct expr));
1384 +    expr->next = NULL;
1385 +    expr->type = type;
1386 +    switch (expr->type) {
1387 +
1388 +    case S_not:
1389 +       expr->u.not.child = NULL;
1390 +       break;
1391 +
1392 +    case S_and:
1393 +    case S_or:
1394 +       expr->u.and_or.child_first = NULL;
1395 +       break;
1396 +
1397 +    case S_user:
1398 +    case S_host:
1399 +    case S_group:
1400 +       expr->u.entity.entity = NULL;
1401 +       break;
1402 +
1403 +    default:
1404 +       report(LOG_ERR, "Illegal node type %d for new_expr", expr->type);
1405 +       return (expr);  /* it would be probably lethal to return NULL */
1406 +    }
1407 +    return (expr);
1408 +}
1409 +
1410 +static int expr_sink_internal TAC_ARGS((struct expr *expr, struct membership *membership, struct expr *parent));
1411 +
1412 +static int
1413 +expr_sink_internal(expr, membership, parent)
1414 +struct expr *expr;
1415 +struct membership *membership;
1416 +struct expr *parent;
1417 +{
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) {
1424 +
1425 +       case S_not:
1426 +           if (expr_sink_internal(expr->u.not.child, membership, expr /* parent */))
1427 +               return (1);
1428 +           break;
1429 +
1430 +       case S_and:
1431 +       case S_or:
1432 +           if (expr_sink_internal(expr->u.and_or.child_first, membership, expr /* parent */))
1433 +               return (1);
1434 +           break;
1435 +
1436 +       case S_user:
1437 +       case S_host:
1438 +       case S_group:
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)
1444 +                   return (1);
1445 +               expr->u.entity.name = NULL;
1446 +           }
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);
1450 +               return (1);
1451 +           }
1452 +           /* already NULLed for not-yet-existing S_host */
1453 +           free((char *) expr->u.entity.name);
1454 +           expr->u.entity.name = NULL;
1455 +           break;
1456 +
1457 +       default:
1458 +           report(LOG_ERR, "Illegal node type %d for expr_sink", expr->type);
1459 +           return (1);
1460 +       }
1461 +    }
1462 +    return (0);
1463 +}
1464 +
1465 +static int expr_sink TAC_ARGS((struct expr *expr, struct membership *membership));
1466 +
1467 +static int
1468 +expr_sink(expr, membership)
1469 +struct expr *expr;
1470 +struct membership *membership;
1471 +{
1472 +    return (expr_sink_internal(expr, membership, NULL /* parent */));
1473 +}
1474 +
1475 +static struct expr *expr_sink_register_head = NULL;
1476 +
1477 +void expr_sink_register TAC_ARGS((struct expr *expr));
1478 +
1479 +void
1480 +expr_sink_register(expr)
1481 +struct expr *expr;
1482 +{
1483 +    if (!expr)
1484 +       return;
1485 +
1486 +    expr->parent = expr_sink_register_head;
1487 +    expr_sink_register_head = expr;
1488 +}
1489 +
1490 +int expr_sink_commit TAC_ARGS((void));
1491 +
1492 +int
1493 +expr_sink_commit()
1494 +{
1495 +    struct expr *expr;
1496 +
1497 +    while ((expr = expr_sink_register_head)) {
1498 +       expr_sink_register_head = expr->parent;
1499 +       /* 'expr->parent' not defined for 'expr_sink()' */
1500 +
1501 +       if (expr_sink(expr, NULL /* membership */))
1502 +           return (1);         /* failure */
1503 +    }
1504 +    return (0);                /* success */
1505 +}
1506 +
1507 +struct expr *dupl_expr TAC_ARGS((const struct expr *in));
1508 +
1509 +struct expr *
1510 +dupl_expr(in)
1511 +const struct expr *in;
1512 +{
1513 +    struct expr *expr_root = NULL;
1514 +    struct expr **succ_exprp = &expr_root;
1515 +    struct expr *expr;
1516 +
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) {
1523 +
1524 +       case S_not:
1525 +           if (in->u.not.child && in->u.not.child->type==S_not) {
1526 +               free(expr);
1527 +               expr = dupl_expr(in->u.not.child->u.not.child);
1528 +           } else
1529 +               expr->u.not.child = dupl_expr(in->u.not.child);
1530 +           break;
1531 +
1532 +       case S_and:
1533 +       case S_or:
1534 +           if (!in->u.and_or.child_first) {
1535 +               free(expr);
1536 +               continue;
1537 +           } else if (!in->u.and_or.child_first->next) {
1538 +               free(expr);
1539 +               expr = dupl_expr(in->u.and_or.child_first);
1540 +           } else
1541 +               expr->u.and_or.child_first = dupl_expr(in->u.and_or.child_first);
1542 +           break;
1543 +
1544 +       case S_user:
1545 +       case S_host:
1546 +       case S_group:
1547 +           if (in->u.entity.name)
1548 +               expr->u.entity.name = tac_strdup(in->u.entity.name);
1549 +           else
1550 +               expr->u.entity.name = NULL;
1551 +           expr->u.entity.entity = in->u.entity.entity;
1552 +           break;
1553 +
1554 +       default:
1555 +           report(LOG_ERR, "Illegal node type %d for dupl_expr", in->type);
1556 +           free_expr(expr_root);
1557 +           return (NULL);
1558 +       }
1559 +
1560 +       *succ_exprp = expr;
1561 +       succ_exprp = &expr->next;
1562 +    }
1563 +    return (expr_root);
1564 +}
1565 +
1566 +
1567 +/* 'check_*_scan_*()' section:
1568 + */
1569 +
1570 +static void check_request_scan_expr TAC_ARGS((struct expr *expr, int flush));
1571 +
1572 +static void
1573 +check_request_scan_expr(expr, flush)
1574 +struct expr *expr;
1575 +int flush;
1576 +{
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));
1581 +#endif
1582 +
1583 +    if (!flush && expr->request_scan.seq == request_scan_seq)
1584 +       return;         /* up to date */
1585 +
1586 +    expr->request_scan.result = ER_UNKNOWN;
1587 +    expr->request_scan.loop_reported = 0;
1588 +    expr->request_scan.seq = request_scan_seq;
1589 +
1590 +    if (debug & DEBUG_CFGEVAL_FLAG)
1591 +       report(LOG_DEBUG, "check_request_scan_expr: done: " PF_EXPR,
1592 +               PA_EXPR(expr));
1593 +}
1594 +
1595 +static void check_eval_scan_expr TAC_ARGS((struct expr *expr, int flush));
1596 +
1597 +static void
1598 +check_eval_scan_expr(expr, flush)
1599 +struct expr *expr;
1600 +int flush;
1601 +{
1602 +#if REPORT_CHECK_SCAN_VERBOSE
1603 +    if (debug & DEBUG_CFGEVAL_FLAG)
1604 +       report(LOG_DEBUG, "check_eval_scan_expr: " PF_EXPR,
1605 +               PA_EXPR(expr));
1606 +#endif
1607 +
1608 +    if (!flush && expr->eval_scan.seq == eval_scan_seq)
1609 +       return;         /* up to date */
1610 +    check_request_scan_expr(expr, 0);
1611 +
1612 +    switch (expr->type) {
1613 +
1614 +    case S_user:
1615 +    case S_host:
1616 +    case S_group: {
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);
1622 +
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);
1628 +           }
1629 +#else /* SCAN_PARANOIA */
1630 +       tac_list_node_init(&expr->eval_scan.u.entity.notify_expr_node);
1631 +#endif /* SCAN_PARANOIA */
1632 +       } break;
1633 +    }
1634 +
1635 +    expr->eval_scan.seq = eval_scan_seq;       /* used above, keep as LAST! */
1636 +
1637 +    if (debug & DEBUG_CFGEVAL_FLAG)
1638 +       report(LOG_DEBUG, "check_eval_scan_expr: done: " PF_EXPR,
1639 +               PA_EXPR(expr));
1640 +}
1641 +
1642 +static void check_request_scan_membership TAC_ARGS((struct membership *membership, int flush));
1643 +
1644 +static void
1645 +check_request_scan_membership(membership, flush)
1646 +struct membership *membership;
1647 +int flush;
1648 +{
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));
1653 +#endif
1654 +
1655 +    if (!flush && membership->request_scan.seq == request_scan_seq)
1656 +       return;         /* up to date */
1657 +
1658 +#ifdef SCAN_PARANOIA
1659 +    {
1660 +        struct tac_list *virtual_list = tac_list_node_get_list(&membership->request_scan.virtual_membership_node);
1661 +
1662 +        if (virtual_list && virtual_list != &request_virtual_membership_list)
1663 +           report(LOG_ERR, "Illegal list in membership->virtual_membership_node.list");
1664 +       if (virtual_list)
1665 +           tac_list_node_remove(&membership->request_scan.virtual_membership_node);
1666 +    }
1667 +#else /* SCAN_PARANOIA */
1668 +    tac_list_node_init(&membership->request_scan.virtual_membership_node);
1669 +#endif /* SCAN_PARANOIA */
1670 +
1671 +    membership->request_scan.seq = request_scan_seq;   /* used above, keep as LAST! */
1672 +
1673 +    if (debug & DEBUG_CFGEVAL_FLAG)
1674 +       report(LOG_DEBUG, "check_request_scan_membership: done: " PF_MEMBERSHIP,
1675 +               PA_MEMBERSHIP(membership));
1676 +}
1677 +
1678 +/* we are cross-checking (membership<->parent entity)! */
1679 +
1680 +static void check_eval_scan_membership TAC_ARGS((struct membership *membership, int flush));
1681 +
1682 +static void
1683 +check_eval_scan_membership(membership, flush)
1684 +struct membership *membership;
1685 +int flush;
1686 +{
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));
1691 +#endif
1692 +
1693 +    if (!flush && membership->eval_scan.seq == eval_scan_seq)
1694 +       return;         /* up to date */
1695 +    check_request_scan_membership(membership, 0);
1696 +
1697 +    membership->eval_scan.unsolved = 1;
1698 +    membership->eval_scan.seq = eval_scan_seq;
1699 +
1700 +    if (debug & DEBUG_CFGEVAL_FLAG)
1701 +       report(LOG_DEBUG, "check_eval_scan_membership: done: " PF_MEMBERSHIP,
1702 +               PA_MEMBERSHIP(membership));
1703 +}
1704 +
1705 +static void check_request_scan_entity TAC_ARGS((ENTITY *entity, int flush));
1706 +
1707 +static void
1708 +check_request_scan_entity(entity, flush)
1709 +ENTITY *entity;
1710 +int flush;
1711 +{
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));
1716 +#endif
1717 +
1718 +    if (!flush && entity->request_scan.seq == request_scan_seq)
1719 +       return;
1720 +
1721 +    entity->request_scan.belongs = ER_UNKNOWN;
1722 +    entity->request_scan.seq = request_scan_seq;
1723 +
1724 +    if (debug & DEBUG_CFGEVAL_FLAG)
1725 +       report(LOG_DEBUG, "check_request_scan_entity: done: " PF_ENTITY,
1726 +               PA_ENTITY(entity));
1727 +}
1728 +
1729 +static void check_value_scan_entity TAC_ARGS((ENTITY *entity, int flush));
1730 +
1731 +static void
1732 +check_value_scan_entity(entity, flush)
1733 +ENTITY *entity;
1734 +int flush;
1735 +{
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));
1740 +#endif
1741 +
1742 +    if (!flush && entity->value_scan.seq == value_scan_seq)
1743 +       return;
1744 +    check_request_scan_entity(entity, 0);
1745 +
1746 +    entity->value_scan.seen = 0;
1747 +    entity->value_scan.from = NULL;
1748 +    entity->value_scan.seq = value_scan_seq;
1749 +
1750 +    if (debug & DEBUG_CFGEVAL_FLAG)
1751 +       report(LOG_DEBUG, "check_value_scan_entity: done: " PF_ENTITY,
1752 +               PA_ENTITY(entity));
1753 +}
1754 +
1755 +static void check_eval_scan_entity TAC_ARGS((ENTITY *entity, int flush));
1756 +
1757 +static void
1758 +check_eval_scan_entity(entity, flush)
1759 +ENTITY *entity;
1760 +int flush;
1761 +{
1762 +    struct tac_list_node *child_membership_parent_node;
1763 +
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));
1768 +#endif
1769 +
1770 +    if (!flush && entity->eval_scan.seq == eval_scan_seq)
1771 +       return;         /* up to date */
1772 +    check_value_scan_entity(entity, 0);
1773 +
1774 +    entity->eval_scan.unsolved_to_child_membership_num = entity->to_child_membership_num;
1775 +
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);
1778 +
1779 +       entity->eval_scan.unsolved_to_child_membership_first = child_membership;
1780 +    } else
1781 +       entity->eval_scan.unsolved_to_child_membership_first = NULL;
1782 +
1783 +#ifdef SCAN_PARANOIA
1784 +    {
1785 +       struct tac_list_node *notify_expr_node;
1786 +
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);
1789 +
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);
1795 +       }
1796 +
1797 +       if (tac_list_node_get_list(&entity->eval_scan.pending_entity_node))
1798 +           tac_list_node_remove(&entity->eval_scan.pending_entity_node);
1799 +    }
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 */
1804 +
1805 +    entity->eval_scan.seq = eval_scan_seq;     /* used above, keep as LAST! */
1806 +
1807 +    if (debug & DEBUG_CFGEVAL_FLAG)
1808 +       report(LOG_DEBUG, "check_eval_scan_entity: done: " PF_ENTITY,
1809 +               PA_ENTITY(entity));
1810 +}
1811 +
1812 +
1813 +/* invalidation managing section (for '*_scan_begin()'):
1814 + */
1815 +
1816 +/* this will happen once upon 'unsigned' overflow, ehm */
1817 +
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))
1822 +
1823 +static const long invalidate_scan_expr_table[IS_MAX]={
1824 +    G_STRUCT_OFFSET(struct expr, request_scan.seq),
1825 +    -1,
1826 +    G_STRUCT_OFFSET(struct expr,    eval_scan.seq)};
1827 +
1828 +static void invalidate_scan_expr TAC_ARGS((struct expr *expr,enum invalidate_scan what));
1829 +
1830 +static void
1831 +invalidate_scan_expr(expr_single, what)
1832 +struct expr *expr_single;
1833 +enum invalidate_scan what;
1834 +{
1835 +    struct expr *expr_parent, *expr_child;
1836 +
1837 +    if (!expr_single) {
1838 +       report(LOG_ERR, "INTERNAL: NULL input expressions not support by invalidate_scan_expr");
1839 +       return;
1840 +    }
1841 +    if (expr_single->parent) {
1842 +       report(LOG_ERR, "INTERNAL: non-root expressions not supported by invalidate_scan_expr");
1843 +       return;
1844 +    }
1845 +
1846 +    /* TOP->DOWN scanner: */
1847 +top_down:
1848 +    do {
1849 +       INVALIDATE_SEQ_PTR(expr,expr_single);
1850 +       expr_parent = expr_single;
1851 +
1852 +       switch (expr_parent->type) {
1853 +
1854 +       case S_not:
1855 +           expr_child = expr_parent->u.not.child;
1856 +           continue;
1857 +
1858 +       case S_and:
1859 +       case S_or:
1860 +           expr_child = expr_parent->u.and_or.child_first;
1861 +           break;
1862 +
1863 +       case S_user:
1864 +       case S_host:
1865 +       case S_group:
1866 +           expr_child = NULL;  /* no child exists */
1867 +           break;
1868 +
1869 +       default:
1870 +           report(LOG_ERR, "Illegal child node type %d for invalidate_scan_expr", expr_parent->type);
1871 +           return;
1872 +       }
1873 +    } while ((expr_single = expr_child));
1874 +    /* expr_child==NULL, we have only expr_parent: */
1875 +
1876 +    expr_child = expr_parent;
1877 +
1878 +    /* we have only expr_child: */
1879 +    /* BOTTOM->UP scanner */
1880 +    do {
1881 +        if ((expr_single = expr_child->next))
1882 +           goto top_down;
1883 +       expr_parent = expr_child->parent;
1884 +    } while ((expr_child = expr_parent));
1885 +}
1886 +
1887 +static const long invalidate_scan_membership_table[IS_MAX]={
1888 +    G_STRUCT_OFFSET(struct membership, request_scan.seq),
1889 +    -1,
1890 +    G_STRUCT_OFFSET(struct membership,    eval_scan.seq)};
1891 +
1892 +static void invalidate_scan_membership TAC_ARGS((struct membership *membership,enum invalidate_scan what));
1893 +
1894 +static void
1895 +invalidate_scan_membership(membership, what)
1896 +struct membership *membership;
1897 +enum invalidate_scan what;
1898 +{
1899 +    INVALIDATE_SEQ(membership);
1900 +
1901 +    if (membership->when)
1902 +       invalidate_scan_expr(membership->when, what);
1903 +}
1904 +
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)};
1909 +
1910 +static void invalidate_scan_entity TAC_ARGS((ENTITY *entity,enum invalidate_scan what));
1911 +
1912 +static void
1913 +invalidate_scan_entity(entity, what)
1914 +ENTITY *entity;
1915 +enum invalidate_scan what;
1916 +{
1917 +    struct tac_list_node *child_membership_node;
1918 +    struct membership *child_membership;
1919 +
1920 +    INVALIDATE_SEQ(entity);
1921 +
1922 +    if (what==IS_VALUE)                /* optimalization */
1923 +       return;
1924 +
1925 +    for (
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)
1929 +           ) {
1930 +       child_membership = PARENT_NODE_TO_MEMBERSHIP(child_membership_node);
1931 +       invalidate_scan_membership(child_membership, what);
1932 +    }
1933 +}
1934 +
1935 +void scan_invalidate_entities_hashtable TAC_ARGS((void **hashtable, enum invalidate_scan what));
1936 +
1937 +void
1938 +scan_invalidate_entities_hashtable(hashtable, what)
1939 +void **hashtable;
1940 +enum invalidate_scan what;
1941 +{
1942 +    int i;
1943 +    ENTITY *entity;
1944 +
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);
1948 +}
1949 +
1950 +/* '*_scan_begin()' section:
1951 + */
1952 +
1953 +void request_scan_begin TAC_ARGS((void));
1954 +
1955 +void
1956 +request_scan_begin()
1957 +{
1958 +#ifdef SCAN_PARANOIA
1959 +    static int inited = 0;
1960 +#endif /* SCAN_PARANOIA */
1961 +
1962 +    if (debug & DEBUG_CFGEVAL_FLAG)
1963 +       report(LOG_DEBUG, "request_scan_begin:");
1964 +
1965 +    request_scan_user_known = 0;
1966 +
1967 +    if (!++request_scan_seq)
1968 +       scan_invalidate_entities(IS_REQUEST);
1969 +
1970 +#ifdef SCAN_PARANOIA
1971 +    if (!inited) {
1972 +#endif /* SCAN_PARANOIA */
1973 +       tac_list_init(&request_virtual_membership_list);
1974 +#ifdef SCAN_PARANOIA
1975 +       inited = 1;
1976 +    } else {
1977 +       struct tac_list_node *virtual_membership_node;
1978 +
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);
1981 +
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);
1987 +           }
1988 +    }
1989 +#endif /* SCAN_PARANOIA */
1990 +}
1991 +
1992 +static void value_scan_begin TAC_ARGS((ENTITY *entity));
1993 +
1994 +static void
1995 +value_scan_begin(entity)
1996 +ENTITY *entity;
1997 +{
1998 +    if (debug & DEBUG_CFGEVAL_FLAG)
1999 +       report(LOG_DEBUG, "value_scan_begin:");
2000 +
2001 +    if (!++value_scan_seq)
2002 +       scan_invalidate_entities(IS_VALUE);
2003 +
2004 +    check_value_scan_entity(entity, 0);        /* sure as seq invalidated */
2005 +    /* assumed (entity->value_scan.from == NULL) */
2006 +}
2007 +
2008 +#ifdef SCAN_PARANOIA
2009 +
2010 +static void eval_scan_begin_pending_entity_node TAC_ARGS((struct tac_list_node *pending_entity_node));
2011 +
2012 +static void
2013 +eval_scan_begin_pending_entity_node(pending_entity_node)
2014 +struct tac_list_node *pending_entity_node;
2015 +{
2016 +    ENTITY *pending_entity = PENDING_ENTITY_NODE_TO_ENTITY(pending_entity_node);
2017 +
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");
2020 +
2021 +    tac_list_node_remove(pending_entity_node);
2022 +}
2023 +
2024 +#endif /* SCAN_PARANOIA */
2025 +
2026 +static void eval_scan_begin TAC_ARGS((void));
2027 +
2028 +static void
2029 +eval_scan_begin()
2030 +{
2031 +#ifdef SCAN_PARANOIA
2032 +    static int inited = 0;
2033 +#endif /* SCAN_PARANOIA */
2034 +
2035 +    if (debug & DEBUG_CFGEVAL_FLAG)
2036 +       report(LOG_DEBUG, "eval_scan_begin:");
2037 +
2038 +    if (!++eval_scan_seq)
2039 +       scan_invalidate_entities(IS_EVAL);
2040 +
2041 +#ifdef SCAN_PARANOIA
2042 +    if (!inited) {
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
2048 +       inited = 1;
2049 +    } else {
2050 +       struct tac_list_node *pending_entity_node;
2051 +       struct tac_list_node *notify_expr_node;
2052 +
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);
2057 +
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);
2060 +
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");
2063 +
2064 +           tac_list_node_remove(notify_expr_node);
2065 +       }
2066 +    }
2067 +#endif /* SCAN_PARANOIA */
2068 +}
2069 +
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...
2074 + */
2075 +
2076 +static void register_kicked_entity TAC_ARGS((ENTITY *entity, int priority));
2077 +
2078 +static void register_kicked_entity(entity, priority)
2079 +ENTITY *entity;
2080 +int priority;
2081 +{
2082 +    struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
2083 +
2084 +    check_eval_scan_entity(entity, 0);
2085 +
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));
2091 +    }
2092 +    if (tac_list_node_get_list(pending_entity_node) == NULL) {
2093 +       if (priority)
2094 +           tac_list_addhead(&eval_kicked_entity_list, pending_entity_node);
2095 +       else
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"));
2100 +    }
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");
2104 +       return;
2105 +    }
2106 +#endif
2107 +}
2108 +
2109 +/* check_eval_scan_*() is assumed both for "expr" and for "entity" ! */
2110 +
2111 +static void expr_eval_notify_expr TAC_ARGS((struct expr *expr));
2112 +
2113 +static void
2114 +expr_eval_notify_expr(expr)
2115 +struct expr *expr;
2116 +{
2117 +    ENTITY *entity = expr->u.entity.entity;
2118 +
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));
2122 +
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));
2129 +#endif
2130 +       return;
2131 +    }
2132 +
2133 +    tac_list_addtail(&entity->eval_scan.notify_expr_list,
2134 +           &expr->eval_scan.u.entity.notify_expr_node);
2135 +
2136 +    register_kicked_entity(entity, 0 /* priority */);
2137 +}
2138 +
2139 +/* check_eval_scan_*() is assumed for "expr" ! */
2140 +
2141 +static void expr_eval_notify_expr_remove_internal TAC_ARGS((struct expr *expr));
2142 +
2143 +static void
2144 +expr_eval_notify_expr_remove_internal(expr)
2145 +struct expr *expr;
2146 +{
2147 +    if (debug & DEBUG_CFGEVAL_FLAG)
2148 +       report(LOG_DEBUG, "expr_eval_notify_expr_remove_internal: no longer interested in " PF_EXPR,
2149 +               PA_EXPR(expr));
2150 +
2151 +    if (!expr)
2152 +       return;
2153 +    if (expr->eval_scan.seq != eval_scan_seq)
2154 +       return;
2155 +    if (expr->request_scan.result != ER_UNKNOWN)
2156 +       return;
2157 +
2158 +    switch (expr->type) {
2159 +
2160 +    case S_not:
2161 +       expr_eval_notify_expr_remove_internal(expr->u.not.child);
2162 +       break;
2163 +
2164 +    case S_and:
2165 +    case S_or: {
2166 +       struct expr *child;
2167 +
2168 +       for (child=expr->u.and_or.child_first; child; child=child->next)
2169 +           expr_eval_notify_expr_remove_internal(child);
2170 +       } break;
2171 +
2172 +    case S_user:
2173 +    case S_host:
2174 +    case S_group: {
2175 +       ENTITY *entity = expr->u.entity.entity;
2176 +       struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
2177 +
2178 +       if (!tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
2179 +           break;
2180 +
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))
2183 +           break;
2184 +       /* no one is further interested in "entity" */
2185 +
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));
2191 +       }
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));
2197 +       }
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");
2201 +           return;
2202 +       }
2203 +#endif
2204 +
2205 +       } break;
2206 +
2207 +    default:
2208 +       report(LOG_ERR, "Illegal node type %d for expr_eval_notify_expr_remove", expr->type);
2209 +       return;
2210 +    }
2211 +}
2212 +
2213 +static void expr_eval_notify_expr_flush_destroy_entity_list TAC_ARGS((void));
2214 +
2215 +static void expr_eval_notify_expr_flush_destroy_entity_list()
2216 +{
2217 +struct tac_list_node *destroy_entity_node;
2218 +
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;
2222 +
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));
2226 +
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);
2229 +
2230 +           expr_eval_notify_expr_remove_internal(destroy_notify_expr);
2231 +       }
2232 +    }
2233 +}
2234 +
2235 +static void expr_eval_notify_expr_remove TAC_ARGS((struct expr *expr));
2236 +
2237 +static void
2238 +expr_eval_notify_expr_remove(expr)
2239 +struct expr *expr;
2240 +{
2241 +    if (debug & DEBUG_CFGEVAL_FLAG)
2242 +       report(LOG_DEBUG, "expr_eval_notify_expr_remove: no longer interested in " PF_EXPR,
2243 +               PA_EXPR(expr));
2244 +
2245 +    expr_eval_notify_expr_remove_internal(expr);
2246 +    expr_eval_notify_expr_flush_destroy_entity_list();
2247 +}
2248 +
2249 +/* It would be very nice to try to optimize the expression before evaluation.
2250 +
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.
2256 +
2257 +   TODO in future: Full NP optimization for small number of variables and/or
2258 +   heuristic optimizations for complex expressions.
2259 +*/
2260 +
2261 +static enum eval_result expr_eval_immediate TAC_ARGS((struct expr *expr_single));
2262 +
2263 +static enum eval_result
2264 +expr_eval_immediate(expr_single)
2265 +struct expr *expr_single;
2266 +{
2267 +    struct expr *expr_child, *expr_parent;
2268 +    enum eval_result result_child, result_parent = 0 /* GCC paranoia */;
2269 +
2270 +    if (debug & DEBUG_CFGEVAL_FLAG)
2271 +       report(LOG_DEBUG, "expr_eval_immediate: " PF_EXPR,
2272 +               PA_EXPR(expr_single));
2273 +
2274 +    if (!expr_single)
2275 +       return (ER_TRUE);
2276 +
2277 +    /* TOP->DOWN scanner: */
2278 +top_down:
2279 +    while (1) {
2280 +       enum eval_result result_single;
2281 +
2282 +       if (debug & DEBUG_CFGEVAL_FLAG)
2283 +           report(LOG_DEBUG, "expr_eval_immediate: top_down start: " PF_EXPR,
2284 +                   PA_EXPR(expr_single));
2285 +
2286 +       check_eval_scan_expr(expr_single, 0);
2287 +       result_single = expr_single->request_scan.result;
2288 +       if (result_single != ER_UNKNOWN)
2289 +           break;
2290 +       switch (expr_single->type) {
2291 +
2292 +       case S_not:
2293 +           expr_single = expr_single->u.not.child;
2294 +           continue;
2295 +
2296 +       case S_and:
2297 +       case S_or:
2298 +           expr_single = expr_single->u.and_or.child_first;
2299 +           continue;
2300 +
2301 +       case S_user:
2302 +       case S_host:
2303 +       case S_group: {
2304 +           ENTITY *entity = expr_single->u.entity.entity;
2305 +
2306 +           check_eval_scan_entity(entity, 0);
2307 +
2308 +           if (entity->request_scan.belongs == ER_UNKNOWN)
2309 +               expr_eval_notify_expr(expr_single);
2310 +           else
2311 +               result_single = entity->request_scan.belongs;
2312 +           } break;
2313 +
2314 +       default:
2315 +           report(LOG_ERR, "Illegal child node type %d for expr_eval", expr_single->type);
2316 +           return (ER_UNKNOWN);
2317 +       }
2318 +
2319 +       expr_single->request_scan.result = result_single;
2320 +       break;
2321 +    }
2322 +
2323 +    /* BOTTOM->UP scanner: */
2324 +    do {
2325 +       if (debug & DEBUG_CFGEVAL_FLAG)
2326 +           report(LOG_DEBUG, "expr_eval_immediate: bottom_up start: " PF_EXPR,
2327 +                   PA_EXPR(expr_single));
2328 +
2329 +       expr_parent = expr_single->parent;
2330 +       if (!expr_parent)
2331 +           break;
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);
2335 +       }
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);
2339 +       }
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);
2343 +       }
2344 +
2345 +       expr_child = expr_single;
2346 +       result_child = expr_child->request_scan.result;
2347 +
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));
2351 +
2352 +       switch (expr_parent->type) {
2353 +
2354 +       case S_not:
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;
2359 +           }
2360 +           break;
2361 +
2362 +       case S_and:
2363 +       case S_or: {
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);
2366 +
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));
2375 +                   goto top_down;
2376 +               }
2377 +
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));
2381 +
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.
2388 +                */
2389 +               result_parent = consent;
2390 +               for (expr_child = expr_parent->u.and_or.child_first; expr_child; expr_child = expr_child->next)
2391 +               {
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;
2397 +                       break;
2398 +                   }
2399 +               }
2400 +               break;
2401 +           }
2402 +           } break;
2403 +
2404 +       default:
2405 +           report(LOG_ERR, "Illegal parent node type %d for expr_eval", expr_parent->type);
2406 +           return (ER_UNKNOWN);
2407 +       }
2408 +
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));
2412 +
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);
2417 +       }
2418 +
2419 +       expr_single = expr_parent;
2420 +    } while (0);
2421 +    /* The whole expression has been scanned to its root, we have "expr_single" */
2422 +
2423 +    if (debug & DEBUG_CFGEVAL_FLAG)
2424 +       report(LOG_DEBUG, "expr_eval_immediate: done: " PF_EXPR,
2425 +               PA_EXPR(expr_single));
2426 +
2427 +    return (expr_single->request_scan.result);
2428 +}
2429 +
2430 +static void membership_solved TAC_ARGS((struct membership *membership));
2431 +
2432 +static void
2433 +membership_solved(membership)
2434 +struct membership *membership;
2435 +{
2436 +    ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
2437 +
2438 +    check_request_scan_entity(parent_entity, 0);
2439 +
2440 +#ifdef SCAN_PARANOIA
2441 +    if (!membership->eval_scan.unsolved) {
2442 +       report(LOG_ERR, "INTERNAL: membership already solved in membership_solved");
2443 +       return;
2444 +    }
2445 +#endif
2446 +
2447 +    membership->eval_scan.unsolved = 0;
2448 +
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++;
2453 +    }
2454 +#endif
2455 +    parent_entity->eval_scan.unsolved_to_child_membership_num--;
2456 +
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 */);
2461 +    }
2462 +}
2463 +
2464 +static void membership_parent_solve TAC_ARGS((struct membership *membership, enum eval_result how));
2465 +
2466 +static void
2467 +membership_parent_solve(membership, how)
2468 +struct membership *membership;
2469 +enum eval_result how;
2470 +{
2471 +    enum eval_result negative = (how == ER_TRUE ? ER_FALSE : ER_TRUE);
2472 +    ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
2473 +
2474 +    check_request_scan_entity(parent_entity, 0);
2475 +
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));
2479 +
2480 +    parent_entity->request_scan.belongs = how;
2481 +    register_kicked_entity(parent_entity, 1 /* priority */);
2482 +
2483 +    membership_solved(membership);
2484 +
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));
2488 +}
2489 +
2490 +static void membership_eval_immediate TAC_ARGS((struct membership *membership));
2491 +
2492 +static void
2493 +membership_eval_immediate(membership)
2494 +struct membership *membership;
2495 +{
2496 +    enum eval_result membership_valid;
2497 +    ENTITY *child_entity, *parent_entity;
2498 +
2499 +    if (debug & DEBUG_CFGEVAL_FLAG)
2500 +       report(LOG_DEBUG, "membership_eval_immediate: " PF_MEMBERSHIP,
2501 +               PA_MEMBERSHIP(membership));
2502 +
2503 +    check_eval_scan_membership(membership, 0);
2504 +
2505 +    if (!membership->eval_scan.unsolved)
2506 +       return;
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? */
2510 +       return;
2511 +
2512 +    membership_valid = expr_eval_immediate(membership->when);
2513 +
2514 +    child_entity = MEMBERSHIP_TO_CHILD_ENTITY( membership);
2515 +    check_request_scan_entity( child_entity, 0);
2516 +
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);
2520 +       return;
2521 +    }
2522 +#endif
2523 +
2524 +    if (child_entity->request_scan.belongs == ER_TRUE  && membership_valid == ER_TRUE ) {
2525 +       membership_parent_solve(membership, ER_TRUE );
2526 +       return;
2527 +    }
2528 +
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 */);
2533 +
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);
2537 +
2538 +    if (debug & DEBUG_CFGEVAL_FLAG)
2539 +       report(LOG_DEBUG, "membership_eval_immediate: done: " PF_MEMBERSHIP,
2540 +               PA_MEMBERSHIP(membership));
2541 +}
2542 +
2543 +static void entity_eval_immediate TAC_ARGS((ENTITY *entity));
2544 +
2545 +static void
2546 +entity_eval_immediate(entity)
2547 +ENTITY *entity;
2548 +{
2549 +    struct tac_list_node *notified_expr_node;
2550 +    struct tac_list_node *child_membership_node;
2551 +
2552 +    if (debug & DEBUG_CFGEVAL_FLAG)
2553 +       report(LOG_DEBUG, "entity_eval_immediate: " PF_ENTITY,
2554 +               PA_ENTITY(entity));
2555 +
2556 +    check_eval_scan_entity(entity, 0);
2557 +
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));
2563 +#endif
2564 +       return;
2565 +    }
2566 +
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);
2571 +
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);
2575 +           else
2576 +               entity->eval_scan.unsolved_to_child_membership_first = NULL;
2577 +
2578 +           register_kicked_entity(entity, 0 /* priority */);
2579 +
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));
2583 +           return;
2584 +       }
2585 +
2586 +       if (!entity->eval_scan.unsolved_to_child_membership_num)
2587 +           entity->request_scan.belongs = ER_FALSE;
2588 +       else {
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");
2591 +           return;
2592 +       }
2593 +    }
2594 +    /* belonging is known here */
2595 +
2596 +    /* recheck all memberships we may decide */
2597 +    for (
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)
2601 +           ) {
2602 +       struct membership *child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
2603 +
2604 +       membership_eval_immediate(child_membership);
2605 +    }
2606 +
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);
2611 +    }
2612 +
2613 +    if (debug & DEBUG_CFGEVAL_FLAG)
2614 +       report(LOG_DEBUG, "entity_eval_immediate: done: " PF_ENTITY,
2615 +               PA_ENTITY(entity));
2616 +}
2617 +
2618 +
2619 +enum eval_result expr_eval TAC_ARGS((struct expr *expr));
2620 +
2621 +enum eval_result
2622 +expr_eval(expr)
2623 +struct expr *expr;
2624 +{
2625 +    if (debug & DEBUG_CFGEVAL_FLAG)
2626 +       report(LOG_DEBUG, "expr_eval: top level order for " PF_EXPR,
2627 +               PA_EXPR(expr));
2628 +
2629 +    if (!expr)
2630 +       return (ER_TRUE);
2631 +
2632 +    eval_scan_begin();
2633 +    if (expr_eval_immediate(expr) != ER_UNKNOWN)
2634 +       return (expr->request_scan.result);
2635 +
2636 +    /* all 'solved' nodes MUST be removed BEFORE '*_immediate()' has been called,
2637 +     * otherwise we may have no longer valid node!
2638 +     */
2639 +    for (;;) {
2640 +       struct tac_list_node *notified_expr_node, *kicked_entity_node;
2641 +
2642 +       /* check it rather always, checking just on notifications looks too complex.
2643 +       */
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",
2647 +                       PA_EXPR(expr));
2648 +           return (expr->request_scan.result);
2649 +       }
2650 +
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 */
2654 +
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);
2657 +
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));
2661 +
2662 +           tac_list_node_remove(notified_expr_node);
2663 +           expr_eval_immediate(notified_expr);
2664 +
2665 +           if (notified_expr->membership)
2666 +               membership_eval_immediate(notified_expr->membership);
2667 +
2668 +           continue;           /* shortcut */
2669 +       }
2670 +
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);
2673 +
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));
2677 +
2678 +           tac_list_node_remove(kicked_entity_node);
2679 +           entity_eval_immediate(kicked_entity);
2680 +           continue;           /* shortcut */
2681 +       }
2682 +
2683 +       break;  /* nothing done yet, all lists are empty! */
2684 +    }
2685 +
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;
2689 +    }
2690 +    return (ER_UNKNOWN);
2691 +}
2692 +
2693 +
2694 +void eval_force_belong_entity TAC_ARGS((ENTITY *entity));
2695 +
2696 +void eval_force_belong_entity(entity)
2697 +ENTITY *entity;
2698 +{
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));
2702 +
2703 +    check_request_scan_entity(entity, 0);
2704 +
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");
2707 +
2708 +    entity->request_scan.belongs = ER_TRUE;
2709 +}
2710 +
2711 +void scan_init_entity TAC_ARGS((ENTITY *entity));
2712 +
2713 +void
2714 +scan_init_entity(entity)
2715 +ENTITY *entity;
2716 +{
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);
2722 +}
2723 +
2724 +struct membership *enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child, struct expr *when));
2725 +
2726 +struct membership *
2727 +enlist_entity_direct(parent, child, when)
2728 +ENTITY *parent;
2729 +ENTITY *child;
2730 +struct expr *when;
2731 +{
2732 +    struct membership *membership = (struct membership *) tac_malloc(sizeof(struct membership));
2733 +
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;
2739 +
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);
2747 +       return (NULL);
2748 +    }
2749 +
2750 +    if (debug & DEBUG_CFGEVAL_FLAG)
2751 +       report(LOG_DEBUG, "enlist_entity_direct: done: " PF_MEMBERSHIP,
2752 +               PA_MEMBERSHIP(membership));
2753 +
2754 +    return (membership);
2755 +}
2756 +
2757 +struct membership *virtual_enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child));
2758 +
2759 +struct membership *
2760 +virtual_enlist_entity_direct(parent, child)
2761 +ENTITY *parent;
2762 +ENTITY *child;
2763 +{
2764 +    struct membership *membership;
2765 +
2766 +    if (debug & DEBUG_CFGEVAL_FLAG)
2767 +       report(LOG_DEBUG, "virtual_enlist_entity_direct: the following enlist will be VIRTUAL...");
2768 +
2769 +    membership = enlist_entity_direct(parent, child, NULL /* when */);
2770 +    if (!membership)
2771 +       return (NULL);
2772 +
2773 +    check_request_scan_membership(membership, 0);
2774 +    tac_list_addtail(&request_virtual_membership_list, &membership->request_scan.virtual_membership_node);
2775 +
2776 +    return (membership);
2777 +}
2778 +
2779 +/* returns given 'entity' or NULL if already visited */
2780 +
2781 +void (*value_scan_forward_seen_hook) TAC_ARGS((struct membership *membership));
2782 +
2783 +static ENTITY *value_scan_forward TAC_ARGS((struct membership *membership));
2784 +
2785 +static ENTITY *
2786 +value_scan_forward(membership)
2787 +struct membership *membership;
2788 +{
2789 +    ENTITY *parent_entity;
2790 +
2791 +    if (debug & DEBUG_CFGEVAL_FLAG)
2792 +       report(LOG_DEBUG, "value_scan_forward: from " PF_MEMBERSHIP " try forward...",
2793 +               PA_MEMBERSHIP(membership));
2794 +
2795 +    parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
2796 +
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.");
2800 +       return (NULL);
2801 +    }
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);
2809 +       return (NULL);
2810 +    }
2811 +    parent_entity->value_scan.seen = 1;
2812 +    parent_entity->value_scan.from = membership;
2813 +
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);
2818 +}
2819 +
2820 +struct membership *value_scan_backward TAC_ARGS((ENTITY *entity));
2821 +
2822 +struct membership *
2823 +value_scan_backward(entity)
2824 +ENTITY *entity;
2825 +{
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));
2829 +
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");
2833 +       return (NULL);
2834 +    }
2835 +#endif
2836 +
2837 +    return (entity->value_scan.from);
2838 +}
2839 +
2840 +/* Scan the entity graph and return each node found.
2841 +   'when' conditions for graph connections are respected,
2842 +   looping is correctly prevented.
2843 +*/
2844 +
2845 +enum value_scan_func_result value_scan_entity TAC_ARGS((ENTITY *entity, int recurse, value_scan_func_t func, void *func_data));
2846 +
2847 +enum value_scan_func_result
2848 +value_scan_entity(entity, recurse, func, func_data)
2849 +ENTITY *entity;
2850 +int recurse;
2851 +value_scan_func_t func;
2852 +void *func_data;
2853 +{
2854 +    enum value_scan_func_result vsfr;
2855 +    struct tac_list_node *membership_node;
2856 +
2857 +    if (debug & DEBUG_CFGEVAL_FLAG)
2858 +       report(LOG_DEBUG, "value_scan_entity: " PF_ENTITY ", recurse=%d",
2859 +               PA_ENTITY(entity), recurse);
2860 +
2861 +    vsfr=(*func)(entity,func_data);
2862 +
2863 +    if (debug & DEBUG_CFGEVAL_FLAG)
2864 +       report(LOG_DEBUG, "value_scan_entity: root func-> " PF_VSFR,
2865 +               PA_VSFR(vsfr));
2866 +
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");
2870 +       return (vsfr);
2871 +    }
2872 +    if (!recurse ) {
2873 +       if (debug & DEBUG_CFGEVAL_FLAG)
2874 +           report(LOG_DEBUG, "value_scan_entity: finishing as recurse not ordered");
2875 +       return (VSFR_STOP);
2876 +    }
2877 +
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 */
2884 +    }
2885 +
2886 +    while (1) {
2887 +       struct membership *membership = CHILD_NODE_TO_MEMBERSHIP(membership_node);
2888 +
2889 +       if (debug & DEBUG_CFGEVAL_FLAG)
2890 +           report(LOG_DEBUG, "value_scan_entity: trace loop start: " PF_MEMBERSHIP,
2891 +                   PA_MEMBERSHIP(membership));
2892 +
2893 +       entity = value_scan_forward(membership);
2894 +       if (entity) {
2895 +           if (debug & DEBUG_CFGEVAL_FLAG)
2896 +               report(LOG_DEBUG, "value_scan_entity: successful recurse to " PF_ENTITY,
2897 +                       PA_ENTITY(entity));
2898 +
2899 +           vsfr=(*func)(entity,func_data);
2900 +
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));
2904 +
2905 +           if (vsfr == VSFR_FOUND) {
2906 +               if (debug & DEBUG_CFGEVAL_FLAG)
2907 +                   report(LOG_DEBUG, "value_scan_entity: finishing as func returned VSFR_FOUND");
2908 +               return (vsfr);
2909 +           }
2910 +           if (vsfr == VSFR_CONTINUE)
2911 +               membership_node = tac_list_first_node(&entity->to_parent_membership_list);
2912 +       }
2913 +       if (!entity || vsfr == VSFR_STOP) {
2914 +           ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
2915 +
2916 +           entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);    /* for retreat from the LAST membership */
2917 +
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));
2921 +
2922 +           membership_node = tac_list_node_next(&membership->child_node);
2923 +       }
2924 +
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 */
2931 +           }
2932 +
2933 +           entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);    /* for retreat from the LAST membership */
2934 +
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));
2939 +
2940 +           membership_node = tac_list_node_next(&membership->child_node);
2941 +       }
2942 +    }
2943 +    /* NOTREACHED */
2944 +}
2945 diff --git a/cfgeval.h b/cfgeval.h
2946 new file mode 100644
2947 index 0000000..63f33cb
2948 --- /dev/null
2949 +++ b/cfgeval.h
2950 @@ -0,0 +1,134 @@
2951 +#ifndef CFGEVAL_H
2952 +#define CFGEVAL_H 1
2953 +
2954 +#include "tac_plus.h"
2955 +
2956 +#include "utils.h"
2957 +
2958 +
2959 +struct entity;
2960 +typedef struct entity ENTITY;
2961 +enum invalidate_scan {
2962 +    IS_REQUEST = 0,
2963 +    IS_VALUE   = 1,
2964 +    IS_EVAL    = 2,
2965 +    IS_MAX     = 3
2966 +};
2967 +
2968 +enum eval_result {
2969 +    ER_UNKNOWN,
2970 +    ER_FALSE,
2971 +    ER_TRUE
2972 +};
2973 +
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() */
2978 +};
2979 +
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 */
2983 +
2984 +    struct {
2985 +       unsigned seq;                   /* corresponds to global request_scan_seq */
2986 +       struct tac_list_node virtual_membership_node;
2987 +    } request_scan;            /*   cfg_request() scanning */
2988 +
2989 +    struct {
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 */
2994 +
2995 +    struct expr *when;
2996 +};
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))
3009 +
3010 +struct expr {
3011 +    struct {
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 */
3016 +
3017 +    struct {
3018 +       unsigned seq;                   /* corresponds to global eval_scan_seq */
3019 +       union {
3020 +
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"
3024 +                        */
3025 +           struct tac_list_node notify_expr_node;      /* gets removed on this expr->seq!= */
3026 +       } entity;
3027 +
3028 +       } u;
3029 +    } eval_scan;               /*     expr_eval() scanning, many per value_scan */
3030 +
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 */
3036 +    int line;
3037 +    union {
3038 +
3039 +    struct {
3040 +       struct expr *child;
3041 +    } not;
3042 +
3043 +    struct {
3044 +       struct expr *child_first;       /* linked by expr->next */
3045 +    } and_or;
3046 +
3047 +    struct {           /* for S_host, S_user or S_group */
3048 +       const char *name;
3049 +       ENTITY *entity;
3050 +    } entity;
3051 +
3052 +    } u;
3053 +};
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))
3058 +
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));
3061 +
3062 +
3063 +extern int request_scan_user_known;    /* have we allowed to 'solve' S_user entities at all? */
3064 +
3065 +
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));
3082 +
3083 +
3084 +#endif /* CFGEVAL_H */
3085 diff --git a/cfgfile.c b/cfgfile.c
3086 index 6eaef53..041993c 100644
3087 --- a/cfgfile.c
3088 +++ b/cfgfile.c
3089 @@ -17,38 +17,87 @@
3090     FITNESS FOR A PARTICULAR PURPOSE.
3091  */
3092  
3093 +
3094  #include "tac_plus.h"
3095 +
3096  #include <stdio.h>
3097 +#include <stdlib.h>
3098  #include <errno.h>
3099 -#include "regexp.h"
3100 +#include <string.h>
3101 +
3102 +#ifndef WITH_INCLUDED_REGEX
3103 +#ifdef HAVE_REGEX_H
3104 +#include <regex.h>
3105 +#endif
3106 +#endif
3107 +
3108 +#include "cfgfile.h"
3109 +#include "report.h"
3110 +#include "utils.h"
3111 +#include "hash.h"
3112 +#include "parse.h"
3113 +#include "main.h"
3114 +#include "do_author.h"                 /* for "struct identity" */
3115 +
3116 +#ifdef WITH_INCLUDED_REGEX
3117 +#include "tac_regexp.h"
3118 +#endif
3119 +
3120 +
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));
3131 +
3132  
3133  /*
3134     <config>           := <decl>*
3135  
3136 -   <decl>           := <top_level_decl> | <user_decl>
3137 +   <decl>             := <top_level_decl> | <entity_decl>
3138  
3139     <top_level_decl>   := <authen_default> |
3140 -                       accounting file = <string>
3141 +                         accounting file = <string> |
3142                           default authorization = permit |
3143 -                       key = <string>
3144 +                         key = <string> |
3145 +                         authorization = ( first | recursive )
3146  
3147     <authen_default>   := default authentication = file <filename>
3148  #if defined(DB)
3149 -                   | db <string> )
3150 +                         | db <string>
3151  #endif
3152  
3153 -<permission>     := permit | deny
3154 +   <permission>       := permit | deny
3155  
3156     <filename>         := <string>
3157  
3158     <password>         := <string>
3159  
3160     <user_decl>        := user  = <string> {
3161 -                        [ default service = [ permit | deny ] ]
3162 +                           [ <service_default> ]
3163                             <user_attr>*
3164                             <svc>*
3165                           }
3166  
3167 +   <host_decl>        := host  = <string> {
3168 +                           [ <service_default> ]
3169 +                           <host_attr>*
3170 +                           <svc>*
3171 +                         }
3172 +
3173 +   <group_decl>       := group = <string> {
3174 +                           [ <service_default> ]
3175 +                           <group_attr>*
3176 +                           <svc>*
3177 +                         }
3178 +
3179 +   <service_default>  := default service = ( permit | deny | default )
3180 +
3181     <password_spec>    := file <filename> |
3182                           skey |
3183                           cleartext <password> |
3184 @@ -80,23 +129,66 @@
3185                           global   = cleartext <string> |
3186                           msg      = <string>
3187                           before authorization = <string> |
3188 -                        after authorization = <string>
3189 +                         after  authorization = <string> |
3190 +                         <when_attr>
3191 +
3192 +   <host_attr>       :=  key      = <string> |
3193 +                         <user_attr>
3194 +
3195 +   <group_attr>      :=  enlist   = <entity_spec> |
3196 +                         key      = <string> |
3197 +                         <user_attr>
3198 +
3199 +   <when_attr>       := member   = <string> |
3200 +                        enlist   = <entity_spec> |
3201 +                        <svc> |
3202 +                        <when_attr_block>
3203 +
3204 +   <when_attr_block> := <when_decl> {
3205 +                          <when_attr>*
3206 +                        }
3207  
3208     <svc>             := <svc_auth> | <cmd_auth>
3209  
3210     <cmd_auth>        := cmd = <string> {
3211 -                        <cmd-match>*
3212 +                          <when_match>*
3213                          }
3214  
3215 -   <cmd-match>      := <permission> <string>
3216 +   <when_match>      := <permission> <string> |
3217 +                        <when_match_block>
3218 +
3219 +   <when_match_block> := <when_decl> {
3220 +                           <when_match>*
3221 +                         }
3222  
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>*
3228 +                          <when_AV_pair>*
3229 +                        }
3230 +
3231 +   <when_AV_pair>    := [ optional ] <string> = <string> |
3232 +                        <when_AV_pair_block>
3233 +
3234 +   <when_AV_pair_block> := <when_decl> {
3235 +                             <when_AV_pair>*
3236                             }
3237  
3238 -   <attr_value_pair> := [ optional ] <string> = <string>
3239 +   <when_decl>       := when = <expr>
3240  
3241 +# to avoid ambiguous precence by forbid of "or" & "and" without parentheses:
3242 +   <expr>            := <entity_spec> |
3243 +                        not <expr> |
3244 +                        '(' <expr_or>  ')' |
3245 +                        '(' <expr_and> ')'
3246 +
3247 +   <expr_or>         := <expr> |
3248 +                        <expr> or  <expr_or>
3249 +
3250 +   <expr_and>        := <expr> |
3251 +                        <expr> and <expr_and>
3252 +
3253 +   <entity_spec>     := ( user | host | group ) <string>
3254  */
3255  
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";
3270  
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.
3274 -
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 */
3277 -
3278 -struct host {
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         */
3284 -};
3285 -
3286 -/* A user or group definition
3287 -
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
3290 -   peril */
3291 -
3292 -struct user {
3293 -    char *name;                        /* username */
3294 -    void *hash;                        /* hash table next pointer */
3295 -    int line;                  /* line number defined on */
3296 -    long flags;                        /* flags field */
3297 -
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 */
3301 -
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 */
3312 -#ifdef MSCHAP
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
3319 -                                * cmd */
3320 -    NODE *svcs;                        /* pointer to svc nodes */
3321 -#ifdef MAXSESS
3322 -    int maxsess;               /* Max sessions/user */
3323 -#endif /* MAXSESS */
3324 -    char *time;                /* Timestamp  */
3325 -};
3326 -
3327 -typedef struct host HOST;
3328 -typedef struct user USER;
3329  
3330  /* Only the first 2 fields (name and hash) are used by the hash table
3331     routines to hashh structures into a table.
3332  */
3333  
3334 -union hash {
3335 -    struct user u;
3336 -    struct host h;
3337 -};
3338 -
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 */
3343  
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 */
3347  
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;
3353 +    int line;
3354 +};
3355 +static struct enlist_entity_item * enlist_entity_list;
3356 +static struct enlist_entity_item **enlist_entity_list_tailp = &enlist_entity_list;
3357  
3358 -static void
3359 - sym_get();
3360  
3361 +static void parse_error TAC_ARGS((char *fmt,...)) G_GNUC_PRINTF(1, 2);
3362  
3363  #ifdef __STDC__
3364 +
3365  #include <stdarg.h>            /* ANSI C, variable length args */
3366  static void
3367  parse_error(char *fmt,...)
3368 -#else
3369 +
3370 +#else /* __STDC__ */
3371 +
3372  #include <varargs.h>           /* has 'vararg' definitions */
3373  /* VARARGS2 */
3374  static void
3375  parse_error(fmt, va_alist)
3376  char *fmt;
3377 -
3378  va_dcl                         /* no terminating semi-colon */
3379 -#endif
3380 +
3381 +#endif /* __STDC__ */
3382  {
3383      char msg[256];             /* temporary string */
3384      va_list ap;
3385 @@ -220,7 +264,9 @@ va_dcl                              /* no terminating semi-colon */
3386      tac_exit(1);
3387  }
3388  
3389 -char *
3390 +const char *cfg_nodestring TAC_ARGS((int type));
3391 +
3392 +const char *
3393  cfg_nodestring(type)
3394      int type;
3395  {
3396 @@ -250,6 +296,54 @@ cfg_nodestring(type)
3397      }
3398  }
3399  
3400 +const char *entity_type_to_string TAC_ARGS((int entity_type));
3401 +
3402 +const char *
3403 +entity_type_to_string(entity_type)
3404 +int entity_type;
3405 +{
3406 +    switch (entity_type) {
3407 +    case S_user:
3408 +       return ("user");
3409 +    case S_host:
3410 +       return ("host");
3411 +    case S_group:
3412 +       return ("group");
3413 +    }
3414 +    return (NULL);
3415 +}
3416 +
3417 +static void **entity_type_to_hashtable TAC_ARGS((int entity_type));
3418 +
3419 +static void **
3420 +entity_type_to_hashtable(entity_type)
3421 +int entity_type;
3422 +{
3423 +    switch (entity_type) {
3424 +    case S_user:
3425 +       return (usertable);
3426 +    case S_host:
3427 +       return (hosttable);
3428 +    case S_group:
3429 +       return (grouptable);
3430 +    }
3431 +    return (NULL);
3432 +}
3433 +
3434 +void scan_invalidate_entities TAC_ARGS((enum invalidate_scan what));
3435 +
3436 +void
3437 +scan_invalidate_entities(what)
3438 +enum invalidate_scan what;
3439 +{
3440 +    scan_invalidate_entities_hashtable( usertable, what);
3441 +    scan_invalidate_entities_hashtable( hosttable, what);
3442 +    scan_invalidate_entities_hashtable(grouptable, what);
3443 +}
3444 +
3445 +
3446 +static void free_attrs TAC_ARGS((NODE *node));
3447 +
3448  static void
3449  free_attrs(node)
3450  NODE *node;
3451 @@ -257,13 +351,17 @@ NODE *node;
3452      NODE *next;
3453  
3454      while (node) {
3455 +       unlink_expr(node->when);
3456 +       free_expr(node->when);
3457 +       node->when = NULL;
3458 +
3459         switch (node->type) {
3460         case N_optarg:
3461         case N_arg:
3462             if (debug & DEBUG_CLEAN_FLAG)
3463                 report(LOG_DEBUG, "free_cmd_match %s %s",
3464                        cfg_nodestring(node->type),
3465 -                      node->value);
3466 +                      (const char *) node->value);
3467             break;
3468         default:
3469             report(LOG_ERR, "Illegal node type %s for free_attrs",
3470 @@ -278,6 +376,8 @@ NODE *node;
3471      }
3472  }
3473  
3474 +static void free_cmd_matches TAC_ARGS((NODE *node));
3475 +
3476  static void
3477  free_cmd_matches(node)
3478  NODE *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),
3483 -                  node->value);
3484 +                  (const char *) node->value);
3485 +
3486 +       unlink_expr(node->when);
3487 +       free_expr(node->when);
3488 +       node->when = NULL;
3489  
3490         free(node->value);      /* text */
3491 -       free(node->value1);     /* regexp compiled text */
3492 +
3493 +#ifdef WITH_INCLUDED_REGEX
3494 +
3495 +       free(node->value1);     /* tac_regexp compiled text */
3496 +
3497 +#else /* WITH_INCLUDED_REGEX */
3498 +
3499 +       regfree((regex_t *) node->value1);      /* POSIX regex compiled text */
3500 +
3501 +#endif /* WITH_INCLUDED_REGEX */
3502 +
3503         next = node->next;
3504         free(node);
3505         node = next;
3506      }
3507  }
3508  
3509 +static void free_svcs TAC_ARGS((NODE *node));
3510 +
3511  static void
3512  free_svcs(node)
3513  NODE *node;
3514 @@ -305,12 +421,16 @@ NODE *node;
3515      NODE *next;
3516  
3517      while (node) {
3518 +       unlink_expr(node->when);
3519 +       free_expr(node->when);
3520 +       node->when = NULL;
3521  
3522         switch (node->type) {
3523         case N_svc_cmd:
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);
3531             next = node->next;
3532 @@ -340,85 +460,107 @@ NODE *node;
3533      }
3534  }
3535  
3536 +static void free_enlist_entity_item TAC_ARGS((struct enlist_entity_item *item));
3537 +
3538 +static void
3539 +free_enlist_entity_item(item)
3540 +struct enlist_entity_item *item;
3541 +{
3542 +    free(item->parent);
3543 +    free(item->child);
3544 +    free_expr(item->when);
3545 +}
3546 +
3547 +
3548 +static void free_entity TAC_ARGS((ENTITY *entity));
3549 +
3550  static void
3551 -free_userstruct(user)
3552 -USER *user;
3553 +free_entity(entity)
3554 +ENTITY *entity;
3555  {
3556      if (debug & DEBUG_CLEAN_FLAG)
3557         report(LOG_DEBUG, "free %s %s",
3558 -              (user->flags & FLAG_ISUSER) ? "user" : "group",
3559 -              user->name);
3560 -
3561 -    if (user->name)
3562 -       free(user->name);
3563 -    if (user->full_name)
3564 -       free(user->full_name);
3565 -    if (user->login)
3566 -       free(user->login);
3567 -    if (user->member)
3568 -       free(user->member);
3569 -    if (user->expires)
3570 -       free(user->expires);
3571 -    if (user->time)
3572 -       free(user->time);
3573 -    if (user->arap)
3574 -       free(user->arap);
3575 -    if (user->chap)
3576 -       free(user->chap);
3577 +               entity_type_to_string(entity->type), entity->name);
3578 +
3579 +    /* function MUST be called while the whole entity is still VALID! */
3580 +    scan_free_entity(entity);
3581 +
3582 +    if (entity->name)
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);
3590 +    if (entity->time)
3591 +       free(entity->time);
3592 +    if (entity->arap)
3593 +       free(entity->arap);
3594 +    if (entity->chap)
3595 +       free(entity->chap);
3596  #ifdef MSCHAP
3597 -    if (user->mschap)
3598 -       free(user->mschap);
3599 +    if (entity->mschap)
3600 +       free(entity->mschap);
3601  #endif /* MSCHAP */
3602 -    if (user->pap)
3603 -       free(user->pap);
3604 -    if (user->opap)
3605 -       free(user->opap);
3606 -    if (user->global)
3607 -       free(user->global);
3608 -    if (user->msg)
3609 -       free(user->msg);
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);
3615 +    if (entity->pap)
3616 +       free(entity->pap);
3617 +    if (entity->opap)
3618 +       free(entity->opap);
3619 +    if (entity->global)
3620 +       free(entity->global);
3621 +    if (entity->msg)
3622 +       free(entity->msg);
3623 +    if (entity->before_author)
3624 +       free(entity->before_author);
3625 +    if (entity->after_author)
3626 +       free(entity->after_author);
3627 +    if (entity->key)
3628 +       free(entity->key);
3629 +    free_svcs(entity->svcs);
3630  }
3631  
3632 +static void free_hashtable TAC_ARGS((void **hashtable));
3633 +
3634  static void
3635 -free_hoststruct(host)
3636 -HOST *host;
3637 +free_hashtable(hashtable)
3638 +void **hashtable;
3639  {
3640 -    if (debug & DEBUG_CLEAN_FLAG)
3641 -       report(LOG_DEBUG, "free %s",
3642 -               host->name);
3643 -
3644 -    if (host->name)
3645 -       free(host->name);
3646 -    
3647 -    if (host->key)
3648 -       free(host->key);
3649 +    int i;
3650 +    ENTITY *entity,**entityp;
3651  
3652 -    if (host->type)
3653 -       free(host->type);
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);
3659 +           free(entity);
3660 +       }
3661 +    }
3662  }
3663  
3664 +
3665  /*
3666   * Exported routines
3667   */
3668  
3669 +void cfg_clean_config TAC_ARGS((void));
3670 +
3671  /* Free all allocated structures preparatory to re-reading the config file */
3672  void
3673  cfg_clean_config()
3674  {
3675 -    int i;
3676 -    USER *entry, *next;
3677 -    HOST *host_entry,*hn;
3678 +    struct enlist_entity_item *enlist_entity_item;
3679  
3680      if (authen_default) {
3681         free(authen_default);
3682         authen_default = NULL;
3683      }
3684  
3685 +    if (algorithm_recursive) {
3686 +       algorithm_recursive = 0;
3687 +    }
3688 +
3689      if (authen_default_method) {
3690         authen_default_method = 0;
3691      }
3692 @@ -438,43 +580,21 @@ cfg_clean_config()
3693         session.db_acct = NULL;
3694      }
3695  
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);
3702 -           free(host_entry);
3703 -           host_entry = hn;
3704 -       }
3705 -       hosttable[i] = NULL;
3706 -    }
3707 -
3708 -    /* the grouptable */
3709 -    for (i = 0; i < HASH_TAB_SIZE; i++) {
3710 -       entry = (USER *) grouptable[i];
3711 -       while (entry) {
3712 -           next = entry->hash;
3713 -           free_userstruct(entry);
3714 -           free(entry);
3715 -           entry = next;
3716 -       }
3717 -       grouptable[i] = NULL;
3718 -    }
3719 +    free_hashtable( usertable);
3720 +    free_hashtable( hosttable);
3721 +    free_hashtable(grouptable);
3722  
3723 -    /* the usertable */
3724 -    for (i = 0; i < HASH_TAB_SIZE; i++) {
3725 -       entry = (USER *) usertable[i];
3726 -       while (entry) {
3727 -           next = entry->hash;
3728 -           free_userstruct(entry);
3729 -           free(entry);
3730 -           entry = next;
3731 -       }
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);
3738      }
3739 +    enlist_entity_list_tailp = &enlist_entity_list;
3740  }
3741  
3742 +static int parse_permission TAC_ARGS((void));
3743 +
3744  static int
3745  parse_permission()
3746  {
3747 @@ -490,6 +610,8 @@ parse_permission()
3748      return (symbol);
3749  }
3750  
3751 +static int parse TAC_ARGS((int symbol));
3752 +
3753  static int
3754  parse(symbol)
3755  int symbol;
3756 @@ -505,9 +627,13 @@ int symbol;
3757      return (0);
3758  }
3759  
3760 +static int parse_opt_svc_default TAC_ARGS((void));
3761 +
3762  static int
3763  parse_opt_svc_default()
3764  {
3765 +    int retval;
3766 +
3767      if (sym_code != S_default) {
3768         return (0);
3769      }
3770 @@ -515,14 +641,30 @@ parse_opt_svc_default()
3771      parse(S_default);
3772      parse(S_svc);
3773      parse(S_separator);
3774 -    if (sym_code == S_permit) {
3775 -       parse(S_permit);
3776 -       return (S_permit);
3777 +
3778 +    switch (sym_code) {
3779 +    default:
3780 +       parse_error("expecting 'permit', 'deny' or 'default' but found '%s' on line %d",
3781 +                   sym_buf, sym_line);
3782 +       return (1);
3783 +
3784 +    case S_default:
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);
3788 +           return (1);
3789 +       }
3790 +       /* FALLTHRU */
3791 +    case S_permit:
3792 +    case S_deny:
3793 +       retval = sym_code;
3794 +       sym_get();
3795 +       return (retval);
3796      }
3797 -    parse(S_deny);
3798 -    return (S_deny);
3799  }
3800  
3801 +static int parse_opt_attr_default TAC_ARGS((void));
3802 +
3803  static int
3804  parse_opt_attr_default()
3805  {
3806 @@ -536,20 +678,19 @@ parse_opt_attr_default()
3807      return (S_permit);
3808  }
3809  
3810 -static int parse_user();
3811 -static int parse_host();
3812 -
3813 -static void
3814 - rch();
3815 -
3816  /*
3817     Parse lines in the config file, creating data structures
3818     Return 1 on error, otherwise 0 */
3819  
3820 +static int parse_decls TAC_ARGS((void));
3821 +
3822  static int
3823  parse_decls()
3824  {
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;
3829  
3830      sym_code = 0;
3831      rch();
3832 @@ -614,7 +755,7 @@ parse_decls()
3833                 case S_db:
3834  #endif
3835  #ifdef USE_LDAP
3836 -               case S_ldap;
3837 +               case S_ldap:
3838  #endif
3839  #ifdef USE_PAM
3840                 case S_pam:
3841 @@ -642,6 +783,26 @@ parse_decls()
3842                 continue;
3843             }
3844  
3845 +       case S_authorization:
3846 +           sym_get();
3847 +           parse(S_separator);
3848 +           switch (sym_code) {
3849 +           default:
3850 +               parse_error("expecting 'first' or 'recursive' but found '%s' on line %d",
3851 +                           sym_buf, sym_line);
3852 +               return (1);
3853 +
3854 +           case S_first:
3855 +               parse(S_first);
3856 +               algorithm_recursive = 0;
3857 +               continue;
3858 +
3859 +           case S_recursive:
3860 +               parse(S_recursive);
3861 +               algorithm_recursive = 1;
3862 +               continue;
3863 +           }
3864 +
3865         case S_key:
3866             /* Process a key declaration. */
3867             sym_get();
3868 @@ -656,17 +817,12 @@ parse_decls()
3869             sym_get();
3870             continue;
3871  
3872 -       case S_host:
3873 -           parse_host();
3874 -           continue;
3875 -       
3876         case S_user:
3877 +       case S_host:
3878         case S_group:
3879 -           parse_user();
3880 +           parse_entity(sym_code);
3881             continue;
3882  
3883 -           /* case S_host: parse_host(); continue; */
3884 -
3885         default:
3886             parse_error("Unrecognised token %s on line %d", sym_buf, sym_line);
3887             return (1);
3888 @@ -674,8 +830,6 @@ parse_decls()
3889      }
3890  }
3891  
3892 -static NODE *parse_svcs();
3893 -
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) { \
3898      } \
3899      field = tac_strdup(sym_buf);
3900  
3901 -static int
3902 -parse_host()
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)
3908 +
3909 +static struct expr *parse_expr_node TAC_ARGS((int single_item));
3910 +
3911 +static struct expr *
3912 +parse_expr_node(single_item)
3913 +int single_item;
3914  {
3915 -    HOST *h;
3916 -    HOST *host = (HOST *) tac_malloc(sizeof(HOST));
3917 -    int save_sym;
3918 -    char buf[MAX_INPUT_LINE_LEN];
3919 +    struct expr *expr_root = NULL;
3920 +    struct expr **succ_exprp = &expr_root;
3921 +    struct expr *expr;
3922  
3923 -    bzero(host, sizeof(HOST));
3924 +    while (1) {
3925 +       switch (sym_code) {
3926  
3927 +       case S_not:
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;
3934             sym_get();
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);
3941 +               return (NULL);
3942 +           }
3943 +           break;
3944 +
3945 +       case S_user:
3946 +       case S_host:
3947 +       case S_group:
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;
3954 +           sym_get();
3955 +           expr->u.entity.name = tac_strdup(sym_buf);
3956 +           sym_get();
3957 +           expr->u.entity.entity = NULL;       /* not known yet */
3958 +           break;
3959  
3960 -    h = hash_add_entry(hosttable, (void *) host);
3961 +       case S_openparen:
3962 +           sym_get();
3963 +           expr = parse_expr_node(0 /* single_item */);
3964 +           *succ_exprp = expr;
3965 +           parse(S_closeparen);
3966  
3967 -    if (h) {
3968 -        parse_error("multiply defined %s on lines %d and %d",
3969 -                    host->name, h->line, sym_line);
3970 -        return (1);
3971 +           if (expr->next) {
3972 +               report(LOG_ERR, "Illegal filled next field of parsed parenthesed expr");
3973 +               free_expr(expr_root);
3974 +               return (NULL);
3975             }
3976 +           succ_exprp = &expr->next;
3977 +           break;
3978  
3979 -    sym_get();
3980 -    parse(S_openbra);
3981 +       default:
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);
3985 +           return (NULL);
3986 +       }
3987 +
3988 +       if (single_item)                /* used by 'not' operator with high precedence */
3989 +           return (expr_root);
3990  
3991 -    while (1) {
3992          switch (sym_code) {
3993 -        case S_eof:
3994 -            return (0);
3995 -       case S_key:
3996 -           ASSIGN(host->key);
3997 -            sym_get();
3998 -            continue;
3999 -       case S_type:
4000 -           ASSIGN(host->type);
4001 +
4002 +       case S_and:
4003 +       case S_or:
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",
4006 +                       sym_line);
4007 +               free_expr(expr_root);
4008 +               return (NULL);
4009 +           }
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;
4016 +               expr_root = expr;
4017 +           }
4018             sym_get();
4019             continue;
4020 +       }
4021  
4022 -       case S_closebra:
4023 -            parse(S_closebra);
4024 -            return (0);
4025 +       return(expr_root);
4026 +    }
4027 +}
4028  
4029 -       default:
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));
4033  
4034 -            return (0);
4035 +static struct expr *
4036 +parse_when_decl()
4037 +{
4038 +    parse(S_when);
4039 +    if (!algorithm_recursive) {
4040 +       parse_error("'when' conditionals supported only if set top level 'authorization = recursive', on line %d",
4041 +                   sym_line);
4042 +       return (NULL);
4043      }
4044 -    } /* while */
4045 -} /* finish parse_host */
4046 +    parse(S_separator);
4047 +    return (parse_expr_node(0 /* single_item */));
4048 +}
4049 +
4050 +static void when_expr_root_init TAC_ARGS((void));
4051 +
4052 +static void
4053 +when_expr_root_init()
4054 +{
4055 +    free_expr(when_expr_root);
4056 +    when_expr_root = new_expr(S_and);
4057 +}
4058  
4059 +static int push_parsed_when_decl TAC_ARGS((void));
4060  
4061  static int
4062 -parse_user()
4063 +push_parsed_when_decl()
4064  {
4065 -    USER *n;
4066 -    int isuser;
4067 -    USER *user = (USER *) tac_malloc(sizeof(USER));
4068 -    int save_sym;
4069 -    char **fieldp;
4070 -    char buf[MAX_INPUT_LINE_LEN];
4071 +    struct expr *parsed_expr;
4072  
4073 -    bzero(user, sizeof(USER));
4074 +    parsed_expr = parse_when_decl();
4075 +    if (!parsed_expr)
4076 +       return (1);
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);
4080 +       return (1);
4081 +    }
4082 +    if (parsed_expr->next) {
4083 +       report(LOG_ERR, "INTERNAL: Illegal filled next field of parsed expr");
4084 +       free_expr(parsed_expr);
4085 +       return (1);
4086 +    }
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;
4090 +    return (0);
4091 +}
4092  
4093 -    isuser = (sym_code == S_user);
4094 +static int pop_when_decl TAC_ARGS((void));
4095  
4096 -    sym_get();
4097 -    parse(S_separator);
4098 -    user->name = tac_strdup(sym_buf);
4099 -    user->line = sym_line;
4100 +static int
4101 +pop_when_decl()
4102 +{
4103 +    struct expr *first_expr;
4104  
4105 -    if (isuser) {
4106 -       user->flags |= FLAG_ISUSER;
4107 -       n = hash_add_entry(usertable, (void *) user);
4108 -    } else {
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()!");
4113 +       return (1);
4114      }
4115 -
4116 -    if (n) {
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");
4123         return (1);
4124      }
4125 -    sym_get();
4126 -    parse(S_openbra);
4127 +    when_expr_root->u.and_or.child_first = first_expr->next;
4128 +    first_expr->next = NULL;
4129 +    free_expr(first_expr);
4130 +    return (0);
4131 +}
4132  
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));
4136  
4137 -    while (1) {
4138 -       switch (sym_code) {
4139 -       case S_eof:
4140 -           return (0);
4141 +static struct expr *
4142 +copy_current_when_decl()
4143 +{
4144 +    return (dupl_expr(when_expr_root));
4145 +}
4146  
4147 -       case S_time:
4148 -          ASSIGN(user->time);
4149 -          sym_get(); 
4150 -          continue;
4151 +static struct expr *when_expr_dungeon;
4152  
4153 -       case S_before:
4154 -           sym_get();
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));
4160 +
4161 +static void
4162 +starve_when_decl()
4163 +{
4164 +    if (!WHEN_EXPR_ROOT_SANE()) {
4165 +       report(LOG_WARNING, "INTERNAL: when_expr_root not sane during starve_when_decl!");
4166 +    }
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();
4171 +}
4172 +
4173 +static int feed_when_decl TAC_ARGS((void));
4174 +
4175 +static int
4176 +feed_when_decl()
4177 +{
4178 +    if (!when_expr_dungeon) {
4179 +       report(LOG_ERR, "INTERNAL: No expr in dungeon and feed_when_decl() called");
4180 +       return (1);
4181 +    }
4182 +    if (!WHEN_EXPR_ROOT_EMPTY()) {
4183 +       report(LOG_WARNING, "INTERNAL: Some 'when' expression found still pushed in dungeon during feed_when_decl()!");
4184 +    }
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;
4189 +    return (0);
4190 +}
4191 +
4192 +ENTITY *entity_lookup TAC_ARGS((int type, const char *name));
4193 +
4194 +ENTITY *
4195 +entity_lookup(type, name)
4196 +int type;
4197 +const char *name;
4198 +{
4199 +    return (hash_lookup(entity_type_to_hashtable(type), name));
4200 +}
4201 +
4202 +static int enlist_entity_connect TAC_ARGS((void));
4203 +
4204 +static int
4205 +enlist_entity_connect()
4206 +{
4207 +    struct enlist_entity_item *item;
4208 +    ENTITY *parent_entity, *child_entity;
4209 +
4210 +    while ((item=enlist_entity_list)) {
4211 +
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);
4216 +           return (1);
4217 +       }
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'! */
4224 +       }
4225 +
4226 +       if (!enlist_entity_direct(parent_entity, child_entity, item->when))
4227 +           return (1);         /* entities not found */
4228 +
4229 +       enlist_entity_list = item->next;
4230 +       item->when = NULL;
4231 +       free_enlist_entity_item(item);
4232 +       free(item);
4233 +    }
4234 +    enlist_entity_list_tailp = &enlist_entity_list;
4235 +    return (0);
4236 +}
4237 +
4238 +static void enlist_entity TAC_ARGS((int parent_type, const char *parent, int child_type, const char *child));
4239 +
4240 +static void
4241 +enlist_entity(parent_type, parent, child_type, child)
4242 +int parent_type;
4243 +const char *parent;
4244 +int child_type;
4245 +const char *child;
4246 +{
4247 +    struct enlist_entity_item *item =
4248 +               (struct enlist_entity_item *) tac_malloc(sizeof(struct enlist_entity_item));
4249 +
4250 +    item->next = NULL;
4251 +    *enlist_entity_list_tailp = item;
4252 +    enlist_entity_list_tailp = &item->next;
4253 +
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;
4260 +}
4261 +
4262 +static int parse_entity_spec TAC_ARGS((void));
4263 +
4264 +/* returns 0 for error, otherwise S_user, S_host or S_group; sym_buf filled */
4265 +static int
4266 +parse_entity_spec()
4267 +{
4268 +    int retval;
4269 +
4270 +    if (sym_code != S_user
4271 +     && sym_code != S_host
4272 +     && sym_code != S_group
4273 +       ) {
4274 +       parse_error("Expecting 'user', 'host' or ' group' as entity specification, found %s on line %d",
4275 +                   sym_buf, sym_line);
4276 +       return (0);
4277 +    }
4278 +
4279 +    retval = sym_code;
4280      sym_get();
4281 -           continue;
4282  
4283 -       case S_after:
4284 +    return (retval);
4285 +}
4286 +
4287 +static int parse_conditional_block_item TAC_ARGS((ENTITY *entity));
4288 +
4289 +static int
4290 +parse_conditional_block_item(entity)
4291 +ENTITY *entity;
4292 +{
4293 +    switch (sym_code) {
4294 +    case S_eof:
4295 +       return (1);
4296 +
4297 +    /* case S_closebra: not needed, handled by our caller parse_conditional_block() */
4298 +
4299 +    default:
4300 +       parse_error("Unrecognised keyword %s for entity on line %d",
4301 +                   sym_buf, sym_line);
4302 +       return (1);
4303 +
4304 +    case S_member:
4305         sym_get();
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);
4312         sym_get();
4313 -           continue;
4314 +       break;
4315 +
4316 +    case S_enlist: {
4317 +       int parsed_entity_type;
4318 +
4319 +       if (entity->type != S_group) {
4320 +           parse_error("'enlist' keyword allowed only in 'group' section on line %d",
4321 +                       sym_line);
4322 +           return (1);
4323 +       }
4324 +       sym_get();
4325 +       parse(S_separator);
4326 +       parsed_entity_type = parse_entity_spec();
4327 +       if (!parsed_entity_type)
4328 +           return (1);
4329 +       enlist_entity(entity->type, entity->name, parsed_entity_type, sym_buf);
4330 +       sym_get();
4331 +       break;
4332 +       }
4333  
4334      case S_svc:
4335      case S_cmd:
4336  
4337 -           if (user->svcs) {   
4338 +       if (entity->svcs) {
4339             /*
4340              * Already parsed some services/commands. Thanks to Gabor Kiss
4341              * who found this bug.
4342              */
4343             NODE *p;
4344 -               for (p=user->svcs; p->next; p=p->next) 
4345 +           for (p=entity->svcs; p->next; p=p->next)
4346                 /* NULL STMT */;
4347             p->next = parse_svcs();
4348         } else {
4349 -               user->svcs = parse_svcs();
4350 +           entity->svcs = parse_svcs();
4351 +       }
4352 +       break;
4353 +
4354 +    case S_when:
4355 +       if (parse_conditional_block(entity))
4356 +           return (1);
4357 +       break;
4358 +    }
4359 +
4360 +    return (0);
4361 +}
4362 +
4363 +static int parse_conditional_block TAC_ARGS((ENTITY *entity));
4364 +
4365 +static int
4366 +parse_conditional_block(entity)
4367 +ENTITY *entity;
4368 +{
4369 +    int retval = -1 /* GCC paranoia */;
4370 +
4371 +    if (push_parsed_when_decl())
4372 +       return (1);
4373 +    parse(S_openbra);
4374 +
4375 +    while (1) {
4376 +       if (sym_code == S_closebra) {
4377 +           sym_get();
4378 +           retval = 0;         /* success */
4379 +           break;
4380 +       }
4381 +
4382 +       if (parse_conditional_block_item(entity)) {
4383 +           retval = 1;         /* failure */
4384 +           break;
4385 +       }
4386 +    }
4387 +
4388 +    if (pop_when_decl())
4389 +       return (1);
4390 +
4391 +    return (retval);
4392 +}
4393 +
4394 +/* passed 'name' WILL be directly stored to returned ENTITY, don't touch it! */
4395 +
4396 +ENTITY *new_entity TAC_ARGS((int type, char *name, int line));
4397 +
4398 +ENTITY *
4399 +new_entity(type, name, line)
4400 +int type;
4401 +char *name;
4402 +int line;
4403 +{
4404 +    ENTITY *entity = (ENTITY *) tac_malloc(sizeof(ENTITY));
4405 +    ENTITY *hash_conflict;
4406 +
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);
4412 +
4413 +    entity->type = type;
4414 +    entity->name = name;
4415 +    entity->line = line;
4416 +
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);
4422 +       free (entity);
4423 +       return (NULL);
4424 +    }
4425 +
4426 +    return (entity);
4427 +}
4428 +
4429 +static int parse_entity TAC_ARGS((int entity_type));
4430 +
4431 +static int
4432 +parse_entity(entity_type)
4433 +int entity_type;
4434 +{
4435 +    ENTITY *entity;
4436 +    int save_sym;
4437 +    char **fieldp = NULL /* GCC paranoia */;
4438 +    char buf[MAX_INPUT_LINE_LEN];
4439 +
4440 +    sym_get();
4441 +    parse(S_separator);
4442 +
4443 +    entity = new_entity(entity_type, tac_strdup(sym_buf) /* name */, sym_line /* line */);
4444 +    if (!entity)
4445 +       return (1);             /* 'hash_add_entry()' conflict, 'tac_strdup(sym_buf)' leaked! */
4446 +
4447 +    sym_get();
4448 +    parse(S_openbra);
4449 +
4450 +    /* Is the default deny for svcs or cmds to be overridden? */
4451 +    entity->svc_dflt = parse_opt_svc_default();
4452 +
4453 +    while (1) {
4454 +       if (entity_type != S_user)
4455 +           switch (sym_code) {
4456 +           case S_key:
4457 +               ASSIGN(entity->key);
4458 +               sym_get();
4459 +               continue;
4460             }
4461 +
4462 +       switch (sym_code) {
4463 +       case S_eof:
4464 +           return (0);
4465 +
4466 +       case S_time:
4467 +          ASSIGN(entity->time);
4468 +          sym_get();
4469 +          continue;
4470 +
4471 +       case S_before:
4472 +           sym_get();
4473 +           parse(S_authorization);
4474 +           if (entity->before_author)
4475 +               free(entity->before_author);
4476 +           entity->before_author = tac_strdup(sym_buf);
4477 +           sym_get();
4478 +           continue;
4479 +
4480 +       case S_after:
4481 +           sym_get();
4482 +           parse(S_authorization);
4483 +           if (entity->after_author)
4484 +               free(entity->after_author);
4485 +           entity->after_author = tac_strdup(sym_buf);
4486 +           sym_get();
4487             continue;
4488  
4489         case S_login:
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,
4495                             sym_buf, sym_line);
4496                 tac_exit(1);
4497             }
4498 @@ -837,15 +1355,15 @@ parse_user()
4499             switch(sym_code) {
4500  
4501             case S_skey:
4502 -               user->login = tac_strdup(sym_buf);
4503 +               entity->login = tac_strdup(sym_buf);
4504                 break;
4505  
4506             case S_nopasswd:
4507                 /* set to dummy string, so that we detect a duplicate
4508                  * password definition attempt
4509                  */
4510 -               user->login = tac_strdup(nopasswd_str);
4511 -               user->nopasswd = 1;
4512 +               entity->login = tac_strdup(nopasswd_str);
4513 +               entity->nopasswd = 1;
4514                 break;
4515  
4516             case S_file:
4517 @@ -860,7 +1378,7 @@ parse_user()
4518                 sprintf(buf, "%s ", sym_buf);
4519                 sym_get();
4520                 strcat(buf, sym_buf);
4521 -               user->login = tac_strdup(buf);
4522 +               entity->login = tac_strdup(buf);
4523                 break;
4524  
4525             default:
4526 @@ -878,9 +1396,9 @@ parse_user()
4527             continue;
4528  
4529         case S_pap:
4530 -           if (user->pap) {
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,
4535                             sym_buf, sym_line);
4536                 tac_exit(1);
4537             }
4538 @@ -896,11 +1414,11 @@ parse_user()
4539                 sprintf(buf, "%s ", sym_buf);
4540                 sym_get();
4541                 strcat(buf, sym_buf);
4542 -               user->pap = tac_strdup(buf);
4543 +               entity->pap = tac_strdup(buf);
4544                 break;
4545  
4546                 sprintf(buf, "%s ", sym_buf);
4547 -               user->pap = tac_strdup(buf);
4548 +               entity->pap = tac_strdup(buf);
4549                 break;
4550  
4551             default:
4552 @@ -918,23 +1436,17 @@ parse_user()
4553             continue;
4554  
4555         case S_name:
4556 -           ASSIGN(user->full_name);
4557 -           sym_get();
4558 -           continue;
4559 -
4560 -       case S_member:
4561 -           ASSIGN(user->member);
4562 +           ASSIGN(entity->full_name);
4563             sym_get();
4564             continue;
4565  
4566 -
4567         case S_expires:
4568 -           ASSIGN(user->expires);
4569 +           ASSIGN(entity->expires);
4570             sym_get();
4571             continue;
4572  
4573         case S_message:
4574 -           ASSIGN(user->msg);
4575 +           ASSIGN(entity->msg);
4576             sym_get();
4577             continue;
4578  
4579 @@ -952,20 +1464,32 @@ parse_user()
4580             parse(S_cleartext);
4581             strcat(buf, sym_buf);
4582  
4583 -           if (save_sym == S_arap)
4584 -               fieldp = &user->arap;
4585 -           if (save_sym == S_chap)
4586 -               fieldp = &user->chap;
4587 +           switch (save_sym) {
4588 +           case S_arap:
4589 +               fieldp = &entity->arap;
4590 +               break;
4591 +           case S_chap:
4592 +               fieldp = &entity->chap;
4593 +               break;
4594  #ifdef MSCHAP
4595 -           if (save_sym == S_mschap)
4596 -               fieldp = &user->mschap;
4597 +           case S_mschap:
4598 +               fieldp = &entity->mschap;
4599 +               break;
4600  #endif /* 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;
4607 +           case S_pap:
4608 +               fieldp = &entity->pap;
4609 +               break;
4610 +           case S_opap:
4611 +               fieldp = &entity->opap;
4612 +               break;
4613 +           case S_global:
4614 +               fieldp = &entity->global;
4615 +               break;
4616 +           default:
4617 +               report(LOG_ERR, "INTERNAL: fieldp not recognized (on line %d)",
4618 +                       sym_line);
4619 +               continue;
4620 +           }
4621  
4622             if (*fieldp) {
4623                 parse_error("Duplicate value for %s %s and %s on line %d",
4624 @@ -984,7 +1508,7 @@ parse_user()
4625         case S_maxsess:
4626             sym_get();
4627             parse(S_separator);
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",
4631                     sym_buf, sym_line);
4632             }
4633 @@ -997,16 +1521,14 @@ parse_user()
4634                 fprintf(stderr,
4635                         "\npassword = <string> is obsolete. Use login = des <string>\n");
4636             }
4637 -           parse_error("Unrecognised keyword %s for user on line %d",
4638 -                       sym_buf, sym_line);
4639  
4640 -           return (0);
4641 +           if (parse_conditional_block_item(entity))
4642 +               return (0);             /* error message already printed */
4643         }
4644      }
4645  }
4646  
4647 -static NODE *parse_attrs();
4648 -static NODE *parse_cmd_matches();
4649 +static NODE *parse_svcs TAC_ARGS((void));
4650  
4651  static NODE *
4652  parse_svcs()
4653 @@ -1034,11 +1556,16 @@ parse_svcs()
4654  
4655         sym_get();
4656         parse(S_openbra);
4657 -
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 */
4663 +
4664         result->type = N_svc_cmd;
4665 +       result->when = copy_current_when_decl();
4666 +       expr_sink_register(result->when);
4667  
4668 -       parse(S_closebra);
4669         result->next = parse_svcs();
4670         return (result);
4671      }
4672 @@ -1075,25 +1602,52 @@ parse_svcs()
4673         result->value1 = tac_strdup(sym_buf);
4674         break;
4675      }
4676 +
4677      sym_get();
4678      parse(S_openbra);
4679 +    starve_when_decl();
4680 +
4681      result->dflt = parse_opt_attr_default();
4682      result->value = parse_attrs();
4683 +
4684      parse(S_closebra);
4685 +    feed_when_decl();
4686 +
4687 +    result->when = copy_current_when_decl();
4688 +    expr_sink_register(result->when);
4689 +
4690      result->next = parse_svcs();
4691      return (result);
4692  }
4693  
4694 -/*  <cmd-match>         := <permission> <string> */
4695 +/*  <cmd_match>         := <permission> <string> */
4696 +
4697 +static NODE *parse_cmd_matches TAC_ARGS((void));
4698  
4699  static NODE *
4700  parse_cmd_matches()
4701  {
4702 +    NODE *retval = NULL, **succp = &retval;
4703      NODE *result;
4704  
4705 -    if (sym_code != S_permit && sym_code != S_deny) {
4706 -       return (NULL);
4707 -    }
4708 +    for (;;) {
4709 +       switch (sym_code) {
4710 +       default:
4711 +           return (retval);
4712 +
4713 +       case S_when:
4714 +           if (push_parsed_when_decl())
4715 +               tac_exit(1);            /* no error return possibility */
4716 +           parse(S_openbra);
4717 +           result = parse_cmd_matches();
4718 +           parse(S_closebra);
4719 +           if (pop_when_decl())
4720 +               tac_exit(1);            /* no error return possibility */
4721 +           break;
4722 +
4723 +       case S_permit:
4724 +       case S_deny:
4725 +
4726             result = (NODE *) tac_malloc(sizeof(NODE));
4727  
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);
4732  
4733 -    result->value1 = (void *) regcomp(result->value);
4734 +#ifdef WITH_INCLUDED_REGEX
4735 +
4736 +           result->value1 = (void *) tac_regcomp(result->value);
4737 +
4738 +#else /* WITH_INCLUDED_REGEX */
4739 +
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;
4744 +           }
4745 +
4746 +#endif /* WITH_INCLUDED_REGEX */
4747 +
4748             if (!result->value1) {
4749                 report(LOG_ERR, "in regular expression %s on line %d",
4750                        sym_buf, sym_line);
4751 @@ -1110,30 +1677,56 @@ parse_cmd_matches()
4752             }
4753             sym_get();
4754  
4755 -    result->next = parse_cmd_matches();
4756 +           result->when = copy_current_when_decl();
4757 +           expr_sink_register(result->when);
4758  
4759 -    return (result);
4760 +           result->next = NULL;
4761 +       }
4762 +       *succp = result;
4763 +       while (result->next)
4764 +           result = result->next;      /* skip parsed chain from parse_cmd_matches() */
4765 +       succp = &result->next;
4766 +    }
4767 +    /* NOTREACHED */
4768  }
4769  
4770 +static NODE *parse_attrs TAC_ARGS((void));
4771 +
4772  static NODE *
4773  parse_attrs()
4774  {
4775 +    NODE *retval = NULL, **succp = &retval;
4776      NODE *result;
4777      char buf[MAX_INPUT_LINE_LEN];
4778 -    int optional = 0;
4779 +    int optional;
4780  
4781 -    if (sym_code == S_closebra) {
4782 -       return (NULL);
4783 -    }
4784 +    for (;;) {
4785 +       optional = 0;
4786 +
4787 +       switch (sym_code) {
4788 +       case S_closebra:
4789 +           return (retval);
4790 +
4791 +       case S_when:
4792 +           if (push_parsed_when_decl())
4793 +               tac_exit(1);            /* no error return possibility */
4794 +           parse(S_openbra);
4795 +           result = parse_attrs();
4796 +           parse(S_closebra);
4797 +           if (pop_when_decl())
4798 +               tac_exit(1);            /* no error return possibility */
4799 +           break;
4800 +
4801 +       case S_optional:
4802 +           optional = 1;
4803 +           sym_get();
4804 +           /* FALLTHRU */
4805 +       default:
4806             result = (NODE *) tac_malloc(sizeof(NODE));
4807  
4808             bzero(result, sizeof(NODE));
4809             result->line = sym_line;
4810  
4811 -    if (sym_code == S_optional) {
4812 -       optional++;
4813 -       sym_get();
4814 -    }
4815             result->type = optional ? N_optarg : N_arg;
4816  
4817             strcpy(buf, sym_buf);
4818 @@ -1144,13 +1737,22 @@ parse_attrs()
4819             parse(S_string);
4820  
4821             result->value = tac_strdup(buf);
4822 -    result->next = parse_attrs();
4823 -    return (result);
4824 +
4825 +           result->when = copy_current_when_decl();
4826 +           expr_sink_register(result->when);
4827 +
4828 +           result->next = NULL;
4829 +       }
4830 +       *succp = result;
4831 +       while (result->next)
4832 +           result = result->next;      /* skip parsed chain from parse_attrs() */
4833 +       succp = &result->next;
4834 +    }
4835 +    /* NOTREACHED */
4836  }
4837  
4838  
4839 -static void
4840 - getsym();
4841 +static void sym_get TAC_ARGS((void));
4842  
4843  static void
4844  sym_get()
4845 @@ -1163,9 +1765,11 @@ sym_get()
4846      }
4847  }
4848  
4849 +static char *sym_buf_add TAC_ARGS((int c));
4850 +
4851  static char *
4852  sym_buf_add(c)
4853 -char c;
4854 +int c;                         /* promoted "char" type */
4855  {
4856      if (sym_pos >= MAX_INPUT_LINE_LEN) {
4857         sym_buf[MAX_INPUT_LINE_LEN-1] = '\0';
4858 @@ -1180,6 +1784,8 @@ char c;
4859      return(sym_buf);
4860  }
4861  
4862 +static void getsym TAC_ARGS((void));
4863 +
4864  static void
4865  getsym()
4866  {
4867 @@ -1220,6 +1826,18 @@ next:
4868         rch();
4869         return;
4870  
4871 +    case '(':
4872 +       strcpy(sym_buf, "(");
4873 +       sym_code = S_openparen;
4874 +       rch();
4875 +       return;
4876 +
4877 +    case ')':
4878 +       strcpy(sym_buf, ")");
4879 +       sym_code = S_closeparen;
4880 +       rch();
4881 +       return;
4882 +
4883      case '#':
4884         while ((sym_ch != '\n') && (sym_ch != EOF))
4885             rch();
4886 @@ -1304,6 +1922,8 @@ next:
4887      }
4888  }
4889  
4890 +static void rch TAC_ARGS((void));
4891 +
4892  static void
4893  rch()
4894  {
4895 @@ -1318,201 +1938,208 @@ rch()
4896  }
4897  
4898  
4899 -/* For a user or group, find the value of a field. Does not recurse. */
4900 -VALUE
4901 -get_value(user, field)
4902 -USER *user;
4903 +static VALUE get_value TAC_ARGS((ENTITY *entity, int field));
4904 +
4905 +/* Find the value of a field. Does not recurse. */
4906 +static VALUE
4907 +get_value(entity, field)
4908 +ENTITY *entity;
4909  int field;
4910  {
4911      VALUE v;
4912  
4913 +    v.pval = NULL;     /* do both just for sure... */
4914      v.intval = 0;
4915  
4916 -    if (!user) {
4917 -       parse_error("get_value: illegal user");
4918 +    if (!entity) {
4919 +       parse_error("get_value: illegal entity");
4920         return (v);
4921      }
4922      switch (field) {
4923  
4924      case S_name:
4925 -       v.pval = user->name;
4926 +       v.pval = entity->name;
4927         break;
4928  
4929      case S_login:
4930 -       v.pval = user->login;
4931 +       v.pval = entity->login;
4932         break;
4933  
4934      case S_global:
4935 -       v.pval = user->global;
4936 -       break;
4937 -
4938 -    case S_member:
4939 -       v.pval = user->member;
4940 +       v.pval = entity->global;
4941         break;
4942  
4943      case S_expires:
4944 -       v.pval = user->expires;
4945 +       v.pval = entity->expires;
4946         break;
4947  
4948      case S_arap:
4949 -       v.pval = user->arap;
4950 +       v.pval = entity->arap;
4951         break;
4952  
4953      case S_chap:
4954 -       v.pval = user->chap;
4955 +       v.pval = entity->chap;
4956         break;
4957  
4958  #ifdef MSCHAP
4959      case S_mschap:
4960 -       v.pval = user->mschap;
4961 +       v.pval = entity->mschap;
4962         break;
4963  #endif /* MSCHAP */
4964  
4965      case S_pap:
4966 -       v.pval = user->pap;
4967 +       v.pval = entity->pap;
4968         break;
4969  
4970      case S_opap:
4971 -       v.pval = user->opap;
4972 +       v.pval = entity->opap;
4973         break;
4974  
4975      case S_message:
4976 -       v.pval = user->msg;
4977 +       v.pval = entity->msg;
4978         break;
4979  
4980      case S_svc:
4981 -       v.pval = user->svcs;
4982 +       v.pval = entity->svcs;
4983         break;
4984  
4985      case S_before:
4986 -       v.pval = user->before_author;
4987 +       v.pval = entity->before_author;
4988         break;
4989  
4990      case S_after:
4991 -       v.pval = user->after_author;
4992 +       v.pval = entity->after_author;
4993         break;
4994  
4995      case S_svc_dflt:
4996 -       v.intval = user->svc_dflt;
4997 +       v.intval = entity->svc_dflt;
4998         break;
4999  
5000  #ifdef MAXSESS
5001      case S_maxsess:
5002 -       v.intval = user->maxsess;
5003 +       v.intval = entity->maxsess;
5004         break;
5005  #endif
5006  
5007      case S_nopasswd:
5008 -       v.intval = user->nopasswd;
5009 +       v.intval = entity->nopasswd;
5010         break;
5011  
5012      case S_time:
5013 -       v.pval = user->time;
5014 +       v.pval = entity->time;
5015         break;
5016  
5017 -    default:
5018 +    case S_key:
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);
5022 +           v.pval = NULL;
5023 +           return(v);
5024 +       }
5025 +       v.pval = entity->key;
5026 +       break;
5027 +
5028 +    default:
5029         report(LOG_ERR, "get_value: unknown field %d", field);
5030         break;
5031      }
5032      return (v);
5033  }
5034  
5035 -/* For host , find value of field. Doesn't recursive */
5036 -VALUE
5037 -get_hvalue(host, field)
5038 -HOST *host;
5039 -int field;
5040 +
5041 +/* Internal graph scanning routines */
5042 +
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));
5044 +
5045 +static enum value_scan_func_result
5046 +value_scan(type, name, recurse, func, func_data)
5047 +int type;
5048 +const char *name;
5049 +int recurse;
5050 +value_scan_func_t func;
5051 +void *func_data;
5052  {
5053 -    VALUE v;
5054 -    v.intval = 0;
5055 -    if(!host) {
5056 -       parse_error("get_hvalue: illegal host");
5057 -        return (v);
5058 -    }
5059 -    switch (field) {
5060 -       case S_name:
5061 -        v.pval = host->name;
5062 -        break;
5063 +    ENTITY *entity;
5064  
5065 -       case S_key:
5066 -       v.pval = host->key;
5067 -       break;
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);
5071  
5072 -       default:
5073 -        report(LOG_ERR, "get_value: unknown field %d", field);
5074 -        break;
5075 +    entity = entity_lookup(type, name);
5076 +    if (!entity) {
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);
5081      }
5082 -    return (v);
5083 -}
5084  
5085 +    return (value_scan_entity(entity, recurse, func, func_data));
5086 +}
5087  
5088  /* For each user, check she doesn't circularly reference a
5089     group. Return 1 if it does */
5090 -static int
5091 -circularity_check()
5092 -{
5093 -    USER *user, *entry, *group;
5094 -    USER **users = (USER **) hash_get_entries(usertable);
5095 -    USER **groups = (USER **) hash_get_entries(grouptable);
5096 -    USER **p, **q;
5097  
5098 -    /* users */
5099 -    for (p = users; *p; p++) {
5100 -       user = *p;
5101 +static int circularity_check_failed;
5102  
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));
5106 +
5107 +static void
5108 +circularity_check_fail(membership)
5109 +struct membership *membership;
5110 +{
5111 +    ENTITY *entity;
5112 +
5113 +    circularity_check_failed = 1;
5114  
5115 -       /* Initialise all groups "seen" flags to zero */
5116 -       for (q = groups; *q; q++) {
5117 -           group = *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);
5125      }
5126 +}
5127  
5128 -       entry = user;
5129 +static enum value_scan_func_result circularity_check_func TAC_ARGS((ENTITY *entity, void *func_data));
5130  
5131 -       while (entry) {
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 */)
5136 +ENTITY *entity;
5137 +void *func_data;
5138 +{
5139 +    /* only useful to speedup case of failure */
5140 +    if (circularity_check_failed)
5141 +       return (VSFR_FOUND);
5142  
5143 -           if (debug & DEBUG_PARSE_FLAG)
5144 -               report(LOG_DEBUG, "\tmember of group %s",
5145 -                      groupname ? groupname : "<none>");
5146 +    return (VSFR_CONTINUE);
5147 +}
5148  
5149 +static int circularity_check TAC_ARGS((void));
5150  
5151 -           /* if not a member of any groups, go on to next user */
5152 -           if (!groupname)
5153 -               break;
5154 +static int
5155 +circularity_check()
5156 +{
5157 +    ENTITY *entity;
5158 +    ENTITY **users_base = (ENTITY **) hash_get_entries(usertable);
5159 +    ENTITY **users;
5160  
5161 -           group = (USER *) hash_lookup(grouptable, groupname);
5162 -           if (!group) {
5163 -               report(LOG_ERR, "%s=%s, group %s does not exist",
5164 -                      (entry->flags & FLAG_ISUSER) ? "user" : "group",
5165 -                      entry->name, groupname);
5166 -               free(users);
5167 -               free(groups);
5168 -               return (1);
5169 -           }
5170 -           if (group->flags & FLAG_SEEN) {
5171 -               report(LOG_ERR, "recursively defined groups");
5172 +    /* users */
5173 +    for (users = users_base; *users; users++) {
5174 +       entity = *users;
5175  
5176 -               /* print all seen "groups" */
5177 -               for (q = groups; *q; q++) {
5178 -                   group = *q;
5179 -                   if (group->flags & FLAG_SEEN)
5180 -                       report(LOG_ERR, "%s", group->name);
5181 -               }
5182 -               free(users);
5183 -               free(groups);
5184 -               return (1);
5185 -           }
5186 -           group->flags |= FLAG_SEEN;  /* mark group as seen */
5187 -           entry = group;
5188 -       }
5189 +       if (debug & DEBUG_PARSE_FLAG)
5190 +           report(LOG_DEBUG, "circularity_check: user=%s", entity->name);
5191 +
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)
5198 +           break;
5199      }
5200 -    free(users);
5201 -    free(groups);
5202 -    return (0);
5203 +    free(users_base);
5204 +    return (circularity_check_failed);
5205  }
5206  
5207  
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).
5211  */
5212 -static VALUE
5213 -cfg_get_value(name, isuser, attr, recurse)
5214 -char *name;
5215 -int isuser, attr, recurse;
5216 -{
5217 -    USER *user, *group;
5218 -    VALUE value;
5219  
5220 -    value.pval = NULL;
5221 +static VALUE cfg_get_value_VALUE;      /* private */
5222  
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);
5226 -
5227 -    /* find the user/group entry */
5228 -
5229 -    user = (USER *) hash_lookup(isuser ? usertable : grouptable, name);
5230 -
5231 -    if (!user) {
5232 -       if (debug & DEBUG_CONFIG_FLAG)
5233 -           report(LOG_DEBUG, "cfg_get_value: no user/group named %s", name);
5234 -       return (value);
5235 -    }
5236 +static enum value_scan_func_result cfg_get_value_func TAC_ARGS((ENTITY *entity, int *attrp));
5237  
5238 +static enum value_scan_func_result
5239 +cfg_get_value_func(entity,attrp /* func_data */)
5240 +ENTITY *entity;
5241 +int *attrp;
5242 +{
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);
5248  
5249 -    if (value.pval || !recurse) {
5250 -       return (value);
5251 -    }
5252 -    /* no value. Check containing group */
5253 -    if (user->member)
5254 -       group = (USER *) hash_lookup(grouptable, user->member);
5255 -    else
5256 -       group = NULL;
5257 +    return (VSFR_CONTINUE);
5258 +}
5259  
5260 -    while (group) {
5261 -       if (debug & DEBUG_CONFIG_FLAG)
5262 -           report(LOG_DEBUG, "cfg_get_value: recurse group = %s",
5263 -                  group->name);
5264 +static VALUE cfg_get_value TAC_ARGS((int type, const char *name, int attr, int recurse));
5265  
5266 -       value = get_value(group, attr);
5267 +static VALUE
5268 +cfg_get_value(type, name, attr, recurse)
5269 +int type;
5270 +const char *name;
5271 +int attr, recurse;
5272 +{
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);
5276  
5277 -       if (value.pval) {
5278 -           return (value);
5279 -       }
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);
5285 +}
5286  
5287 -       if (group->member)
5288 -           group = (USER *) hash_lookup(grouptable, group->member);
5289 -       else
5290 -           group = NULL;
5291 -    }
5292  
5293 -    /* no value for this user or her containing groups */
5294 -    value.pval = NULL;
5295 -    return (value);
5296 -}
5297 +/* Wrappers for cfg_get_value:
5298 + */
5299  
5300 +int cfg_get_intvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
5301  
5302 -/* Wrappers for cfg_get_value */
5303  int
5304 -cfg_get_intvalue(name, isuser, attr, recurse)
5305 -char *name;
5306 -int isuser, attr, recurse;
5307 +cfg_get_intvalue(type, name, attr, recurse)
5308 +int type;
5309 +const char *name;
5310 +int attr, recurse;
5311  {
5312 -    int val = cfg_get_value(name, isuser, attr, recurse).intval;
5313 +    int val = cfg_get_value(type, name, attr, recurse).intval;
5314  
5315      if (debug & DEBUG_CONFIG_FLAG)
5316         report(LOG_DEBUG, "cfg_get_intvalue: returns %d", val);
5317      return(val);
5318  }
5319  
5320 -char *
5321 -cfg_get_pvalue(name, isuser, attr, recurse)
5322 -char *name;
5323 -int isuser, attr, recurse;
5324 -{
5325 -    char *p = cfg_get_value(name, isuser, attr, recurse).pval;
5326 -
5327 -    if (debug & DEBUG_CONFIG_FLAG)
5328 -       report(LOG_DEBUG, "cfg_get_pvalue: returns %s", 
5329 -              p ? p : "NULL");
5330 -    return(p);
5331 -}
5332 -
5333 -/* For getting host values */
5334 -static VALUE
5335 -cfg_get_hvalue(name, attr)
5336 -char *name;
5337 -int attr;
5338 -{
5339 -    HOST *host;
5340 -    VALUE value;
5341 -
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));
5346 -    
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));
5349  
5350 -    host = (HOST *) hash_lookup( hosttable, name);
5351 -
5352 -    if (!host) {
5353 -        if (debug & DEBUG_CONFIG_FLAG)
5354 -            report(LOG_DEBUG, "cfg_get_hvalue: no host named %s", name);
5355 -        return (value);
5356 -    }
5357 -
5358 -    /* found the entry. Lookup value from attr=value */
5359 -    value = get_hvalue(host, attr);
5360 -
5361 -    if (value.pval) {
5362 -        return (value);
5363 -    }
5364 -    /* No any value for this host */    
5365 -    value.pval = NULL;
5366 -    return (value);
5367 -}
5368 -
5369 -/* Wrappers for cfg_get_hvalue */
5370 -char *
5371 -cfg_get_phvalue(name, attr)
5372 -char *name;
5373 -int attr;
5374 +const char *
5375 +cfg_get_pvalue(type, name, attr, recurse)
5376 +int type;
5377 +const char *name;
5378 +int attr, recurse;
5379  {
5380 -    char *p = cfg_get_hvalue(name, attr).pval;
5381 +    char *p = cfg_get_value(type, name, attr, recurse).pval;
5382  
5383      if (debug & DEBUG_CONFIG_FLAG)
5384 -       report(LOG_DEBUG, "cfg_get_phvalue: returns %s", 
5385 +       report(LOG_DEBUG, "cfg_get_pvalue: returns %s",
5386                 p ? p : "NULL");
5387      return(p);
5388  }
5389  
5390 -/*
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.
5395 + */
5396 +int cfg_read_config TAC_ARGS((const char *cfile));
5397  
5398 +int
5399  cfg_read_config(cfile)
5400 -char *cfile;
5401 +const char *cfile;
5402  {
5403      sym_line = 1;
5404  
5405 @@ -1679,7 +2244,17 @@ char *cfile;
5406         return (1);
5407      }
5408  
5409 -    if (circularity_check()) {
5410 +    if (0
5411 +     || enlist_entity_connect()
5412 +     || expr_sink_commit()
5413 +           /* circularity is allowed in the new fully-recursive algorithm */
5414 +     || (!algorithm_recursive && circularity_check())
5415 +        ) {
5416 +       fclose(cf);
5417 +       return (1);
5418 +    }
5419 +    if (!WHEN_EXPR_ROOT_EMPTY() || when_expr_dungeon) {
5420 +       report(LOG_ERR, "Some 'when' expression found still pushed on stack");
5421         fclose(cf);
5422         return (1);
5423      }
5424 @@ -1688,346 +2263,443 @@ char *cfile;
5425      return (0);
5426  }
5427  
5428 -/* return 1 if user exists, 0 otherwise */
5429 +/* return 1 if user exists, 0 otherwise
5430 + */
5431 +int cfg_user_exists TAC_ARGS((const char *username));
5432 +
5433  int
5434  cfg_user_exists(username)
5435 -char *username;
5436 +const char *username;
5437  {
5438 -    USER *user = (USER *) hash_lookup(usertable, username);
5439 -
5440 -    return (user != NULL);
5441 +    return (NULL != hash_lookup(usertable, username));
5442  }
5443  
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 */
5446 -char *
5447 -cfg_get_expires(username, recurse)
5448 -char *username;
5449 + * on, and so on, recursively if recurse is non-zero
5450 + */
5451 +const char *cfg_get_expires TAC_ARGS((const char *username, int recurse));
5452  
5453 +const char *
5454 +cfg_get_expires(username, recurse)
5455 +const char *username;
5456 +int recurse;
5457  {
5458 -    return (cfg_get_pvalue(username, TAC_IS_USER, S_expires, recurse));
5459 +    return (cfg_get_pvalue(S_user, username, S_expires, recurse));
5460  }
5461  
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 */
5464 -char *
5465 + * on, and so on, recursively if recurse is non-zero
5466 + */
5467 +const char *cfg_get_timestamp TAC_ARGS((const char *username, int recurse));
5468 +
5469 +const char *
5470  cfg_get_timestamp(username, recurse)
5471 -char *username;
5472 +const char *username;
5473 +int recurse;
5474  {
5475 -    return (cfg_get_pvalue(username, TAC_IS_USER, S_time, recurse));
5476 +    return (cfg_get_pvalue(S_user, username, S_time, recurse));
5477  }
5478  
5479 -
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 */
5482 -char *
5483 -cfg_get_login_secret(user, recurse)
5484 -char *user;
5485 + * on, and so on, recursively if recurse is non-zero
5486 + */
5487 +const char *cfg_get_login_secret TAC_ARGS((const char *user, int recurse));
5488  
5489 +const char *
5490 +cfg_get_login_secret(user, recurse)
5491 +const char *user;
5492 +int recurse;
5493  {
5494 -    return (cfg_get_pvalue(user, TAC_IS_USER, S_login, recurse));
5495 +    return (cfg_get_pvalue(S_user, user, S_login, recurse));
5496  }
5497  
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
5501 + */
5502 +int cfg_get_user_nopasswd TAC_ARGS((const char *user, int recurse));
5503 +
5504  int
5505  cfg_get_user_nopasswd(user, recurse)
5506 -    char *user;
5507 +const char *user;
5508 +int recurse;
5509  {
5510 -    return (cfg_get_intvalue(user, TAC_IS_USER, S_nopasswd, recurse));
5511 +    return (cfg_get_intvalue(S_user, user, S_nopasswd, recurse));
5512  }
5513  
5514  /* return user's secret. If none, try groups she is a member
5515 -   on, and so on, recursively if recurse is non-zero */
5516 -char *
5517 -cfg_get_arap_secret(user, recurse)
5518 -char *user;
5519 + * on, and so on, recursively if recurse is non-zero
5520 + */
5521 +const char *cfg_get_arap_secret TAC_ARGS((const char *user, int recurse));
5522  
5523 +const char *
5524 +cfg_get_arap_secret(user, recurse)
5525 +const char *user;
5526 +int recurse;
5527  {
5528 -    return (cfg_get_pvalue(user, TAC_IS_USER, S_arap, recurse));
5529 +    return (cfg_get_pvalue(S_user, user, S_arap, recurse));
5530  }
5531  
5532 -char *
5533 -cfg_get_chap_secret(user, recurse)
5534 -char *user;
5535 +const char *cfg_get_chap_secret TAC_ARGS((const char *user, int recurse));
5536  
5537 +const char *
5538 +cfg_get_chap_secret(user, recurse)
5539 +const char *user;
5540 +int recurse;
5541  {
5542 -    return (cfg_get_pvalue(user, TAC_IS_USER, S_chap, recurse));
5543 +    return (cfg_get_pvalue(S_user, user, S_chap, recurse));
5544  }
5545  
5546  #ifdef MSCHAP
5547 -char *
5548 -cfg_get_mschap_secret(user, recurse)
5549 -char *user;
5550  
5551 +const char *cfg_get_mschap_secret TAC_ARGS((const char *user, int recurse));
5552 +
5553 +const char *
5554 +cfg_get_mschap_secret(user, recurse)
5555 +const char *user;
5556 +int recurse;
5557  {
5558 -    return (cfg_get_pvalue(user, TAC_IS_USER, S_mschap, recurse));
5559 +    return (cfg_get_pvalue(S_user, user, S_mschap, recurse));
5560  }
5561 +
5562  #endif /* MSCHAP */
5563  
5564 -char *
5565 +const char *cfg_get_pap_secret TAC_ARGS((const char *user, int recurse));
5566 +
5567 +const char *
5568  cfg_get_pap_secret(user, recurse)
5569 -char *user;
5570 +const char *user;
5571 +int recurse;
5572  {
5573 -    return (cfg_get_pvalue(user, TAC_IS_USER, S_pap, recurse));
5574 +    return (cfg_get_pvalue(S_user, user, S_pap, recurse));
5575  }
5576  
5577 -char *
5578 +const char *cfg_get_opap_secret TAC_ARGS((const char *user, int recurse));
5579 +
5580 +const char *
5581  cfg_get_opap_secret(user, recurse)
5582 -char *user;
5583 +const char *user;
5584 +int recurse;
5585  {
5586 -    return (cfg_get_pvalue(user, TAC_IS_USER, S_opap, recurse));
5587 +    return (cfg_get_pvalue(S_user, user, S_opap, recurse));
5588  }
5589  
5590  /* return the global password for the user (or the group, etc.) */
5591  
5592 -char *
5593 -cfg_get_global_secret(user, recurse)
5594 -char *user;
5595 +const char *cfg_get_global_secret TAC_ARGS((const char *user, int recurse));
5596  
5597 +const char *
5598 +cfg_get_global_secret(user, recurse)
5599 +const char *user;
5600 +int recurse;
5601  {
5602 -    return (cfg_get_pvalue(user, TAC_IS_USER, S_global, recurse));
5603 +    return (cfg_get_pvalue(S_user, user, S_global, recurse));
5604  }
5605  
5606  #ifdef USE_PAM
5607 +
5608  /* Return a pointer to a node representing a PAM Service name */
5609 -char *
5610 -cfg_get_pam_service(user,recurse)
5611 -char *user;
5612  
5613 +const char *cfg_get_pam_service TAC_ARGS((const char *user, int recurse));
5614 +
5615 +const char *
5616 +cfg_get_pam_service(user, recurse)
5617 +const char *user;
5618 +int recurse;
5619  {
5620 - char *cfg_passwd;
5621 - char *p;   
5622 +    const char *cfg_passwd;
5623 +    const char *p;
5624  
5625 -cfg_passwd = cfg_get_pap_secret(user, recurse);
5626 +    cfg_passwd = cfg_get_pap_secret(user, recurse);
5627  
5628 -if (!cfg_passwd) {
5629 +    if (!cfg_passwd)
5630         cfg_passwd = cfg_get_global_secret(user, recurse);
5631 -}
5632  
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()) {
5637 +
5638         case (S_pam):
5639             if (debug & DEBUG_AUTHOR_FLAG)
5640                 report(LOG_DEBUG, "Get Default PAM Service :%s",cfg_passwd);
5641             return(cfg_passwd);
5642             break;
5643 +
5644         default:
5645             if (debug & DEBUG_AUTHOR_FLAG)
5646                 report(LOG_DEBUG, "I havent find any PAM Service!!");
5647             return(NULL);/* Haven't any PAM Service!! */
5648         }
5649 -}
5650 +    }
5651  
5652 -p=tac_find_substring("pam ", cfg_passwd);
5653 +    p = tac_find_substring("pam ", cfg_passwd);
5654  
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);
5659 -return (p);
5660 -}
5661 +       return (p);
5662 +    }
5663  
5664 -if (debug & DEBUG_AUTHOR_FLAG)
5665 +    if (debug & DEBUG_AUTHOR_FLAG)
5666         report(LOG_DEBUG, "No any PAM Sevice");
5667  
5668 -return(NULL);
5669 +    return(NULL);
5670  }
5671  
5672  #endif /* For PAM */
5673  
5674  
5675 -
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
5680     is N_svc.
5681  */
5682  
5683 -NODE *
5684 -cfg_get_svc_node(username, type, protocol, svcname, recurse)
5685 -char *username;
5686 -int type;
5687 -char *protocol, *svcname;
5688 -int recurse;
5689 -{
5690 -    USER *user, *group;
5691 -    NODE *svc;
5692 -
5693 -    if (debug & DEBUG_CONFIG_FLAG)
5694 -       report(LOG_DEBUG, 
5695 -              "cfg_get_svc_node: username=%s %s proto=%s svcname=%s rec=%d",
5696 -              username, 
5697 -              cfg_nodestring(type), 
5698 -              protocol ? protocol : "", 
5699 -              svcname ? svcname : "", 
5700 -              recurse);
5701 -
5702 -    /* find the user/group entry */
5703 -    user = (USER *) hash_lookup(usertable, username);
5704 +struct cfg_get_svc_node_param {
5705 +    int svctype;
5706 +    const char *protocol, *svcname;
5707 +    NODE *node;
5708 +    int retval;
5709 +};
5710  
5711 -    if (!user) {
5712 -       if (debug & DEBUG_CONFIG_FLAG)
5713 -           report(LOG_DEBUG, "cfg_get_svc_node: no user named %s", username);
5714 -       return (NULL);
5715 -    }
5716 +static enum value_scan_func_result cfg_get_svc_node_func TAC_ARGS((ENTITY *entity, struct cfg_get_svc_node_param *param));
5717  
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 */)
5722 +ENTITY *entity;
5723 +struct cfg_get_svc_node_param *param;
5724 +{
5725 +    NODE *svc;
5726 +    enum eval_result svc_default;
5727  
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)
5731             continue;
5732 -
5733 -       if (type == N_svc_ppp && !STREQ(svc->value1, protocol)) {
5734 +       if (param->svctype == N_svc_ppp && param->protocol && !STREQ(svc->value1, param->protocol))
5735             continue;
5736 -       }
5737 -
5738 -       if (type == N_svc && !STREQ(svc->value1, svcname)) {
5739 +       if (param->svctype == N_svc     && param->svcname  && !STREQ(svc->value1, param->svcname ))
5740 +           continue;
5741 +       if (expr_eval(svc->when) != ER_TRUE)    /* expensive */
5742             continue;
5743 -       }
5744  
5745         if (debug & DEBUG_CONFIG_FLAG)
5746             report(LOG_DEBUG,
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 : "");
5754  
5755 -       return(svc);
5756 +       param->node = svc;
5757 +       param->retval = 1;
5758 +       return (VSFR_FOUND);
5759      }
5760  
5761 -    if (!recurse) {
5762 -       if (debug & DEBUG_CONFIG_FLAG)
5763 -           report(LOG_DEBUG, "cfg_get_svc_node: returns NULL");
5764 -       return (NULL);
5765 -    }
5766 +    /* look at 'default service' settings */
5767 +    svc_default = entity_svc_default(entity);
5768 +    switch (svc_default) {
5769  
5770 -    /* no matching node. Check containing group */
5771 -    if (user->member)
5772 -       group = (USER *) hash_lookup(grouptable, user->member);
5773 -    else
5774 -       group = NULL;
5775 +    case ER_TRUE:
5776 +    case ER_FALSE:
5777 +       if (debug & DEBUG_AUTHOR_FLAG)
5778 +           report(LOG_DEBUG,
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"));
5784  
5785 -    while (group) {
5786 -       if (debug & DEBUG_CONFIG_FLAG)
5787 -           report(LOG_DEBUG, "cfg_get_svc_node: recurse group = %s",
5788 -                  group->name);
5789 +       param->retval = (svc_default == ER_TRUE);
5790 +       return (VSFR_FOUND);
5791  
5792 -       for(svc = (NODE *) get_value(group, S_svc).pval; svc; svc = svc->next) {
5793 +    default:   /* shouldn't happen */
5794 +    case ER_UNKNOWN:
5795 +       return (VSFR_CONTINUE);
5796 +    }
5797 +    /* NOTREACHED */
5798 +}
5799  
5800 -           if (svc->type != type) 
5801 -               continue;
5802 +int cfg_get_svc_node TAC_ARGS((const char *username, int svctype, const char *protocol, const char *svcname, int recurse, NODE **nodep));
5803  
5804 -           if (type == N_svc_ppp && !STREQ(svc->value1, protocol)) {
5805 -               continue;
5806 -           }
5807 +int
5808 +cfg_get_svc_node(username, svctype, protocol, svcname, recurse, nodep)
5809 +const char *username;
5810 +int svctype;
5811 +const char *protocol;
5812 +const char *svcname;
5813 +int recurse;
5814 +NODE **nodep;
5815 +{
5816 +    struct cfg_get_svc_node_param param;
5817 +    enum value_scan_func_result vsfr;
5818  
5819 -           if (type == N_svc && !STREQ(svc->value1, svcname)) {
5820 -               continue;
5821 -           }
5822 +    param.svctype = svctype;
5823 +    param.protocol = protocol;
5824 +    param.svcname = svcname;
5825 +    param.node = NULL;
5826 +    param.retval = 0;
5827  
5828      if (debug & DEBUG_CONFIG_FLAG)
5829         report(LOG_DEBUG,
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",
5833 +              username,
5834 +              cfg_nodestring(svctype),
5835                protocol ? protocol : "",
5836 -                      svcname ? svcname : "");
5837 -
5838 -           return(svc);
5839 -       }
5840 +              svcname ? svcname : "",
5841 +              recurse);
5842  
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, &param /* func_data */);
5846 +    if (nodep)
5847 +       *nodep = param.node;
5848  
5849 -       if (group->member)
5850 -           group = (USER *) hash_lookup(grouptable, group->member);
5851 -       else
5852 -           group = NULL;
5853 -    }
5854 +    if (vsfr == VSFR_FOUND)
5855 +       return (param.retval);
5856  
5857 -    if (debug & DEBUG_CONFIG_FLAG)
5858 -       report(LOG_DEBUG, "cfg_get_svc_node: returns NULL");
5859 -
5860 -    /* no matching svc node for this user or her containing groups */
5861 -    return (NULL);
5862 +    /* The service does not exist. Do the default */
5863 +    return (cfg_no_user_permitted() ? 1 : 0);
5864  }
5865  
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 */
5869 -NODE *
5870 -cfg_get_cmd_node(name, cmdname, recurse)
5871 -char *name, *cmdname;
5872 -int recurse;
5873  
5874 +struct cfg_authorize_cmd_param {
5875 +    const char *cmd;
5876 +    const char *args;
5877 +    enum eval_result result;
5878 +};
5879 +
5880 +static enum value_scan_func_result cfg_authorize_cmd_func TAC_ARGS((ENTITY *entity, struct cfg_authorize_cmd_param *param));
5881 +
5882 +static enum value_scan_func_result
5883 +cfg_authorize_cmd_func(entity, param /* func_data */)
5884 +ENTITY *entity;
5885 +struct cfg_authorize_cmd_param *param;
5886  {
5887 -    USER *user, *group;
5888      NODE *svc;
5889  
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) {
5894 +       NODE *node;
5895  
5896 -    /* find the user/group entry */
5897 -    user = (USER *) hash_lookup(usertable, name);
5898 +       if (svc->type != N_svc_cmd)
5899 +           continue;
5900 +       if (!STREQ(svc->value, param->cmd))
5901 +           continue;
5902 +       if (expr_eval(svc->when) != ER_TRUE)    /* expensive */
5903 +           continue;
5904  
5905 -    if (!user) {
5906         if (debug & DEBUG_CONFIG_FLAG)
5907 -           report(LOG_DEBUG, "cfg_get_cmd_node: no user named %s", name);
5908 -       return (NULL);
5909 +           report(LOG_DEBUG, "cfg_authorize_cmd: found cmd %s %s node",
5910 +                  param->cmd, cfg_nodestring(svc->type));
5911 +
5912 +       /* we have 'cmd <openbra>' point, now traverse through its 'permit'/'deny' pairs: */
5913 +
5914 +       for (node = svc->value1; node; node = node->next) {
5915 +           int match;
5916 +
5917 +           if (expr_eval(node->when) != ER_TRUE)               /* expensive */
5918 +               continue;
5919 +
5920 +#ifdef WITH_INCLUDED_REGEX
5921 +
5922 +           match = tac_regexec((tac_regexp *) node->value1, param->args);
5923 +
5924 +#else /* WITH_INCLUDED_REGEX */
5925 +
5926 +           match = !regexec((const regex_t *) node->value1, param->args /* string */,
5927 +                   0 /* nmatch */, NULL /* pmatch */, 0 /* eflags */);
5928 +
5929 +#endif /* WITH_INCLUDED_REGEX */
5930 +
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 "));
5936             }
5937 -    /* found the user entry. Find svc node */
5938 -    svc = (NODE *) get_value(user, S_svc).pval;
5939  
5940 -    while (svc) {
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));
5945 -           return (svc);
5946 +           if (!match)
5947 +               continue;
5948 +
5949 +           switch (node->type) {
5950 +           case N_permit:
5951 +               if (debug & DEBUG_AUTHOR_FLAG) {
5952 +                   report(LOG_DEBUG, "%s %s permitted by line %d",
5953 +                          param->cmd, param->args, node->line);
5954                 }
5955 -       svc = svc->next;
5956 +               param->result = ER_TRUE;
5957 +               return (VSFR_FOUND);
5958 +               break;
5959 +           case N_deny:
5960 +               if (debug & DEBUG_AUTHOR_FLAG) {
5961 +                   report(LOG_DEBUG, "%s %s denied by line %d",
5962 +                          param->cmd, param->args, node->line);
5963 +               }
5964 +               param->result = ER_FALSE;
5965 +               return (VSFR_FOUND);
5966 +               break;
5967 +           default:
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);
5972 +           }
5973 +       }
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)",
5977 +                       param->cmd);
5978 +           param->result = ER_FALSE;   /* emulate last "deny .*" */
5979 +           return (VSFR_FOUND);
5980         }
5981 -
5982 -    if (!recurse) {
5983 -       if (debug & DEBUG_CONFIG_FLAG)
5984 -           report(LOG_DEBUG, "cfg_get_cmd_node: returns NULL");
5985 -       return (NULL);
5986      }
5987 -    /* no matching node. Check containing group */
5988 -    if (user->member)
5989 -       group = (USER *) hash_lookup(grouptable, user->member);
5990 -    else
5991 -       group = NULL;
5992  
5993 -    while (group) {
5994 -       if (debug & DEBUG_CONFIG_FLAG)
5995 -           report(LOG_DEBUG, "cfg_get_cmd_node: recurse group = %s",
5996 -                  group->name);
5997 +    /* look at 'default service' settings */
5998 +    param->result = entity_svc_default(entity);
5999 +    switch (param->result) {
6000  
6001 -       svc = get_value(group, S_svc).pval;
6002 +    case ER_TRUE:
6003 +       if (debug & DEBUG_AUTHOR_FLAG)
6004 +           report(LOG_DEBUG, "cmd %s does not exist, permitted by default", param->cmd);
6005 +       return (VSFR_FOUND);
6006  
6007 -       while (svc) {
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));
6012 -               return (svc);
6013 -           }
6014 -           svc = svc->next;
6015 -       }
6016 +    case ER_FALSE:
6017  
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);
6022  
6023 -       if (group->member)
6024 -           group = (USER *) hash_lookup(grouptable, group->member);
6025 -       else
6026 -           group = NULL;
6027 +    default:   /* shouldn't happen */
6028 +    case ER_UNKNOWN:
6029 +       return (VSFR_CONTINUE);
6030      }
6031 +    /* NOTREACHED */
6032 +}
6033 +
6034 +enum eval_result cfg_authorize_cmd TAC_ARGS((const char *username, const char *cmd, const char *args));
6035 +
6036 +enum eval_result
6037 +cfg_authorize_cmd(username, cmd, args)
6038 +const char *username;
6039 +const char *cmd;
6040 +const char *args;
6041 +{
6042 +    struct cfg_authorize_cmd_param param;
6043 +
6044 +    param.cmd = cmd;
6045 +    param.args = args;
6046 +    param.result = ER_UNKNOWN; /* error */
6047  
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);
6052  
6053 -    /* no matching cmd node for this user or her containing groups */
6054 -    return (NULL);
6055 +    value_scan(S_user, username, TAC_PLUS_RECURSE,
6056 +               (value_scan_func_t) cfg_authorize_cmd_func, &param /* func_data */);
6057 +
6058 +    if (param.result != ER_UNKNOWN)
6059 +       return (param.result);
6060 +
6061 +    /* The command does not exist. Do the default */
6062 +    return (cfg_no_user_permitted() ? ER_TRUE : ER_FALSE);
6063  }
6064  
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
6068   * denyp */
6069  
6070 +char **cfg_get_svc_attrs TAC_ARGS((NODE *svcnode, int *denyp));
6071 +
6072  char **
6073  cfg_get_svc_attrs(svcnode, denyp)
6074  NODE *svcnode;
6075 @@ -2063,9 +2737,14 @@ int *denyp;
6076  
6077      i = 0;
6078      for (node = svcnode->value; node; node = node->next) {
6079 -       char *arg = tac_strdup(node->value);
6080 -       char *p = index(arg, '=');
6081 +       char *arg;
6082 +       char *p;
6083  
6084 +       if (expr_eval(node->when) != ER_TRUE)   /* expensive */
6085 +           continue;   /* ignore this node */
6086 +
6087 +       arg = tac_strdup(node->value);
6088 +       p = index(arg, '=');
6089         if (p && node->type == N_optarg)
6090             *p = '*';
6091         args[i++] = arg;
6092 @@ -2075,23 +2754,28 @@ int *denyp;
6093  }
6094  
6095  
6096 -int
6097 -cfg_user_svc_default_is_permit(user)
6098 -char *user;
6099 +static enum eval_result entity_svc_default TAC_ARGS((ENTITY *entity));
6100  
6101 +static enum eval_result
6102 +entity_svc_default(entity)
6103 +ENTITY *entity;
6104  {
6105 -    int permit = cfg_get_intvalue(user, TAC_IS_USER, S_svc_dflt,
6106 -                              TAC_PLUS_RECURSE);
6107 -
6108 -    switch (permit) {
6109 -    default:                   /* default is deny */
6110 -    case S_deny:
6111 -       return (0);
6112 +    switch (entity->svc_dflt) {
6113      case S_permit:
6114 -       return (1);
6115 +       return (ER_TRUE);
6116 +    case S_deny:
6117 +       return (ER_FALSE);
6118 +    case S_default:
6119 +    case 0:    /* not specified */
6120 +       return (ER_UNKNOWN);
6121 +    default:
6122 +       report(LOG_ERR, "INTERNAL: invalid entity svc_dflt (%d)", entity->svc_dflt);
6123 +       return (ER_UNKNOWN);
6124      }
6125  }
6126  
6127 +int cfg_no_user_permitted TAC_ARGS((void));
6128 +
6129  int
6130  cfg_no_user_permitted()
6131  {
6132 @@ -2101,12 +2785,16 @@ cfg_no_user_permitted()
6133  }
6134  
6135  
6136 -char *
6137 +const char *cfg_get_authen_default TAC_ARGS((void));
6138 +
6139 +const char *
6140  cfg_get_authen_default()
6141  {
6142      return (authen_default);
6143  }
6144  
6145 +int cfg_get_authen_default_method TAC_ARGS((void));
6146 +
6147  /* For describe authentication method(pam,file,db..etc) */
6148  int
6149  cfg_get_authen_default_method()
6150 @@ -2115,92 +2803,123 @@ cfg_get_authen_default_method()
6151  }
6152  
6153  
6154 -/* Return 1 if this user has any ppp services configured. Used for
6155 -   authorizing ppp/lcp requests */
6156 -int
6157 -cfg_ppp_is_configured(username, recurse)
6158 -    char *username;
6159 -    int recurse;
6160 +/* Host entity management:
6161 + */
6162 +
6163 +const char *cfg_get_host_key TAC_ARGS((const char *host));
6164 +
6165 +/* For getting host key */
6166 +const char *
6167 +cfg_get_host_key(host)
6168 +const char *host;
6169  {
6170 -    USER *user, *group;
6171 -    NODE *svc;
6172 +    return (cfg_get_pvalue(S_host, host, S_key, algorithm_recursive /* recurse */));
6173 +}
6174  
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));
6179 +
6180 +static ENTITY *
6181 +force_belong_entity(type, name)
6182 +int type;
6183 +const char *name;
6184 +{
6185 +    ENTITY *entity = entity_lookup(type, name);
6186  
6187 -    /* find the user/group entry */
6188 -    user = (USER *) hash_lookup(usertable, username);
6189 +    if (entity)
6190 +       eval_force_belong_entity(entity);
6191  
6192 -    if (!user) {
6193 -       if (debug & DEBUG_CONFIG_FLAG)
6194 -           report(LOG_DEBUG, "cfg_ppp_is_configured: no user named %s", 
6195 -                  username);
6196 -       return (0);
6197 -    }
6198 +    return (entity);
6199 +}
6200  
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*" */
6204  
6205 -       if (svc->type != N_svc_ppp) 
6206 -           continue;
6207 +static ENTITY *request_peer_addr;
6208 +static ENTITY *request_peer;
6209 +static ENTITY *request_DEFAULT_group;
6210  
6211 -       if (debug & DEBUG_CONFIG_FLAG)
6212 -           report(LOG_DEBUG, "cfg_ppp_is_configured: found svc ppp %s node",
6213 -                  svc->value1);
6214 +static void enlist_request_peer TAC_ARGS((const char *hostname, ENTITY **entityp));
6215  
6216 -       return(1);
6217 -    }
6218 +static void
6219 +enlist_request_peer(hostname, entityp)
6220 +const char *hostname;
6221 +ENTITY **entityp;
6222 +{
6223 +    *entityp = NULL;
6224 +    if (!hostname)
6225 +       return;
6226  
6227 -    if (!recurse) {
6228 -       if (debug & DEBUG_CONFIG_FLAG)
6229 -           report(LOG_DEBUG, "cfg_ppp_is_configured: returns 0");
6230 -       return (0);
6231 -    }
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 */);
6235 +}
6236  
6237 -    /* no matching node. Check containing group */
6238 -    if (user->member)
6239 -       group = (USER *) hash_lookup(grouptable, user->member);
6240 -    else
6241 -       group = NULL;
6242 +/* Try to build the following scenery:
6243 + * 
6244 + * host <session.peer_addr> [=ER_TRUE]
6245 + *  |
6246 + *  +-- group <DEFAULT_GROUPNAME>
6247 + *
6248 + * host <session.peer     > [=ER_TRUE]
6249 + *  |
6250 + *  +-- group <DEFAULT_GROUPNAME>
6251 + */
6252  
6253 -    while (group) {
6254 -       if (debug & DEBUG_CONFIG_FLAG)
6255 -           report(LOG_DEBUG, "cfg_ppp_is_configured: recurse group = %s",
6256 -                  group->name);
6257 +void cfg_request_scan_begin TAC_ARGS((void));
6258  
6259 -       for(svc = (NODE *) get_value(group, S_svc).pval; svc; svc = svc->next) {
6260 +void
6261 +cfg_request_scan_begin()
6262 +{
6263 +    request_scan_begin();
6264  
6265 -           if (svc->type != N_svc_ppp)
6266 -               continue;
6267 +    request_DEFAULT_group = entity_lookup(S_group, DEFAULT_GROUPNAME);
6268  
6269 -           if (debug & DEBUG_CONFIG_FLAG)
6270 -               report(LOG_DEBUG, "cfg_ppp_is_configured: found svc ppp %s node",
6271 -                      svc->value1);
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);
6275 +}
6276  
6277 -           return(1);
6278 -       }
6279 +/* Try to build the following scenery:
6280 + *
6281 + * ( user <identity->username> |  user <DEFAULT_USERNAME> ) [=ER_TRUE]
6282 + *  |
6283 + *  +-- host <session.peer_addr> [=ER_TRUE]
6284 + *  |    |
6285 + *  |    +- group <DEFAULT_GROUPNAME>
6286 + *  |
6287 + *  +-- host <session.peer     > [=ER_TRUE]
6288 + *  |    |
6289 + *  |    +-- group <DEFAULT_GROUPNAME>
6290 + *  |
6291 + *  +-- group <DEFAULT_GROUPNAME>
6292 + */
6293  
6294 -       /* still nothing. Check containing group and so on */
6295 +void cfg_request_identity TAC_ARGS((const struct identity *identity));
6296  
6297 -       if (group->member)
6298 -           group = (USER *) hash_lookup(grouptable, group->member);
6299 -       else
6300 -           group = NULL;
6301 -    }
6302 +void
6303 +cfg_request_identity(identity)
6304 +const struct identity *identity;
6305 +{
6306 +    ENTITY *user_entity,*request_DEFAULT_group;
6307  
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);
6312  
6313 -    /* no PPP svc nodes for this user or her containing groups */
6314 -    return (0);
6315 -}
6316 +    user_entity = force_belong_entity(S_user, identity->username);
6317 +    request_DEFAULT_group = entity_lookup(S_group, DEFAULT_GROUPNAME);
6318  
6319 -/* For getting host key */
6320 -char *
6321 -cfg_get_host_key(host)
6322 -char *host;
6323 -{
6324 -    return (cfg_get_phvalue(host, S_key));
6325 -}
6326 +    if (!user_entity)
6327 +       user_entity = force_belong_entity(S_user, DEFAULT_USERNAME);
6328 +
6329 +    request_scan_user_known = 1;
6330  
6331 +    if (!user_entity)
6332 +       return;
6333 +
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 */);
6340 +}
6341 diff --git a/cfgfile.h b/cfgfile.h
6342 new file mode 100644
6343 index 0000000..3669996
6344 --- /dev/null
6345 +++ b/cfgfile.h
6346 @@ -0,0 +1,164 @@
6347 +#ifndef CFGFILE_H
6348 +#define CFGFILE_H 1
6349 +
6350 +#include "tac_plus.h"
6351 +
6352 +#include "utils.h"
6353 +#include "cfgeval.h"
6354 +
6355 +
6356 +/* Configurable:
6357 + */
6358 +
6359 +#define DEFAULT_USERNAME       "DEFAULT"
6360 +#define DEFAULT_GROUPNAME      "DEFAULT"
6361 +
6362 +
6363 +#define TAC_PLUS_RECURSE      1
6364 +#define TAC_PLUS_NORECURSE    0
6365 +
6366 +/* Node types */
6367 +
6368 +#define N_arg           50
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
6376 +#define N_deny          58
6377 +#define N_svc           59
6378 +
6379 +typedef struct node NODE;
6380 +
6381 +/* A parse tree node */
6382 +struct 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 */
6390 +};
6391 +
6392 +union v {
6393 +    int intval;
6394 +    void *pval;
6395 +};
6396 +
6397 +typedef union v VALUE;
6398 +
6399 +/* A user, host or group definition
6400 +
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
6403 +   peril
6404 +*/
6405 +
6406 +struct entity {
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 */
6411 +
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 */
6421 +#ifdef MSCHAP
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
6429 +                                * cmd */
6430 +                               /* =S_permit, S_deny or S_default */
6431 +    NODE *svcs;                        /* pointer to svc nodes */
6432 +#ifdef MAXSESS
6433 +    int maxsess;               /* Max sessions/user */
6434 +#endif /* MAXSESS */
6435 +    char *time;                        /* Timestamp  */
6436 +
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 */
6440 +
6441 +    struct {
6442 +       unsigned seq;                           /* corresponds to global request_scan_seq */
6443 +       enum eval_result belongs;               /* whether this ENTITY 'belongs' */
6444 +    } request_scan;            /*   cfg_request() scanning */
6445 +
6446 +    struct {
6447 +       unsigned seq;                           /* corresponds to global value_scan_seq */
6448 +       unsigned seen:1;
6449 +       struct membership *from;                /* from which we got to this one or NULL */
6450 +    } value_scan;              /* cfg_get_value() scanning, many per request_scan */
6451 +
6452 +    struct {
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().
6461 +                        */
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 */
6465 +};
6466 +#define PENDING_ENTITY_NODE_TO_ENTITY(pending_entity_node_) \
6467 +       (&TAC_MEMBER_STRUCT(ENTITY, (pending_entity_node_), eval_scan.pending_entity_node))
6468 +
6469 +
6470 +struct identity;
6471 +
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));
6484 +#ifdef MSCHAP
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));
6490 +#ifdef USE_PAM
6491 +extern const char *cfg_get_pam_service TAC_ARGS((const char *user, int recurse));
6492 +#endif /* PAM */
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));
6502 +
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));
6508 +
6509 +
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
6515 @@ -17,24 +17,47 @@
6516     FITNESS FOR A PARTICULAR PURPOSE.
6517  */
6518  
6519 +
6520  #include "tac_plus.h"
6521 +
6522 +#include "choose_authen.h"
6523  #include "expire.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"
6532 +#include "main.h"
6533 +#include "do_author.h"                 /* for "struct identity" */
6534  
6535 -static int choose_login();
6536 -static int choose_sendpass();
6537 -static int choose_sendauth();
6538 +#ifdef SKEY
6539 +#include "skey_fn.h"
6540 +#endif
6541  
6542 -int 
6543 +
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));
6547 +
6548 +
6549 +#if 0 /* unused */
6550 +static int
6551  get_minor_version()
6552  {
6553      return(session.version & ~TAC_PLUS_MAJOR_VER_MASK);
6554  }
6555 +#endif /* unused */
6556  
6557  /*
6558   * Choose an authentication function. Return CHOOSE_OK if chosen,
6559   * CHOOSE_GETUSER if we need a username, CHOOSE_FAILED on failure
6560   */
6561  
6562 +int choose_authen TAC_ARGS((struct authen_data *data, struct authen_type *type));
6563 +
6564  int
6565  choose_authen(data, type)
6566  struct authen_data *data;
6567 @@ -84,14 +107,16 @@ struct authen_type *type;
6568      return(CHOOSE_FAILED);
6569  }
6570  
6571 +static int choose_login TAC_ARGS((struct authen_data *data, struct authen_type *type));
6572 +
6573  /* Choose an authentication function for action == LOGIN, service != enable */
6574  static int
6575  choose_login(data, type)
6576  struct authen_data *data;
6577  struct authen_type *type;
6578  {
6579 -    char *name = data->NAS_id->username;
6580 -    char *cfg_passwd;
6581 +    const char *name = data->NAS_id->username;
6582 +    const char *cfg_passwd;
6583  
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);
6588  }
6589  
6590 +static int choose_sendauth TAC_ARGS((struct authen_data *data, struct authen_type *type));
6591 +
6592  static int
6593  choose_sendauth(data, type)
6594  struct authen_data *data;
6595 @@ -247,6 +274,8 @@ struct authen_type *type;
6596      return(CHOOSE_FAILED);
6597  }
6598  
6599 +static int choose_sendpass TAC_ARGS((struct authen_data *data, struct authen_type *type));
6600 +
6601  /* Compatibility routine for (obsolete) minor version == 0 */
6602  static int
6603  choose_sendpass(data, type)
6604 @@ -291,4 +320,3 @@ struct authen_type *type;
6605  
6606      return(CHOOSE_FAILED);
6607  }
6608 -
6609 diff --git a/choose_authen.h b/choose_authen.h
6610 new file mode 100644
6611 index 0000000..1276494
6612 --- /dev/null
6613 +++ b/choose_authen.h
6614 @@ -0,0 +1,63 @@
6615 +#ifndef CHOOSE_AUTHEN_H
6616 +#define CHOOSE_AUTHEN_H 1
6617 +
6618 +#include "tac_plus.h"
6619 +
6620 +#include <sys/types.h>         /* for u_* */
6621 +
6622 +
6623 +/*
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
6628 + */
6629 +
6630 +#define AUTHEN_NAME_SIZE 128
6631 +
6632 +struct authen_data;
6633 +
6634 +struct authen_type {
6635 +    char authen_name[AUTHEN_NAME_SIZE];
6636 +    int (*authen_func) TAC_ARGS((struct authen_data *data));
6637 +    int authen_type;
6638 +};
6639 +
6640 +/*
6641 + * The authen_data structure is the data structure for passing
6642 + * information to and from the authentication function
6643 + * (authen_type.authen_func).
6644 + */
6645 +
6646 +struct authen_data {
6647 +    struct identity *NAS_id;   /* user identity */
6648 +    char *server_msg;          /* null-terminated output msg */
6649 +
6650 +    int server_dlen;           /* output data length */
6651 +    unsigned char *server_data;        /* output data */
6652 +
6653 +    char *client_msg;          /* null-terminated input msg a user typed */
6654 +
6655 +    int client_dlen;           /* input data length */
6656 +    char *client_data;         /* input data */
6657 +
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 */
6664 +};
6665 +
6666 +/* return values for  choose_authen(); */
6667 +
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 */
6672 +
6673 +
6674 +extern int choose_authen TAC_ARGS((struct authen_data *data, struct authen_type *type));
6675 +
6676 +
6677 +#endif /* CHOOSE_AUTHEN_H */
6678 diff --git a/configure.in b/configure.in
6679 index 6b3eb13..0b8fd72 100644
6680 --- a/configure.in
6681 +++ b/configure.in
6682 @@ -1,53 +1,101 @@
6683  dnl This file writen by Devrim SERAL for tac_plus daemon
6684  
6685  AC_INIT()
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)
6690  
6691  dnl Checks for programs.
6692  AC_PROG_MAKE_SET
6693  AC_PROG_CC
6694  
6695 -dnl Check for Host information
6696 -dnl AC_CANONICAL_HOST()
6697 -AC_CANONICAL_SYSTEM()
6698 -
6699  case $host_os in
6700         *linux-gnu)
6701 -       OS="-DLINUX -DGLIBC"
6702 +               AC_DEFINE(LINUX)
6703 +               AC_DEFINE(GLIBC)
6704                 ;;
6705         *solaris)
6706 -       OS="-DSOLARIS"
6707 +               AC_DEFINE(SOLARIS)
6708                 ;;
6709         *freebsd)
6710 -       OS="-DFREEBSD"
6711 +               AC_DEFINE(FREEBSD)
6712                 ;;
6713         *hpux)
6714 -       OS="-DHPUX"
6715 +               AC_DEFINE(HPUX)
6716                 ;;
6717         *aix)
6718 -       OS="-DAIX"
6719 +               AC_DEFINE(AIX)
6720 +               AC_MSG_WARN([See /usr/lpp/bos/bsdport on your system for details of how to define bsdcc])
6721 +               # CC="bsdcc"
6722 +               ;;
6723 +       *mips)
6724 +               AC_DEFINE(MIPS)
6725                 ;;
6726         *)
6727                 ;;
6728  esac
6729  
6730 +dnl Devrim Added
6731 +AM_CONFIG_HEADER(config.h)
6732 +AM_MAINTAINER_MODE
6733 +
6734 +if test "x$USE_MAINTAINER_MODE" = "xyes"; then
6735 +       AC_DEFINE(MAINTAINER_MODE)
6736 +fi
6737 +
6738 +if test "x$USE_MAINTAINER_MODE" = "xyes" -a "x$GCC" = "xyes"; then
6739 +       CFLAGS="$CFLAGS -ggdb3 -Wall -Wstrict-prototypes -pedantic -Wsign-compare"
6740 +fi
6741 +
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"
6745 +
6746 +COND_USE=""
6747 +AC_SUBST(COND_USE)
6748 +conf_LDFLAGS=""
6749 +AC_SUBST(conf_LDFLAGS)
6750 +conf_LDADD=""
6751 +AC_SUBST(conf_LDADD)
6752 +
6753 +
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)
6772  
6773 +dnl Checks for header files.
6774 +AC_HEADER_STDC
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)
6779 +               fi
6780 +               ],)
6781 +dnl Checks for typedefs, structures, and compiler characteristics.
6782 +AC_C_CONST
6783 +AC_HEADER_TIME
6784 +
6785 +dnl Checks for library functions.
6786 +AC_PROG_GCC_TRADITIONAL
6787 +AC_FUNC_SETPGRP
6788 +AC_TYPE_SIGNAL
6789 +AC_FUNC_VPRINTF
6790 +AC_FUNC_WAIT3
6791 +AC_TYPE_SIZE_T
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)
6796  
6797 -dnl Devrim Added 
6798 -AC_CONFIG_HEADER(config.h)
6799  
6800  dnl For PAM support
6801  AC_MSG_CHECKING(for PAM support:)
6802 @@ -55,9 +103,10 @@ echo
6803  AC_ARG_WITH(pam,
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)
6814  else
6815          AC_MSG_RESULT(Pam support... no)
6816 @@ -70,10 +119,15 @@ AC_ARG_WITH(ldap,
6817          [  --with-ldap         With LDAP Support   ],,)
6818  
6819  if test "x$with_ldap" = "xyes";then
6820 -   AC_CHECK_LIB(ldap, ldap_simple_bind_s)
6821 -   AC_CHECK_LIB(ldap, ldap_init)
6822
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" ],
6828 +               [
6829 +       AC_CHECK_LIB(ldap, ldap_init,          [ conf_LDADD="-lldap   $conf_LDADD" ],, $liblber)
6830 +               ], $liblber )
6831 +       AC_DEFINE(USE_LDAP)
6832 +       COND_USE="$COND_USE "'$(cond_USE_LDAP)'
6833         AC_MSG_RESULT(LDAP support... yes)
6834  else
6835         AC_MSG_RESULT(LDAP support... no)
6836 @@ -85,7 +139,10 @@ echo
6837  AC_ARG_WITH(db,
6838          [  --with-db           For DB Support   ],,)
6839  if test "x$with_db" = "xyes";then
6840 -       DB="$DB -DDB -DDB_NULL" 
6841 +       AC_DEFINE(DB)
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)
6846  else
6847         AC_MSG_RESULT(DB support... no)
6848 @@ -108,14 +165,15 @@ AC_ARG_WITH(mysql-prefix,
6849  
6850  if test "x$with_mysql" = "xyes";then
6851  
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),
6860                          -lm)
6861  
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)
6866  else
6867          AC_MSG_RESULT(Mysql support... no)
6868 @@ -140,13 +198,14 @@ AC_ARG_WITH(pgsql-prefix,
6869  
6870  if test "x$with_pgsql" = "xyes";then
6871  
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))
6880  
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)
6885  else
6886          AC_MSG_RESULT(Pgsql support... no)
6887 @@ -164,7 +223,8 @@ AC_ARG_WITH(tacgid,
6888  
6889  if (test "x$with_tacuid" != "x" && test "x$with_tacgid" != "x" && test "x$with_tacuid" != "xyes" && test "x$with_tacgid" != "xyes");then
6890  
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)
6895  fi
6896  
6897 @@ -173,8 +233,9 @@ AC_ARG_ENABLE(maxsess,
6898                [  --enable-maxsess      Enable maxsess feature ],
6899  [
6900  if test "$enableval" = "yes";then
6901 -       DEFINES="-DMAXSESS $DEFINES";
6902 +       AC_DEFINE(MAXSESS)
6903         AC_MSG_RESULT(yes)
6904 +       COND_USE="$COND_USE "'$(cond_MAXSESS)'
6905  else
6906         AC_MSG_RESULT(no)
6907  fi
6908 @@ -184,16 +245,18 @@ fi
6909  ])
6910  
6911  dnl Enable tacacs.pid file directory
6912 -
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" ],
6918 +       [ pidfile="" ]
6919  )
6920 +if test "x$pidfile" '!=' "x"; then
6921 +       AC_DEFINE_UNQUOTED(TACPLUS_PIDFILE, "$pidfile/tac_plus.pid")
6922 +fi
6923  
6924  dnl For libwrap check
6925 -AC_MSG_CHECKING(whether to enable the libwrap feture)
6926 -
6927 +AC_MSG_CHECKING(whether to enable the libwrap feature)
6928 +cond=false
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,
6933    yes)
6934      AC_MSG_RESULT(yes)
6935      AC_CHECK_LIB(wrap, request_init, [
6936 -        LIBS="-lwrap $LIBS"
6937 -        DEFINES="-DTCPWRAPPER $DEFINES"])
6938 +        conf_LDADD="-lwrap $conf_LDADD"
6939 +       cond=true
6940 +       ])
6941      ;;
6942    *)
6943      AC_MSG_RESULT(yes)
6944      if test -d "$withval"; then
6945          LDFLAGS="-L$withval $LDFLAGS"
6946 -       DEFINES="-DTCPWRAPPER $DEFINES"
6947      fi
6948      AC_TRY_LINK([ int allow_severity; int deny_severity; ],
6949                  [ hosts_access(); ],
6950                  [],
6951                  [ AC_MSG_ERROR(Could not find the $withval library.  You must first install tcp_wrappers.) ])
6952 +    cond=true
6953      ;;
6954    esac ],
6955    AC_MSG_RESULT(no)
6956  )
6957 +if $cond; then
6958 +       AC_DEFINE(TCPWRAPPER)
6959 +       COND_USE="$COND_USE "'$(cond_TCPWRAPPER)'
6960 +fi
6961  
6962 -dnl insert defines to Makefile 
6963 -AC_SUBST(DEFINES)
6964 -AC_SUBST(PIDFILE)
6965 -AC_SUBST(DB)
6966 -AC_SUBST(OS)
6967 +dnl For SKEY check
6968 +AC_MSG_CHECKING(whether to use SKEY security feature)
6969 +cond=false
6970 +AC_ARG_WITH(skey,
6971 +[  --with-skey[=LIBPATH]   Compile with SKEY support (also use -I in CPPFLAGS var).],
6972 +[ case "$withval" in
6973 +  no)
6974 +    AC_MSG_RESULT(no)
6975 +    ;;
6976 +  yes)
6977 +    AC_MSG_RESULT(yes)
6978 +    cond=true
6979 +    ;;
6980 +  *)
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.])
6984 +    fi
6985 +    conf_LDADD="$withval $conf_LDADD"
6986 +    cond=true
6987 +    ;;
6988 +  esac ],
6989 +  AC_MSG_RESULT(no)
6990 +)
6991 +if $cond; then
6992 +       AC_DEFINE(SKEY)
6993 +       COND_USE="$COND_USE "'$(cond_SKEY)'
6994 +fi
6995  
6996 -dnl Checks for header files.
6997 -AC_HEADER_STDC
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)
7004 +cond=false
7005 +AC_ARG_WITH(mschap,
7006 +[  --with-mschap[=des]     Compile with Microsoft CHAP (optionally including MSCHAP_DES).],
7007 +[ case "$withval" in
7008 +  no)
7009 +    AC_MSG_RESULT(no)
7010 +    ;;
7011 +  yes)
7012 +    AC_MSG_RESULT([yes, without DES])
7013 +    cond=true
7014 +    ;;
7015 +  des)
7016 +    AC_MSG_RESULT([yes, including DES])
7017 +    AC_DEFINE(MSCHAP_DES)
7018 +    cond=true
7019 +    ;;
7020 +  *)
7021 +    AC_MSG_ERROR(Unknown --with-mschap argument $withval, use: no, yes or des)
7022 +    ;;
7023 +  esac ],
7024 +  AC_MSG_RESULT(no)
7025 +)
7026 +if $cond; then
7027 +       AC_DEFINE(MSCHAP)
7028 +       COND_USE="$COND_USE "'$(cond_MSCHAP)'
7029 +fi
7030 +
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)
7034 +cond=false
7035 +AC_ARG_WITH(descrypt,
7036 +[  --with-descrypt         Be password encryption compatible with SunOS.],
7037 +[ case "$withval" in
7038 +  no)
7039 +    AC_MSG_RESULT(no)
7040 +    ;;
7041 +  yes)
7042 +    AC_MSG_RESULT(yes)
7043 +    LIBS="-ldescrypt $LIBS"
7044 +    ;;
7045 +  *)
7046 +    AC_MSG_RESULT(yes - $withval)
7047 +    LIBS="$withval $LIBS"
7048 +    ;;
7049 +  esac ],
7050 +  AC_MSG_RESULT(no)
7051 +)
7052 +
7053 +AC_ARG_WITH(efence,
7054 +[  --with-efence           compile with efence support (for debugging)],,[
7055 +       if test "x$USE_MAINTAINER_MODE" = "xyes"; then
7056 +               with_efence=auto
7057 +       else
7058 +               with_efence=no
7059         fi
7060 -               ],)
7061 -dnl Checks for typedefs, structures, and compiler characteristics.
7062 -AC_C_CONST
7063 -AC_HEADER_TIME
7064 +])
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.)
7069 +               fi
7070 +               ])
7071 +fi
7072  
7073 -dnl Checks for library functions.
7074 -AC_PROG_GCC_TRADITIONAL
7075 -AC_FUNC_SETPGRP
7076 -AC_TYPE_SIGNAL
7077 -AC_FUNC_VPRINTF
7078 -AC_FUNC_WAIT3
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, [
7083 +       check_ok=false
7084 +       for type in socklen_t size_t int; do
7085 +               AC_TRY_COMPILE([
7086 +#include <sys/types.h>
7087 +#include <sys/socket.h>
7088 +#if STDC_HEADERS
7089 +#include <stdlib.h>
7090 +#include <stddef.h>
7091 +#endif
7092 +],[
7093 +                       return 0;}
7094 +                       int accept(int s, struct sockaddr *addr, ]$type[ *addrlen)
7095 +                       { return 0; }
7096 +                       int discarded_main() {
7097 +],
7098 +                       [check_ok=true;break],continue)
7099 +       done
7100 +       if $check_ok
7101 +       then
7102 +               tac_plus_cv_accept_type=$type
7103 +       else
7104 +               tac_plus_cv_accept_type=no
7105 +       fi
7106 +       ])
7107 +if test "x$tac_plus_cv_accept_type" = "xno"
7108 +then
7109 +       AC_DEFINE(socklen_t,int)
7110 +       AC_MSG_RESULT([failed to detect, will try int])
7111 +else
7112 +       AC_MSG_RESULT($tac_plus_cv_accept_type)
7113 +       if test "x$tac_plus_cv_accept_type" != "xsocklen_t"
7114 +       then
7115 +               AC_DEFINE_UNQUOTED(socklen_t,$tac_plus_cv_accept_type)
7116 +       fi
7117 +fi
7118 +
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)])
7123 +
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],
7127 +       AC_TRY_RUN([
7128 +#ifdef HAVE_UNISTD_H
7129 +#include <unistd.h>
7130 +#endif
7131 +#ifdef HAVE_REGEX_H
7132 +#include <regex.h>
7133 +#endif
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
7139 +       fi
7140 +fi
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)'
7144 +fi
7145 +
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))
7152 +
7153 +if test "$tac_plus_cv_struct_passwd_pw_age" = "yes"; then
7154 +       AC_DEFINE(HAVE_PASSWD_PW_AGE)
7155 +fi
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))
7160 +
7161 +if test "$tac_plus_cv_struct_passwd_pw_comment" = "yes"; then
7162 +       AC_DEFINE(HAVE_PASSWD_PW_COMMENT)
7163 +fi
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))
7168 +
7169 +if test "$tac_plus_cv_struct_utmp_ut_host" = "yes"; then
7170 +       AC_DEFINE(HAVE_UTMP_UT_HOST)
7171 +fi
7172 +
7173 +CFLAGS="$final_CFLAGS"
7174  
7175 -AC_OUTPUT(Makefile,echo timestamp > stamp-h)
7176 +AC_OUTPUT([
7177 +       Makefile
7178 +       tac_plus.spec
7179 +       ])
7180 diff --git a/convert.pl b/convert.pl
7181 index eb0b5c2..83cbdcc 100755
7182 --- a/convert.pl
7183 +++ b/convert.pl
7184 @@ -141,6 +141,3 @@ exit 0 if ($acl_valid);
7185  foreach $group (keys %groups) {
7186      print "group = $group { }\n";
7187  }
7188 -
7189 -
7190 -
7191 diff --git a/db.c b/db.c
7192 index 9cbbbe1..b5c156c 100644
7193 --- a/db.c
7194 +++ b/db.c
7195 @@ -44,18 +44,47 @@
7196     devrim(devrim@gazi.edu.tr)
7197  */
7198  
7199 -#if defined(DB)
7200 -#include <stdio.h>
7201 +
7202  #include "tac_plus.h"
7203 +
7204 +#ifdef DB
7205 +
7206 +#include <stdio.h>
7207 +#include <stdlib.h>
7208 +#include <string.h>
7209 +
7210 +#include "db.h"
7211 +#include "report.h"
7212 +#include "do_acct.h"
7213 +#include "main.h"
7214 +#include "do_author.h"                 /* for "struct identity" */
7215 +#include "utils.h"
7216 +
7217 +
7218 +#ifdef DB_MYSQL
7219 +#include "db_mysql.h"
7220 +#endif
7221 +#ifdef DB_NULL
7222 +#include "db_null.h"
7223 +#endif
7224 +#ifdef DB_PGSQL
7225 +#include "db_pgsql.h"
7226 +#endif
7227 +
7228 +
7229 +static int check_db_type TAC_ARGS((char *db_type));
7230 +
7231 +
7232  /* The databases  recognized by this function */
7233  #define DEFINED_DB {"null","mysql","pgsql"}
7234  
7235 -char *find_attr_value(); 
7236 +int db_verify TAC_ARGS((const char *user, const char *users_passwd, const char *str_conn));
7237  
7238  int
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 */
7245  {
7246      char *buffer;
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);
7251  
7252 -    buffer = db_pref = (char *)malloc( strlen(str_conn) + 1 );
7253 -    if( buffer == NULL ){
7254 -       report(LOG_DEBUG, "Error allocation memory");
7255 -        return(0);
7256 -    }
7257 +    buffer = db_pref = (char *) tac_malloc( strlen(str_conn) + 1 );
7258  
7259      strcpy( buffer, str_conn );
7260  
7261 @@ -216,6 +241,8 @@ char *str_conn;                 /* String connection to database */
7262  }
7263  
7264  
7265 +int db_acct TAC_ARGS((struct acct_rec *rec));
7266 +
7267  /* Db accounting routine */
7268  int
7269  db_acct(rec)
7270 @@ -227,12 +254,7 @@ struct acct_rec *rec;
7271      char *a_username,*s_name,*c_name,*elapsed_time,*bytes_in,*bytes_out;
7272      int ret;
7273  
7274 -    buffer = db_pref = (char *)malloc( strlen(session.db_acct) + 1 );
7275 -       
7276 -    if( buffer == NULL ){
7277 -       report(LOG_DEBUG, "Error allocation memory");
7278 -        return(0);
7279 -    }
7280 +    buffer = db_pref = (char *) tac_malloc( strlen(session.db_acct) + 1 );
7281  
7282      strcpy( buffer, session.db_acct);
7283  
7284 @@ -384,8 +406,10 @@ struct acct_rec *rec;
7285  
7286  }
7287  
7288 +static int check_db_type TAC_ARGS((char *db_type));
7289 +
7290  /* For checking DB type */
7291 -int 
7292 +static int
7293  check_db_type(db_type)
7294  char *db_type;
7295  {
7296 @@ -400,4 +424,9 @@ for (i=0; dbp[i] ; i++ ) {
7297  }
7298  return ret;
7299  }
7300 +
7301 +#else /* DB */
7302 +
7303 +TAC_SOURCEFILE_EMPTY
7304 +
7305  #endif /* DB */
7306 diff --git a/db.h b/db.h
7307 new file mode 100644
7308 index 0000000..dfc0c23
7309 --- /dev/null
7310 +++ b/db.h
7311 @@ -0,0 +1,17 @@
7312 +#ifndef DB_H
7313 +#define DB_H 1
7314 +
7315 +#include "tac_plus.h"
7316 +
7317 +#ifdef DB
7318 +
7319 +
7320 +struct acct_rec;
7321 +
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));
7324 +
7325 +
7326 +#endif /* DB */
7327 +
7328 +#endif /* DB_H */
7329 diff --git a/db_mysql.c b/db_mysql.c
7330 index 8aef6d4..4c09f48 100644
7331 --- a/db_mysql.c
7332 +++ b/db_mysql.c
7333 @@ -1,88 +1,88 @@
7334 -#if defined(DB_MYSQL) && defined(DB)
7335 -
7336  /*
7337 -Writen by Devrim SERAL(devrim@tef.gazi.edu.tr)
7338 -*/
7339 + * Writen by Devrim SERAL(devrim@tef.gazi.edu.tr)
7340 + */
7341 +
7342  
7343  #include "tac_plus.h"
7344 +
7345 +#if defined(DB_MYSQL) && defined(DB)
7346 +
7347  #include <stdio.h>
7348 -#include "mysql.h"
7349 +#include <stdlib.h>
7350 +#include <mysql.h>
7351 +
7352 +#include "db_mysql.h"
7353 +#include "report.h"
7354 +#include "pwlib.h"
7355 +#include "main.h"
7356 +#include "utils.h"
7357 +
7358 +
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())"
7362  
7363 -MYSQL mysqldb;
7364 -MYSQL_RES *res;
7365 -MYSQL_ROW row;
7366 -MYSQL_FIELD *table_field;
7367 -
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;
7373  
7374  
7375 -char *user, *users_passwd;      /* Username and gived password   */
7376 -char *db_user;                  /* db's parameters               */
7377 -char *db_password;
7378 -char *db_hostname;
7379 -char *db_name;
7380 -char *db_table;
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));
7384  
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;
7396  {
7397 -
7398 -char *real_passwd;
7399 -char *mysqlcmd;
7400 -int sql_len;
7401 +    char *real_passwd;
7402 +    char *mysqlcmd;
7403 +    int sql_len;
7404  
7405      if (debug & DEBUG_AUTHEN_FLAG)
7406         report(LOG_DEBUG, "MySQL: verify %s", user);
7407  
7408 -/* Connect database server */
7409 +    /* Connect database server */
7410  
7411 -   if ( !( mysql_connect(&mysqldb,db_hostname,db_user,db_password) ) )
7412 -       {
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);
7416         return(0);
7417      }
7418  
7419 -/*Select tacacs db */
7420 +    /* Select tacacs db */
7421  
7422 -    if ( mysql_select_db(&mysqldb,db_name) )
7423 -       {
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);
7427         return(0);
7428      }
7429  
7430 -/* Check select string length */
7431 +    /* Check select string length */
7432  
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);
7435  
7436 -  if ( sql_len> SQLCMDL )
7437 -        {
7438 +    if ( sql_len> SQLCMDL ) {
7439         if (debug & DEBUG_AUTHEN_FLAG)
7440              report(LOG_DEBUG, "MySQL: Sql cmd exceed alowed limits");
7441         return(0);
7442      }
7443  
7444 -/* Prepare select string */
7445 +    /* Prepare select string */
7446  
7447 -mysqlcmd=(char *) malloc(sql_len);
7448 -
7449 -if(mysqlcmd==NULL) { 
7450 -       if (debug & DEBUG_AUTHEN_FLAG)
7451 -               report(LOG_ERR, "mysql_db_verify: mysqlcmd malloc error");
7452 -       return(0);
7453 -}
7454 +    mysqlcmd = (char *) tac_malloc(sql_len);
7455  
7456 -sprintf(mysqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
7457 +    sprintf(mysqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
7458  
7459 -/*  Query database */
7460 +    /*  Query database */
7461  
7462 -    if (mysql_query(&mysqldb,mysqlcmd))
7463 -       {
7464 +    if (mysql_query(&mysqldb,mysqlcmd)) {
7465         if (debug & DEBUG_AUTHEN_FLAG)
7466                 report(LOG_DEBUG, "MySQL: cannot query database ");
7467         free(mysqlcmd);
7468 @@ -91,32 +91,29 @@ sprintf(mysqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
7469  
7470      free(mysqlcmd);
7471  
7472 -    if (!(res = mysql_store_result(&mysqldb)))
7473 -       {
7474 +    if (!(res = mysql_store_result(&mysqldb))) {
7475         if (debug & DEBUG_AUTHEN_FLAG)
7476                 report(LOG_DEBUG, "MySQL: cannot store result");
7477          return(0);
7478      }
7479  
7480 -   if(!(row = mysql_fetch_row(res)))
7481 -       {
7482 +   if (!(row = mysql_fetch_row(res))) {
7483         if (debug & DEBUG_AUTHEN_FLAG)
7484                 report(LOG_DEBUG, "MySQL: cannot fetch row");
7485          return(0);
7486      }
7487  
7488 -   if (strlen(row[0]) <=0 )
7489 -        {
7490 +   if (strlen(row[0]) <=0 ) {
7491         if (debug & DEBUG_AUTHEN_FLAG)
7492                 report(LOG_DEBUG, "MySQL: DB passwd entry is NULL");
7493          return(0);
7494      }
7495 +
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]);
7500  
7501 -   if (!mysql_eof(res))
7502 -       {
7503 +    if (!mysql_eof(res)) {
7504         if (debug & DEBUG_AUTHEN_FLAG)
7505             report(LOG_DEBUG, "MySQL:  Result not end!!");
7506          return(0);
7507 @@ -125,7 +122,7 @@ sprintf(mysqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
7508      mysql_free_result(res);
7509      mysql_close(&mysqldb);
7510  
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);
7514  
7515      /* Try to verify the password */
7516 @@ -133,69 +130,65 @@ if (debug & DEBUG_AUTHEN_FLAG)
7517          free(real_passwd);
7518         return (0);
7519      }
7520 +
7521      free(real_passwd);
7522      return (1); /* Return 1 if verified, 0 otherwise. */
7523  }
7524  
7525 -int 
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)
7527  
7528 -char *db_user;                 /* db's parameters              */
7529 -char *db_password;
7530 -char *db_hostname;
7531 -char *db_name;
7532 -char *db_table;
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));
7535  
7536 +int
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;
7549  {
7550 +    char *mysqlcmd;
7551 +    int sql_len;
7552  
7553 -char *mysqlcmd;
7554 -int sql_len;
7555 -       
7556 -/* Connect database server */
7557 +    /* Connect database server */
7558  
7559 -   if (!(mysql_connect(&mysqldb,db_hostname,db_user,db_password)))
7560 -       {
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);
7564             return(0);
7565      }
7566  
7567 -/*Select tacacs db */
7568 +    /*Select tacacs db */
7569  
7570 -    if (mysql_select_db(&mysqldb,db_name))
7571 -       {
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);
7575         return(0);
7576      }
7577  
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);
7582  
7583 -if ( sql_len >SQLCMDL)
7584 -        {
7585 +    if ( sql_len >SQLCMDL) {
7586          if (debug & DEBUG_ACCT_FLAG)
7587                 report(LOG_DEBUG, "MySQL: Sql cmd exceed alowed limits");
7588         return(0);
7589      }
7590  
7591  
7592 -/* Prepare select string */
7593 -mysqlcmd=(char *) malloc(sql_len);
7594 +    /* Prepare select string */
7595 +    mysqlcmd=(char *) tac_malloc(sql_len);
7596  
7597 -if(mysqlcmd==NULL) { 
7598 -       if (debug & DEBUG_ACCT_FLAG)
7599 -               report(LOG_ERR, "mysql_db_acct: mysqlcmd malloc error");
7600 -       return(0);
7601 -}
7602 -
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);
7605  
7606 -/*  Query database */
7607 +    /*  Query database */
7608  
7609 -    if (mysql_query(&mysqldb,mysqlcmd))
7610 -       {
7611 +    if (mysql_query(&mysqldb,mysqlcmd)) {
7612         if (debug & DEBUG_ACCT_FLAG)
7613             report(LOG_DEBUG, "MySQL: cannot query database");
7614         free(mysqlcmd);
7615 @@ -204,13 +197,18 @@ sprintf(mysqlcmd,ACCTSQL,db_table,a_username,s_name,c_name,elapsed_time,bytes_in
7616  
7617      free(mysqlcmd);
7618  
7619 -/* Check if accounting is sucess */
7620 -    if ( mysql_affected_rows( &mysqldb ) < 0 )
7621 -       {
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");
7626          return(0);
7627      }
7628 +
7629      return (1); /* Return 1 if verified, 0 otherwise. */
7630  }
7631 -#endif
7632 +
7633 +#else /* defined(DB_MYSQL) && defined(DB) */
7634 +
7635 +TAC_SOURCEFILE_EMPTY
7636 +
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
7641 --- /dev/null
7642 +++ b/db_mysql.h
7643 @@ -0,0 +1,15 @@
7644 +#ifndef DB_MYSQL_H
7645 +#define DB_MYSQL_H 1
7646 +
7647 +#include "tac_plus.h"
7648 +
7649 +#if defined(DB_MYSQL) && defined(DB)
7650 +
7651 +
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));
7654 +
7655 +
7656 +#endif /* defined(DB_MYSQL) && defined(DB) */
7657 +
7658 +#endif /* DB_MYSQL_H */
7659 diff --git a/db_null.c b/db_null.c
7660 index 40252d8..9892ef0 100644
7661 --- a/db_null.c
7662 +++ b/db_null.c
7663 @@ -6,22 +6,30 @@
7664  **  DO_NOT_USE_THIS_FOR_WORK!
7665  */
7666  
7667 -#if defined(DB_NULL) && defined(DB)
7668 +
7669  #include "tac_plus.h"
7670  
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)
7674 +
7675 +#include "db_null.h"
7676 +#include "report.h"
7677 +#include "main.h"
7678  
7679 -char *user, *users_passwd;      /* Username and gived password   */
7680 -char *db_user;                 /* db's parametr's               */
7681 -char *db_password;
7682 -char *db_hostname;
7683 -char *db_table;
7684 -char *dbfield_name;
7685 -char *dbfield_passwd;
7686  
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));
7688 +
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;
7699  {
7700 -//report(LOG_DEBUG, "DB_NULL(%u) - ok", __LINE__);
7701 +/*    report(LOG_DEBUG, "DB_NULL(%u) - ok", __LINE__); */
7702  
7703      /* Try to verify the password
7704         Successful if username and password equal */
7705 @@ -36,22 +44,30 @@ char *dbfield_passwd;
7706  
7707  /*     Null Database Accounting        */
7708  
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));
7710 +
7711  int
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               */
7714 -char *db_password;
7715 -char *db_hostname;
7716 -char *db_name;
7717 -char *db_table;
7718 -char *s_name;
7719 -char *c_name;
7720 -char *a_username;
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;
7733  {
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);
7737 -return (1);
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);
7741 +    return (1);
7742  }
7743 -#endif
7744  
7745 +#else /* defined(DB_NULL) && defined(DB) */
7746 +
7747 +TAC_SOURCEFILE_EMPTY
7748 +
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
7753 --- /dev/null
7754 +++ b/db_null.h
7755 @@ -0,0 +1,15 @@
7756 +#ifndef DB_NULL_H
7757 +#define DB_NULL_H 1
7758 +
7759 +#include "tac_plus.h"
7760 +
7761 +#if defined(DB_NULL) && defined(DB)
7762 +
7763 +
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));
7766 +
7767 +
7768 +#endif /* defined(DB_NULL) && defined(DB) */
7769 +
7770 +#endif /* DB_NULL_H */
7771 diff --git a/db_pgsql.c b/db_pgsql.c
7772 index 22725fe..321133c 100644
7773 --- a/db_pgsql.c
7774 +++ b/db_pgsql.c
7775 @@ -1,5 +1,3 @@
7776 -#if defined(DB_PGSQL) && defined(DB)
7777 -
7778  /*
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.
7783  */
7784  
7785 +
7786  #include "tac_plus.h"
7787 +
7788 +#if defined(DB_PGSQL) && defined(DB)
7789 +
7790  #include <stdio.h>
7791 -#include "libpq-fe.h" 
7792 +#include <stdlib.h>
7793 +#include <libpq-fe.h>
7794 +#include <string.h>
7795 +
7796 +#include "db_pgsql.h"
7797 +#include "main.h"
7798 +#include "report.h"
7799 +#include "utils.h"
7800 +#include "pwlib.h"
7801 +
7802 +
7803 +static void exit_nicely TAC_ARGS((PGconn *cn, PGresult *r));
7804 +
7805 +
7806  #define SQLCMDL 1024
7807  #define PWLEN  13
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())"
7810  
7811 -PGconn     *conn;
7812 -PGresult   *res;
7813 -
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;
7818  
7819  
7820 -char *user, *users_passwd;      /* Username and gived password   */
7821 -char *db_user;                  /* db's parameters               */
7822 -char *db_password;
7823 -char *db_hostname;
7824 -char *db_name;
7825 -char *db_table;
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));
7829  
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;
7841  {
7842 +    char *real_passwd;
7843 +    char *pgsqlcmd;
7844 +    int sql_len;
7845 +    int nrow;
7846  
7847 -char *real_passwd;
7848 -char *pgsqlcmd;
7849 -int sql_len;
7850 -int nrow;
7851 -
7852 -if (debug & DEBUG_AUTHEN_FLAG)
7853 +    if (debug & DEBUG_AUTHEN_FLAG)
7854         report(LOG_DEBUG, "PGSQL: verify %s", user);
7855  
7856 -/* Connect database server */
7857 +    /* Connect database server */
7858  
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);
7861  
7862 -if ( PQstatus(conn) == CONNECTION_BAD ) 
7863 -{
7864 +    if ( PQstatus(conn) == CONNECTION_BAD ) {
7865         if (debug & DEBUG_AUTHEN_FLAG)
7866             report(LOG_DEBUG, "PGSQL: Connection to database %s failed", db_name);
7867         return(0);
7868 -}
7869 +    }
7870  
7871 -/* Check select string length */
7872 +    /* Check select string length */
7873  
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);
7876  
7877 -if ( sql_len> SQLCMDL )
7878 -{
7879 +    if ( sql_len> SQLCMDL ) {
7880         if (debug & DEBUG_AUTHEN_FLAG)
7881             report(LOG_DEBUG, "PGSQL: Sql cmd exceed alowed limits");
7882         return(0);
7883 -}
7884 -
7885 -/* Prepare select string */
7886 +    }
7887  
7888 -pgsqlcmd=(char *) malloc(sql_len);
7889 +    /* Prepare select string */
7890  
7891 -if(pgsqlcmd==NULL) 
7892 -{ 
7893 -    if (debug & DEBUG_AUTHEN_FLAG)
7894 -       report(LOG_ERR, "pgsql_db_verify: pgsqlcmd malloc error");
7895 -       return(0);
7896 -}
7897 +    pgsqlcmd=(char *) tac_malloc(sql_len);
7898  
7899 -sprintf(pgsqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
7900 +    sprintf(pgsqlcmd,AUTHSQL,dbfield_passwd,db_table,dbfield_name,user);
7901  
7902 -/*  Query database */
7903 -res=PQexec(conn,pgsqlcmd);
7904 +    /*  Query database */
7905 +    res=PQexec(conn,pgsqlcmd);
7906  
7907 -if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
7908 -{
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)
7914         free(pgsqlcmd);
7915         exit_nicely(conn,res);
7916         return(0);
7917 -}
7918 +    }
7919  
7920 -free(pgsqlcmd);
7921 +    free(pgsqlcmd);
7922  
7923 -if( nrow=PQntuples(res)!=1) 
7924 -{  
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);
7929         return(0);
7930 -}  
7931 +    }
7932  
7933 -if ( PQgetisnull(res,0,PQfnumber(res,dbfield_passwd)) ) 
7934 -{
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);
7939         return(0);
7940 -}
7941 +    }
7942  
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';
7948  
7949 -exit_nicely(conn,res);
7950 +    exit_nicely(conn,res);
7951  
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);
7955  
7956      /* Try to verify the password */
7957      if (!des_verify(users_passwd, real_passwd))
7958 -       {
7959         return (0);
7960 -       }
7961  
7962      return (1); /* Return 1 if verified, 0 otherwise. */
7963  }
7964  
7965  /*     PGSQL ACCOUNTING function       */
7966  
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)
7968 -
7969 -char *db_user;                  /* db's parameters              */
7970 -char *db_password;
7971 -char *db_hostname;
7972 -char *db_name;
7973 -char *db_table;
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));
7976  
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;
7989  {
7990 -
7991 -char *pgsqlcmd;
7992 -int sql_len;
7993 +    char *pgsqlcmd;
7994 +    int sql_len;
7995  
7996      if (debug & DEBUG_ACCT_FLAG)
7997         report(LOG_DEBUG, "PGSQL: Accounting for %s begin", a_username);
7998  
7999 -/* Connect database server */
8000 +    /* Connect database server */
8001  
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);
8004  
8005 -if ( PQstatus(conn) == CONNECTION_BAD ) 
8006 -{
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) );
8011         }
8012         return(0);
8013 -}
8014 +    }
8015  
8016 -/* Check select string length */
8017 +    /* Check select string length */
8018  
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);
8021  
8022 -if ( sql_len> SQLCMDL )
8023 -{
8024 +    if ( sql_len> SQLCMDL ) {
8025         if (debug & DEBUG_ACCT_FLAG)
8026             report(LOG_DEBUG, "PGSQL: Sql cmd exceed alowed limits");
8027         return(0);
8028 -}
8029 -
8030 -/* Prepare select string */
8031 +    }
8032  
8033 -pgsqlcmd=(char *) malloc(sql_len);
8034 +    /* Prepare select string */
8035  
8036 -if(pgsqlcmd==NULL) 
8037 -{
8038 -if (debug & DEBUG_ACCT_FLAG) 
8039 -       report(LOG_ERR, "pgsql_db_verify: pgsqlcmd malloc error");
8040 -       return(0);
8041 -}
8042 +    pgsqlcmd=(char *) tac_malloc(sql_len);
8043  
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);
8046  
8047 -/*  Query database */
8048 -res=PQexec(conn,pgsqlcmd);
8049 +    /*  Query database */
8050 +    res=PQexec(conn,pgsqlcmd);
8051  
8052 -if (!res || PQresultStatus(res) != PGRES_COMMAND_OK )
8053 -{
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) );
8058 -}
8059 +       }
8060         free(pgsqlcmd);
8061          exit_nicely(conn,res);
8062         return(0);
8063 -}
8064 +    }
8065  
8066 -free(pgsqlcmd);
8067 +    free(pgsqlcmd);
8068  
8069 -/* Flush all result and close connection */
8070 -exit_nicely(conn,res);
8071 +    /* Flush all result and close connection */
8072 +    exit_nicely(conn,res);
8073  
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. */
8078  }
8079  
8080 -int
8081 -exit_nicely(PGconn *cn,PGresult *r)
8082 +
8083 +static void exit_nicely TAC_ARGS((PGconn *cn, PGresult *r));
8084 +
8085 +static void
8086 +exit_nicely(cn, r)
8087 +PGconn *cn;
8088 +PGresult *r;
8089  {
8090      PQclear(r);
8091      PQfinish(cn);
8092  }
8093  
8094 -#endif
8095 +#else /* defined(DB_PGSQL) && defined(DB) */
8096 +
8097 +TAC_SOURCEFILE_EMPTY
8098 +
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
8103 --- /dev/null
8104 +++ b/db_pgsql.h
8105 @@ -0,0 +1,15 @@
8106 +#ifndef DB_PGSQL_H
8107 +#define DB_PGSQL_H 1
8108 +
8109 +#include "tac_plus.h"
8110 +
8111 +#if defined(DB_PGSQL) && defined(DB)
8112 +
8113 +
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));
8116 +
8117 +
8118 +#endif /* defined(DB_PGSQL) && defined(DB) */
8119 +
8120 +#endif /* DB_PGSQL_H */
8121 diff --git a/default_fn.c b/default_fn.c
8122 index f97e9e2..d6196cf 100644
8123 --- a/default_fn.c
8124 +++ b/default_fn.c
8125 @@ -17,23 +17,50 @@
8126     FITNESS FOR A PARTICULAR PURPOSE.
8127  */
8128  
8129 +
8130  #include "tac_plus.h"
8131 +
8132 +#include <stdlib.h>
8133 +#include <string.h>
8134 +#include <ctype.h>
8135 +
8136 +#include "default_fn.h"
8137  #include "expire.h"
8138  #include "md5.h"
8139 +#include "report.h"
8140 +#include "utils.h"
8141 +#include "cfgfile.h"
8142 +#include "pwlib.h"
8143 +#include "choose_authen.h"             /* for "struct authen_data" */
8144 +#include "do_author.h"                 /* for "struct identity" */
8145 +#include "packet.h"
8146 +#include "main.h"
8147  
8148  #ifdef MSCHAP
8149  #include "md4.h"
8150  #include "mschap.h"
8151 -
8152  #ifdef MSCHAP_DES
8153  #include "arap_des.h"
8154 -#endif
8155 +#endif /* MSCHAP_DES */
8156  #endif /* MSCHAP */
8157  
8158  #ifdef ARAP_DES
8159  #include "arap_des.h"
8160  #endif
8161  
8162 +
8163 +struct private_data;
8164 +
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));
8169 +
8170 +#ifdef MSCHAP
8171 +static void mschap_verify TAC_ARGS((struct authen_data *data));
8172 +#endif
8173 +
8174 +
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 {
8179      int state;
8180  };
8181  
8182 -static void chap_verify();
8183 -#ifdef MSCHAP
8184 -static void mschap_verify();
8185 -#endif /* MSCHAP */
8186 -static void arap_verify();
8187 -static void pap_verify();
8188 -static void tac_login();
8189  
8190  /*
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
8194   */
8195  
8196 +int default_fn TAC_ARGS((struct authen_data *data));
8197 +
8198  int
8199  default_fn(data)
8200  struct authen_data *data;
8201 @@ -210,6 +232,8 @@ struct authen_data *data;
8202   *
8203   */
8204  
8205 +static void tac_login TAC_ARGS((struct authen_data *data, struct private_data *p));
8206 +
8207  static void
8208  tac_login(data, p)
8209  struct authen_data *data;
8210 @@ -278,6 +302,8 @@ struct private_data *p;
8211   * the START packet.
8212   */
8213  
8214 +static void pap_verify TAC_ARGS((struct authen_data *data));
8215 +
8216  static void
8217  pap_verify(data)
8218  struct authen_data *data;
8219 @@ -305,6 +331,8 @@ struct authen_data *data;
8220  }
8221  
8222  
8223 +static void chap_verify TAC_ARGS((struct authen_data *data));
8224 +
8225  /* Verify the challenge and id against the response by looking up the
8226   * chap secret in the config file. Set data->status appropriately.
8227   */
8228 @@ -312,8 +340,9 @@ static void
8229  chap_verify(data)
8230  struct authen_data *data;
8231  {
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;
8237      u_char *mdp;
8238      char id;
8239      int chal_len, inlen;
8240 @@ -398,13 +427,15 @@ struct authen_data *data;
8241  }
8242  
8243  
8244 +static void pw_bitshift TAC_ARGS((char *pw));
8245 +
8246  /*
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).
8251   */
8252 -void 
8253 +static void
8254  pw_bitshift(pw)
8255  char *pw;
8256  {
8257 @@ -423,12 +454,14 @@ char *pw;
8258  }
8259  
8260  
8261 +static void arap_verify TAC_ARGS((struct authen_data *data));
8262 +
8263  static void
8264  arap_verify(data)
8265  struct authen_data *data;
8266  {
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;
8270  
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;
8274  #ifdef MSCHAP
8275  
8276  /* Following code is added for ms-chap */
8277 +
8278 +static void mschap_desencrypt TAC_ARGS((const char *clear, unsigned char *str, unsigned char *cypher));
8279 +
8280  static void
8281  mschap_desencrypt(clear, str, cypher)
8282 -char *clear;
8283 +const char *clear;
8284  unsigned char *str;
8285  unsigned char *cypher;
8286  {
8287 @@ -576,19 +612,23 @@ unsigned char *cypher;
8288  }
8289  
8290  
8291 +static void mschap_deshash TAC_ARGS((unsigned char *clear, unsigned char *cypher));
8292 +
8293  static void
8294  mschap_deshash(clear, cypher)
8295 -char *clear;
8296 -char *cypher;
8297 +unsigned char *clear;
8298 +unsigned char *cypher;
8299  {
8300      mschap_desencrypt(MSCHAP_KEY, clear, cypher);
8301  }
8302  
8303  
8304 +static void mschap_lmpasswordhash TAC_ARGS((const char *password, unsigned char *passwordhash));
8305 +
8306  static void
8307  mschap_lmpasswordhash(password, passwordhash)
8308 -char *password;
8309 -char *passwordhash;
8310 +const char *password;
8311 +unsigned char *passwordhash;
8312  {
8313      unsigned char upassword[15];
8314      int i = 0;
8315 @@ -604,13 +644,15 @@ char *passwordhash;
8316  }
8317  
8318  
8319 +static void mschap_challengeresponse TAC_ARGS((const char *challenge, unsigned char *passwordhash, unsigned char *response));
8320 +
8321  static void
8322  mschap_challengeresponse(challenge, passwordhash, response)
8323 -char *challenge;
8324 -char *passwordhash;
8325 -char *response;
8326 +const char *challenge;
8327 +unsigned char *passwordhash;
8328 +unsigned char *response;
8329  {
8330 -    char zpasswordhash[21];
8331 +    unsigned char zpasswordhash[21];
8332  
8333      memset(zpasswordhash, 0, 21);
8334      memcpy(zpasswordhash, passwordhash, 16);
8335 @@ -621,22 +663,26 @@ char *response;
8336  }
8337  
8338  
8339 +void mschap_lmchallengeresponse TAC_ARGS((const char *challenge, const char *password, unsigned char *response));
8340 +
8341  void
8342  mschap_lmchallengeresponse(challenge, password, response)
8343 -char *challenge;
8344 -char *password;
8345 -char *response;
8346 +const char *challenge;
8347 +const char *password;
8348 +unsigned char *response;
8349  {
8350 -    char passwordhash[16];
8351 +    unsigned char passwordhash[16];
8352  
8353      mschap_lmpasswordhash(password, passwordhash);
8354      mschap_challengeresponse(challenge, passwordhash, response);
8355  }
8356  
8357  
8358 +static int mschap_unicode_len TAC_ARGS((unsigned char *password));
8359 +
8360  static int
8361  mschap_unicode_len(password)
8362 -char *password;
8363 +unsigned char *password;
8364  {
8365      int i;
8366  
8367 @@ -649,14 +695,16 @@ char *password;
8368  }
8369  
8370  
8371 +static void mschap_ntpasswordhash TAC_ARGS((const char *password, unsigned char *passwordhash));
8372 +
8373  static void
8374  mschap_ntpasswordhash(password, passwordhash)
8375 -char *password;
8376 -char *passwordhash;
8377 +const char *password;
8378 +unsigned char *passwordhash;
8379  {
8380      MD4_CTX context;
8381      int i;
8382 -    char *cp;
8383 +    const char *cp;
8384      unsigned char unicode_password[512];
8385  
8386      memset(unicode_password, 0, 512);
8387 @@ -676,15 +724,15 @@ char *passwordhash;
8388  }
8389  
8390  
8391 +void mschap_ntchallengeresponse TAC_ARGS((const char *challenge, const char *password, unsigned char *response));
8392 +
8393  void
8394 -mschap_ntchallengeresponse(challenge,
8395 -                          password,
8396 -                          response)
8397 -char *challenge;
8398 -char *password;
8399 -char *response;
8400 +mschap_ntchallengeresponse(challenge, password, response)
8401 +const char *challenge;
8402 +const char *password;
8403 +unsigned char *response;
8404  {
8405 -    char passwordhash[16];
8406 +    unsigned char passwordhash[16];
8407  
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.
8413   */
8414 +
8415 +static void mschap_verify TAC_ARGS((struct authen_data *data));
8416 +
8417  static void
8418  mschap_verify(data)
8419  struct authen_data *data;
8420  {
8421 -    char *name, *secret, *chal, *resp;
8422 -    char *exp_date, *p;
8423 +    const char *name, *secret, *chal, *resp;
8424 +    const char *exp_date, *p;
8425      char id;
8426      int chal_len;
8427 -    char lmresponse[24];
8428 -    char ntresponse[24];
8429 +    unsigned char lmresponse[24];
8430 +    unsigned char ntresponse[24];
8431      int bcmp_status;
8432  
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
8437 --- /dev/null
8438 +++ b/default_fn.h
8439 @@ -0,0 +1,16 @@
8440 +#ifndef DEFAULT_FN_H
8441 +#define DEFAULT_FN_H 1
8442 +
8443 +#include "tac_plus.h"
8444 +
8445 +
8446 +struct authen_data;
8447 +
8448 +extern int default_fn TAC_ARGS((struct authen_data *data));
8449 +#ifdef MSCHAP
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));
8452 +#endif
8453 +
8454 +
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
8460 @@ -17,8 +17,23 @@
8461     FITNESS FOR A PARTICULAR PURPOSE.
8462  */
8463  
8464 +
8465  #include "tac_plus.h"
8466 +
8467 +#include <stdlib.h>
8468 +#include <string.h>
8469 +
8470 +#include "default_v0_fn.h"
8471  #include "expire.h"
8472 +#include "utils.h"
8473 +#include "report.h"
8474 +#include "pwlib.h"
8475 +#include "choose_authen.h"             /* for "struct authen_data" */
8476 +#include "do_author.h"                 /* for "struct identity" */
8477 +#include "packet.h"
8478 +#include "main.h"
8479 +#include "cfgfile.h"
8480 +
8481  
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
8486   */
8487  
8488 +int default_v0_fn TAC_ARGS((struct authen_data *data));
8489 +
8490  int
8491  default_v0_fn(data)
8492  struct authen_data *data;
8493 @@ -185,4 +202,3 @@ struct authen_data *data;
8494         return (1);
8495      }
8496  }
8497 -
8498 diff --git a/default_v0_fn.h b/default_v0_fn.h
8499 new file mode 100644
8500 index 0000000..1165ee4
8501 --- /dev/null
8502 +++ b/default_v0_fn.h
8503 @@ -0,0 +1,12 @@
8504 +#ifndef DEFAULT_V0_FN_H
8505 +#define DEFAULT_V0_FN_H 1
8506 +
8507 +#include "tac_plus.h"
8508 +
8509 +
8510 +struct authen_data;
8511 +
8512 +extern int default_v0_fn TAC_ARGS((struct authen_data *data));
8513 +
8514 +
8515 +#endif /* DEFAULT_V0_FN_H */
8516 diff --git a/do_acct.c b/do_acct.c
8517 index dee8eaa..287b0dc 100644
8518 --- a/do_acct.c
8519 +++ b/do_acct.c
8520 @@ -17,18 +17,46 @@
8521     FITNESS FOR A PARTICULAR PURPOSE.
8522  */
8523  
8524 +
8525  #include "tac_plus.h"
8526  
8527 +#include <stdlib.h>
8528 +#include <errno.h>
8529 +#include <time.h>
8530 +#include <sys/types.h>
8531 +#include <sys/stat.h>
8532 +#ifdef HAVE_FCNTL_H
8533 +#include <fcntl.h>
8534 +#endif
8535 +#include <string.h>
8536 +#include <utmp.h>
8537 +#ifdef HAVE_UNISTD_H
8538 +#include <unistd.h>
8539 +#endif
8540 +
8541 +#include "do_acct.h"
8542 +#include "report.h"
8543 +#include "utils.h"
8544 +#include "main.h"
8545 +#include "do_author.h"                 /* for "struct identity" */
8546 +
8547 +
8548 +char *wtmpfile = NULL; /* for wtmp file logging */
8549 +
8550 +
8551 +static int wtmpfd = 0;
8552  static int acctfd = 0;
8553  
8554  /* Make a acct entry into the accounting file for accounting.
8555     Return 1 on error  */
8556  
8557 +static int acct_write TAC_ARGS((char *string));
8558 +
8559  static int
8560  acct_write(string)
8561 -    char *string;
8562 +char *string;
8563  {
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",
8567                session.peer,
8568                session.acctfile, sys_errlist[errno]);
8569 @@ -41,11 +69,13 @@ acct_write(string)
8570      return(0);
8571  }
8572  
8573 +static int acct_write_field TAC_ARGS((char *string));
8574 +
8575  /* Write a string or "unknown" into the accounting file.
8576     Return 1 on error  */
8577  static int
8578  acct_write_field(string)
8579 -    char *string;
8580 +char *string;
8581  {
8582      if (string && string[0]) {
8583         if (acct_write(string))
8584 @@ -57,6 +87,8 @@ acct_write_field(string)
8585      return(0);
8586  }
8587  
8588 +int do_acct TAC_ARGS((struct acct_rec *rec));
8589 +
8590  int
8591  do_acct(rec)
8592  struct acct_rec *rec;
8593 @@ -131,10 +163,12 @@ struct acct_rec *rec;
8594      return (0);
8595  }
8596  
8597 -int
8598 +static int wtmp_entry TAC_ARGS((char *line, char *name, char *host, time_t utime));
8599 +
8600 +static int
8601  wtmp_entry (line, name, host, utime)
8602 -    char *line, *name, *host;
8603 -    time_t utime;
8604 +char *line, *name, *host;
8605 +time_t utime;
8606  {
8607      struct utmp entry;
8608  
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);
8612  
8613 -#ifndef SOLARIS
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)
8619      close(wtmpfd);
8620  
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);
8624      }
8625  
8626      return(0);
8627  }
8628  
8629 +char *find_attr_value TAC_ARGS((char *attr, char **args, int cnt));
8630 +
8631  char *
8632  find_attr_value (attr, args, cnt)
8633 -    char *attr, **args;
8634 -    int cnt;
8635 +char *attr, **args;
8636 +int cnt;
8637  {
8638      int i;
8639  
8640 @@ -208,9 +244,11 @@ find_attr_value (attr, args, cnt)
8641      return(NULL);
8642  }
8643  
8644 +int do_wtmp TAC_ARGS((struct acct_rec *rec));
8645 +
8646  int
8647  do_wtmp(rec)
8648 -    struct acct_rec *rec;
8649 +struct acct_rec *rec;
8650  {
8651      time_t now = time(NULL);
8652      char *service;
8653 diff --git a/do_acct.h b/do_acct.h
8654 new file mode 100644
8655 index 0000000..5e6e025
8656 --- /dev/null
8657 +++ b/do_acct.h
8658 @@ -0,0 +1,33 @@
8659 +#ifndef DO_ACCT_H
8660 +#define DO_ACCT_H 1
8661 +
8662 +#include "tac_plus.h"
8663 +
8664 +
8665 +/* An API accounting record structure */
8666 +struct acct_rec {
8667 +    int acct_type;             /* start, stop, update */
8668 +
8669 +#define ACCT_TYPE_START      1
8670 +#define ACCT_TYPE_STOP       2
8671 +#define ACCT_TYPE_UPDATE     3
8672 +
8673 +    struct identity *identity;
8674 +    int authen_method;
8675 +    int authen_type;
8676 +    int authen_service;
8677 +    char *msg;       /* output field */
8678 +    char *admin_msg; /* output field */
8679 +    int num_args;
8680 +    char **args;
8681 +};
8682 +
8683 +extern char *wtmpfile;         /* for wtmp file logging */
8684 +
8685 +
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));
8689 +
8690 +
8691 +#endif /* DO_ACCT_H */
8692 diff --git a/do_author.c b/do_author.c
8693 index 574736f..3f23602 100644
8694 --- a/do_author.c
8695 +++ b/do_author.c
8696 @@ -17,15 +17,39 @@
8697     FITNESS FOR A PARTICULAR PURPOSE.
8698  */
8699  
8700 +
8701  #include "tac_plus.h"
8702 -#include "regexp.h"
8703  
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>
8712 +
8713 +#include "do_author.h"
8714 +#include "tac_regexp.h"
8715 +#include "cfgfile.h"
8716 +#include "report.h"
8717 +#include "utils.h"
8718 +#include "programs.h"
8719 +#include "main.h"
8720 +#include "parse.h"
8721 +#include "cfgeval.h"
8722 +
8723 +#ifdef MAXSESS
8724 +#include "maxsess.h"
8725 +#endif
8726 +#ifdef USE_PAM
8727 +#include "tac_pam.h"
8728 +#endif
8729 +
8730 +
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));
8737 +
8738 +
8739 +int do_author TAC_ARGS((struct author_data *data));
8740  
8741  /* Return 0 is data->status is valid */
8742  int
8743 @@ -37,7 +61,7 @@ struct author_data *data;
8744      int svc;
8745      char *cmd, *protocol, *svcname;
8746  #ifdef USE_PAM
8747 -    char *pam_service= NULL;
8748 +    const char *pam_service= NULL;
8749  #endif
8750      protocol = NULL;
8751  
8752 @@ -48,7 +72,8 @@ struct author_data *data;
8753  
8754      /* If this user doesn't exist in our configs, do the default */
8755  
8756 -    if (!cfg_user_exists(username) && !cfg_user_exists(DEFAULT_USERNAME)) {
8757 +    if (!cfg_user_exists(username)) {
8758 +       if (!cfg_user_exists(DEFAULT_USERNAME)) {
8759  
8760             if (cfg_no_user_permitted()) {
8761                 if (debug & DEBUG_AUTHOR_FLAG)
8762 @@ -70,7 +95,8 @@ struct author_data *data;
8763             return (0);
8764         }
8765  
8766 -    if (!cfg_user_exists(username) && cfg_user_exists(DEFAULT_USERNAME)) {
8767 +       /* assumed (cfg_user_exists(DEFAULT_USERNAME)): */
8768 +
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;
8773  #ifdef USE_PAM
8774      /* Check  PAM Authorization */
8775      switch (svc) {
8776 +
8777      case N_svc_ppp:
8778      case N_svc_exec:
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) )) {
8781  
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))
8785 -       {
8786 +           if (tac_pam_authorization(data->id->username, data, pam_service)) {
8787                 if (debug & DEBUG_AUTHOR_FLAG)
8788                     report(LOG_DEBUG, "PAM Authorization Fail");
8789                 return(0);
8790             }
8791 -} /* Pam_service */
8792 +       } /* Pam_service */
8793 +
8794      default:
8795         break;
8796      }
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
8799  */
8800  
8801 +static int pre_authorization TAC_ARGS((const char *username, struct author_data *data));
8802 +
8803  static int
8804  pre_authorization(username, data)
8805 -char *username;
8806 +const char *username;
8807  struct author_data *data;
8808  {
8809      int status;
8810      char **out_args;
8811      int out_cnt, i;
8812 -    char *cmd;
8813 +    const char *cmd;
8814      char error_str[255];
8815      int error_len = 255;
8816  
8817 @@ -199,7 +228,7 @@ struct author_data *data;
8818      /* If a before-authorization program exists, call it to see how to
8819         proceed */
8820  
8821 -    cmd = cfg_get_pvalue(username, TAC_IS_USER, 
8822 +    cmd = cfg_get_pvalue(S_user, username,
8823                          S_before, TAC_PLUS_RECURSE);
8824      if (!cmd)
8825         return(0);
8826 @@ -303,16 +332,17 @@ struct author_data *data;
8827     change the authorization status by calling an external program.
8828  */
8829  
8830 +static void post_authorization TAC_ARGS((const char *username, struct author_data *data));
8831 +
8832  static void
8833  post_authorization(username, data)
8834 -    char *username;
8835 -    struct author_data *data;
8836 +const char *username;
8837 +struct author_data *data;
8838  {
8839      char **out_args;
8840      int out_cnt, i;
8841      int status;
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);
8845      if (!after)
8846         return;
8847  
8848 @@ -378,6 +408,8 @@ post_authorization(username, data)
8849  }
8850  
8851  
8852 +static char *value TAC_ARGS((char *s));
8853 +
8854  /* Return a pointer to the value part of an attr=value string */
8855  static char *
8856  value(s)
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 */
8860  
8861 +static char *assemble_args TAC_ARGS((struct author_data *data));
8862 +
8863  static char *
8864  assemble_args(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. */
8869  
8870 +static int authorize_exec TAC_ARGS((const char *user, struct author_data *data));
8871 +
8872  static int
8873  authorize_exec(user, data)
8874 -char *user;
8875 +const char *user;
8876  struct author_data *data;
8877  {
8878 -    NODE *svc;
8879 -
8880      if (debug & DEBUG_AUTHOR_FLAG)
8881         report(LOG_DEBUG, "exec authorization request for %s", user);
8882  
8883      /* Is an exec explicitly configured? If so, return 0 so we know to
8884         process its attributes */
8885  
8886 -    svc = cfg_get_svc_node(user, N_svc_exec, NULL, NULL, TAC_PLUS_RECURSE);
8887 -    if (svc) {
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",
8891 -                  svc->line);
8892 +           report(LOG_DEBUG, "exec is explicitly permitted");
8893         return (0);
8894      }
8895  
8896      /* No exec is configured. Are any commands configured? */
8897 -    svc = cfg_get_svc_node(user, N_svc_cmd, NULL, NULL, TAC_PLUS_RECURSE);
8898 -    if (svc) {
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");
8902  
8903 @@ -478,18 +509,6 @@ struct author_data *data;
8904         return (1);
8905      }
8906  
8907 -    /* No exec or commands configured. What's the default? */
8908 -    if (cfg_user_svc_default_is_permit(user)) {
8909 -
8910 -       if (debug & DEBUG_AUTHOR_FLAG) 
8911 -           report(LOG_DEBUG, "exec permitted by default");
8912 -
8913 -       data->status = AUTHOR_STATUS_PASS_ADD;
8914 -       data->output_args = NULL;
8915 -       data->num_out_args = 0;
8916 -       return (1);
8917 -    }
8918 -
8919      if (debug & DEBUG_AUTHOR_FLAG)
8920         report(LOG_DEBUG, "exec denied by default");
8921  
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 */
8925  
8926 +static int authorize_cmd TAC_ARGS((const char *user, const char *cmd, struct author_data *data));
8927 +
8928  static int
8929  authorize_cmd(user, cmd, data)
8930 -char *user, *cmd;
8931 +const char *user;
8932 +const char *cmd;
8933  struct author_data *data;
8934  {
8935 -    NODE *node;
8936      char *args;
8937 -    int match;
8938 -
8939 -    args = assemble_args(data);
8940  
8941      if (!cmd) {
8942         data->status = AUTHOR_STATUS_ERROR;
8943 @@ -520,93 +538,41 @@ struct author_data *data;
8944         return (0);
8945      }
8946  
8947 -    node = cfg_get_cmd_node(user, cmd, TAC_PLUS_RECURSE);
8948 -
8949 -    /* The command does not exist. Do the default */
8950 -    if (!node) {
8951 -
8952 -       if (cfg_user_svc_default_is_permit(user)) {
8953 -
8954 -           if (debug & DEBUG_AUTHOR_FLAG) 
8955 -               report(LOG_DEBUG, "cmd %s does not exist, permitted by default",
8956 -                      cmd);
8957 -           
8958 -           data->status = AUTHOR_STATUS_PASS_ADD;
8959 -           data->num_out_args = 0;
8960 -           if (args)
8961 -               free(args);
8962 -           return(0);
8963 -       }
8964 -
8965 -       if (debug & DEBUG_AUTHOR_FLAG) 
8966 -           report(LOG_DEBUG, "cmd %s does not exist, denied by default",
8967 -                  cmd);
8968 -
8969 -       data->status = AUTHOR_STATUS_FAIL;
8970 -       data->num_out_args = 0;
8971 -       if (args)
8972 -           free(args);
8973 -       return(0);
8974 -    }
8975 -
8976 -    /* The command exists. The default if nothing matches is DENY */
8977 -    data->status = AUTHOR_STATUS_FAIL;
8978 -    data->num_out_args = 0;
8979 -
8980 -    for (node=node->value1; node && args; node = node->next) {
8981 -       match = regexec((regexp *) node->value1, args);
8982 -
8983 -       if (debug & DEBUG_AUTHOR_FLAG) {
8984 -           report(LOG_INFO, "line %d compare %s %s '%s' & '%s' %smatch",
8985 -                  node->line, cmd,
8986 -                  node->type == N_permit ? "permit" : "deny",
8987 -                  node->value, args, (match ? "" : "no "));
8988 -       }
8989 -
8990 -       if (!match)
8991 -           continue;
8992 +    args = assemble_args(data);
8993 +    switch (cfg_authorize_cmd(user, cmd, args)) {
8994  
8995 -       switch (node->type) {
8996 -       case N_permit:
8997 -           if (debug & DEBUG_AUTHOR_FLAG) {
8998 -               report(LOG_DEBUG, "%s %s permitted by line %d", 
8999 -                      cmd, args, node->line);
9000 -           }
9001 +    case ER_TRUE:
9002         data->status = AUTHOR_STATUS_PASS_ADD;
9003         data->num_out_args = 0;
9004         break;
9005 -       case N_deny:
9006 -           if (debug & DEBUG_AUTHOR_FLAG) {
9007 -               report(LOG_DEBUG, "%s %s denied by line %d", 
9008 -                      cmd, args, node->line);
9009 -           }
9010 +
9011 +    case ER_FALSE:
9012         data->status = AUTHOR_STATUS_FAIL;
9013         data->num_out_args = 0;
9014         break;
9015 -       default:
9016 +
9017 +    case ER_UNKNOWN:
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");
9023         break;
9024      }
9025 +
9026      if (args)
9027         free(args);
9028 -       args = NULL;
9029 -       return (0);
9030 -    }
9031 -    if (args)
9032 -       free(args);
9033 -    return (0);
9034 +    return(0);
9035  }
9036  
9037 +static int is_separator TAC_ARGS((int ch));
9038 +
9039  static int
9040  is_separator(ch)
9041 -char ch;
9042 +int ch;                                /* promoted "char" type */
9043  {
9044      return (ch == '=' || ch == '*');
9045  }
9046  
9047 +static int arg_ok TAC_ARGS((char *arg));
9048 +
9049  /* check an attr=value pair for well-formedness */
9050  static int
9051  arg_ok(arg)
9052 @@ -630,6 +596,8 @@ char *arg;
9053  }
9054  
9055  
9056 +static int match_attrs TAC_ARGS((char *nas_arg, char *server_arg));
9057 +
9058  /* return 1 if attrs match, 0 otherwise */
9059  static int
9060  match_attrs(nas_arg, server_arg)
9061 @@ -647,6 +615,8 @@ char *nas_arg, *server_arg;
9062      return (0);
9063  }
9064  
9065 +static int match_values TAC_ARGS((char *nas_arg, char *server_arg));
9066 +
9067  /* return 1 if values match, 0 otherwise */
9068  static int
9069  match_values(nas_arg, server_arg)
9070 @@ -671,6 +641,8 @@ char *nas_arg, *server_arg;
9071      return(STREQ(nas_arg, server_arg));
9072  }
9073  
9074 +static int mandatory TAC_ARGS((char *arg));
9075 +
9076  /* Return 1 if arg is mandatory, 0 otherwise */
9077  static int
9078  mandatory(arg)
9079 @@ -690,6 +662,8 @@ char *arg;
9080      return (*p == '=');
9081  }
9082  
9083 +static int optional TAC_ARGS((char *arg));
9084 +
9085  static int
9086  optional(arg)
9087  char *arg;
9088 @@ -699,21 +673,16 @@ char *arg;
9089  
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 */
9094 +
9095 +static int ppp_lcp_allowed TAC_ARGS((const char *user));
9096  
9097  static int
9098 -ppp_lcp_allowed(svc, protocol, user)
9099 -    int svc;
9100 -    char *user, *protocol;
9101 +ppp_lcp_allowed(user)
9102 +const char *user;
9103  {
9104 -    /* This is not a ppp/lcp request. Just Say No */
9105 -    if (!(svc == N_svc_ppp &&
9106 -         protocol &&
9107 -         STREQ(protocol, "lcp")))
9108 -       return(0);
9109 -
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) {
9115             report(LOG_DEBUG,
9116                    "ppp/lcp request permitted (ppp is configured for %s)",
9117 @@ -730,14 +699,16 @@ ppp_lcp_allowed(svc, protocol, user)
9118      return(0);
9119  }
9120  
9121 +static int authorize_svc TAC_ARGS((const char *user, int svc, const char *protocol, const char *svcname, struct author_data *data));
9122 +
9123  /* Return 0 means data->status is valid */
9124  static int
9125  authorize_svc(user, svc, protocol, svcname, data)
9126 -    char *user;
9127 -    int svc;
9128 -    char *svcname;
9129 -    struct author_data *data;
9130 -    char *protocol; /* valid only if svc == ppp */
9131 +const char *user;
9132 +int svc;
9133 +const char *svcname;
9134 +struct author_data *data;
9135 +const char *protocol;          /* valid only if svc == ppp */
9136  {
9137      int max_args;
9138      char **out_args, **outp;
9139 @@ -747,20 +718,23 @@ authorize_svc(user, svc, protocol, svcname, data)
9140      char **cfg_argp;
9141      int deny_by_default;
9142      NODE *node;
9143 +    int service_permit;
9144  
9145      int replaced = 0;
9146      int added = 0;
9147      int cfg_cnt;
9148  
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);
9152  
9153 -    if (!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)
9161 +     */
9162  
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. */
9166  
9167         if (debug & DEBUG_AUTHOR_FLAG)
9168             report(LOG_DEBUG,
9169 @@ -775,7 +749,13 @@ authorize_svc(user, svc, protocol, svcname, data)
9170         return(0);
9171         }
9172  
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. */
9178 +
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)
9185     name in svcname.
9186  */
9187  
9188 +static int get_nas_svc TAC_ARGS((struct author_data *data, char **cmdname, char **protocol, char **svcname));
9189 +
9190  static int
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
9196 --- /dev/null
9197 +++ b/do_author.h
9198 @@ -0,0 +1,64 @@
9199 +#ifndef DO_AUTHOR_H
9200 +#define DO_AUTHOR_H 1
9201 +
9202 +#include "tac_plus.h"
9203 +
9204 +
9205 +/*
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.
9213 + */
9214 +
9215 +struct identity {
9216 +    char *username;
9217 +    char *NAS_name;
9218 +    char *NAS_port;
9219 +    char *NAC_address;
9220 +    int priv_lvl;
9221 +};
9222 +
9223 +
9224 +/*
9225 + * This structure is the data structure for passing information to
9226 + * and from the authorization function (do_author()).
9227 + */
9228 +struct author_data {
9229 +    struct identity *id;       /* user id */
9230 +    int authen_method;         /* authentication method */
9231 +
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
9239 +
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 */
9245 +
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
9250 +
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 */
9255 +
9256 +};
9257 +
9258 +
9259 +extern int do_author TAC_ARGS((struct author_data *data));
9260 +
9261 +
9262 +#endif /* DO_AUTHOR_H */
9263 diff --git a/dump.c b/dump.c
9264 index ae58e5e..511085b 100644
9265 --- a/dump.c
9266 +++ b/dump.c
9267 @@ -17,8 +17,21 @@
9268     FITNESS FOR A PARTICULAR PURPOSE.
9269  */
9270  
9271 +
9272  #include "tac_plus.h"
9273  
9274 +#include <netinet/in.h>                /* for ntohl() */
9275 +
9276 +#include "dump.h"
9277 +#include "report.h"
9278 +#include "utils.h"
9279 +#include "packet.h"
9280 +#include "do_author.h"
9281 +#include "main.h"
9282 +
9283 +
9284 +char *summarise_outgoing_packet_type TAC_ARGS((u_char *pak));
9285 +
9286  /* Routines for dumping packets to stderr */
9287  char *
9288  summarise_outgoing_packet_type(pak)
9289 @@ -90,7 +103,9 @@ u_char *pak;
9290      return (p);
9291  }
9292  
9293 -void
9294 +static void dump_header TAC_ARGS((u_char *pak));
9295 +
9296 +static void
9297  dump_header(pak)
9298  u_char *pak;
9299  {
9300 @@ -117,7 +132,10 @@ u_char *pak;
9301  }
9302  
9303  
9304 +void dump_nas_pak TAC_ARGS((u_char *pak));
9305 +
9306  /* Dump packets originated by a NAS */
9307 +void
9308  dump_nas_pak(pak)
9309  u_char *pak;
9310  {
9311 @@ -376,6 +394,9 @@ u_char *pak;
9312  
9313  /* Dump packets originated by Tacacsd  */
9314  
9315 +void dump_tacacs_pak TAC_ARGS((u_char *pak));
9316 +
9317 +void
9318  dump_tacacs_pak(pak)
9319  u_char *pak;
9320  {
9321 @@ -482,6 +503,8 @@ u_char *pak;
9322      report(LOG_DEBUG, "End packet");
9323  }
9324  
9325 +char *summarise_incoming_packet_type TAC_ARGS((u_char *pak));
9326 +
9327  /* summarise packet types for logging routines. */
9328  char *
9329  summarise_incoming_packet_type(pak)
9330 diff --git a/dump.h b/dump.h
9331 new file mode 100644
9332 index 0000000..bddce30
9333 --- /dev/null
9334 +++ b/dump.h
9335 @@ -0,0 +1,15 @@
9336 +#ifndef DUMP_H
9337 +#define DUMP_H 1
9338 +
9339 +#include "tac_plus.h"
9340 +
9341 +#include <sys/types.h>         /* for u_* */
9342 +
9343 +
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));
9348 +
9349 +
9350 +#endif /* DUMP_H */
9351 diff --git a/enable.c b/enable.c
9352 index 63a17eb..3e56c92 100644
9353 --- a/enable.c
9354 +++ b/enable.c
9355 @@ -17,8 +17,23 @@
9356     FITNESS FOR A PARTICULAR PURPOSE.
9357  */
9358  
9359 +
9360  #include "tac_plus.h"
9361 +
9362 +#include <stdlib.h>
9363 +#include <string.h>
9364 +
9365 +#include "enable.h"
9366  #include "expire.h"
9367 +#include "utils.h"
9368 +#include "report.h"
9369 +#include "pwlib.h"
9370 +#include "choose_authen.h"             /* for "struct authen_data" */
9371 +#include "do_author.h"                 /* for "struct identity" */
9372 +#include "packet.h"
9373 +#include "main.h"
9374 +#include "cfgfile.h"
9375 +
9376  
9377  /* internal state variables */
9378  #define STATE_AUTHEN_START   0 /* no requests issued */
9379 @@ -30,6 +45,8 @@ struct private_data {
9380      int state;
9381  };
9382  
9383 +static void enable TAC_ARGS((char *passwd, struct authen_data *data));
9384 +
9385  static void
9386  enable(passwd, data)
9387  char *passwd;
9388 @@ -84,6 +101,8 @@ struct authen_data *data;
9389   * Return 0 if data->status is valid, otherwise 1
9390   */
9391  
9392 +int enable_fn TAC_ARGS((struct authen_data *data));
9393 +
9394  int
9395  enable_fn(data)
9396  struct authen_data *data;
9397 diff --git a/enable.h b/enable.h
9398 new file mode 100644
9399 index 0000000..10a4e8a
9400 --- /dev/null
9401 +++ b/enable.h
9402 @@ -0,0 +1,12 @@
9403 +#ifndef ENABLE_H
9404 +#define ENABLE_H 1
9405 +
9406 +#include "tac_plus.h"
9407 +
9408 +
9409 +struct authen_data;
9410 +
9411 +extern int enable_fn TAC_ARGS((struct authen_data *data));
9412 +
9413 +
9414 +#endif /* ENABLE_H */
9415 diff --git a/encrypt.c b/encrypt.c
9416 index 60ba5e9..2840916 100644
9417 --- a/encrypt.c
9418 +++ b/encrypt.c
9419 @@ -17,8 +17,19 @@
9420     FITNESS FOR A PARTICULAR PURPOSE.
9421  */
9422  
9423 +
9424  #include "tac_plus.h"
9425 +
9426 +#include <stdlib.h>
9427 +#include <netinet/in.h>                /* for ntohl() */
9428 +
9429 +#include "encrypt.h"
9430  #include "md5.h"
9431 +#include "utils.h"
9432 +#include "report.h"
9433 +#include "packet.h"
9434 +#include "main.h"
9435 +
9436  
9437  /*
9438   * create_md5_hash(): create an md5 hash of the "session_id", "the user's
9439 @@ -36,21 +47,25 @@
9440   *
9441   */
9442  
9443 -void
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));
9445 +
9446 +static void
9447  create_md5_hash(session_id, key, version, seq_no, prev_hash, hash)
9448  int session_id;
9449 -char *key;
9450 -u_char version;
9451 -u_char seq_no;
9452 +const char *key;
9453 +unsigned version;                      /* promoted "u_char" type */
9454 +unsigned seq_no;                       /* promoted "u_char" type */
9455  u_char *prev_hash;
9456  u_char *hash;
9457  {
9458      u_char *md_stream, *mdp;
9459      int md_len;
9460      MD5_CTX mdcontext;
9461 +    u_char version_uchar = version;
9462 +    u_char seq_no_uchar = seq_no;
9463  
9464 -    md_len = sizeof(session_id) + strlen(key) + sizeof(version) +
9465 -       sizeof(seq_no);
9466 +    md_len = sizeof(session_id) + strlen(key) + sizeof(version_uchar) +
9467 +       sizeof(seq_no_uchar);
9468  
9469      if (prev_hash) {
9470         md_len += MD5_LEN;
9471 @@ -62,11 +77,11 @@ u_char *hash;
9472      bcopy(key, mdp, strlen(key));
9473      mdp += strlen(key);
9474  
9475 -    bcopy(&version, mdp, sizeof(version));
9476 -    mdp += sizeof(version);
9477 +    bcopy(&version_uchar, mdp, sizeof(version_uchar));
9478 +    mdp += sizeof(version_uchar);
9479  
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);
9484  
9485      if (prev_hash) {
9486         bcopy(prev_hash, mdp, MD5_LEN);
9487 @@ -90,10 +105,13 @@ u_char *hash;
9488   * Return 0 on success, -1 on failure.
9489   */
9490  
9491 +int md5_xor TAC_ARGS((HDR *hdr, u_char *data, const char *key));
9492 +
9493 +int
9494  md5_xor(hdr, data, key)
9495  HDR *hdr;
9496  u_char *data;
9497 -char *key;
9498 +const char *key;
9499  {
9500      int i, j;
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
9505 --- /dev/null
9506 +++ b/encrypt.h
9507 @@ -0,0 +1,14 @@
9508 +#ifndef ENCRYPT_H
9509 +#define ENCRYPT_H 1
9510 +
9511 +#include "tac_plus.h"
9512 +
9513 +#include <sys/types.h>         /* for u_* */
9514 +
9515 +#include "packet.h"            /* for "HDR" */
9516 +
9517 +
9518 +extern int md5_xor TAC_ARGS((HDR *hdr, u_char *data, const char *key));
9519 +
9520 +
9521 +#endif /* ENCRYPT_H */
9522 diff --git a/expire.c b/expire.c
9523 index 1ef745c..3aed354 100644
9524 --- a/expire.c
9525 +++ b/expire.c
9526 @@ -17,9 +17,17 @@
9527     FITNESS FOR A PARTICULAR PURPOSE.
9528  */
9529  
9530 +
9531  #include "tac_plus.h"
9532 +
9533 +#include <ctype.h>
9534 +#include <time.h>
9535 +#include <string.h>
9536 +#include <stdio.h>
9537 +
9538  #include "expire.h"
9539  
9540 +
9541  /*
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};
9547  
9548 +int check_expiration TAC_ARGS((const char *date));
9549 +
9550  int
9551  check_expiration(date)
9552 -char *date;
9553 +const char *date;
9554  {
9555      long day, month, year, leaps, now, expiration, warning;
9556      char monthstr[10];
9557 @@ -52,11 +62,11 @@ char *date;
9558         return (PW_OK);
9559  
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);
9564  
9565      for(i=0; i < 3; i++) {
9566 -       monthstr[i] = toupper(monthstr[i]);
9567 +       monthstr[i] = toupper((int) monthstr[i]);
9568      }
9569  
9570      /* Compute the expiration date in days. */
9571 diff --git a/expire.h b/expire.h
9572 index c7df48d..6e7fc5e 100644
9573 --- a/expire.h
9574 +++ b/expire.h
9575 @@ -1,3 +1,8 @@
9576 +#ifndef EXPIRE_H
9577 +#define EXPIRE_H 1
9578 +
9579 +#include "tac_plus.h"
9580 +
9581  /*
9582     Copyright (c) 1995-1998 by Cisco systems, Inc.
9583  
9584 @@ -17,10 +22,15 @@
9585     FITNESS FOR A PARTICULAR PURPOSE.
9586  */
9587  
9588 +
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 */
9592  
9593  #define MAX_PASSWD_LEN 256
9594  
9595 -extern int check_expiration();
9596 +
9597 +extern int check_expiration TAC_ARGS((const char *date));
9598 +
9599 +
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
9605 @@ -23,12 +23,41 @@
9606     Usage: a.out [salt]
9607  */
9608  
9609 -#define NULL 0
9610  
9611 +#ifdef HAVE_CONFIG_H
9612 +#include "config.h"
9613 +#endif
9614 +
9615 +
9616 +#ifdef HAVE_UNISTD_H
9617 +#include <unistd.h>
9618 +#endif
9619 +#include <stdlib.h>
9620 +#include <time.h>
9621 +#include <stdio.h>
9622 +#include <string.h>
9623 +
9624 +
9625 +#ifndef NULL
9626 +#define NULL ((void *) 0)
9627 +#endif
9628 +
9629 +/* Stolen from pbmplus.h of netpbm: */
9630 +
9631 +#if __STDC__
9632 +#define TAC_ARGS(alist) alist
9633 +#else /*__STDC__*/
9634 +#define TAC_ARGS(alist) ()
9635 +#endif /*__STDC__*/
9636 +
9637 +
9638 +int main TAC_ARGS((int argc, char **argv));
9639 +
9640 +int
9641  main(argc, argv)
9642 +int argc;
9643  char **argv;
9644  {
9645 -    char *crypt();
9646      char pass[25], *salt, buf[24];
9647      char *result;
9648      int n;
9649 @@ -42,10 +71,10 @@ char **argv;
9650  
9651      write(1, prompt, strlen(prompt));
9652      n = read(0, pass, sizeof(pass));
9653 -    pass[n-1] = NULL;
9654 +    pass[n-1] = 0;
9655  
9656      if (!salt) {
9657 -       int i, r, r1, r2;
9658 +       int i, r, r1 = 0 /* GCC paranoia */, r2 = 0 /* GCC paranoia */;
9659  
9660         srand(time(0));
9661  
9662 @@ -82,9 +111,6 @@ char **argv;
9663  
9664      write(1, result, strlen(result));
9665      write(1, "\n", 1);
9666 -}
9667 -
9668 -
9669 -
9670 -
9671  
9672 +    return (EXIT_SUCCESS);
9673 +}
9674 diff --git a/hash.c b/hash.c
9675 index 443d42b..2db807b 100644
9676 --- a/hash.c
9677 +++ b/hash.c
9678 @@ -17,19 +17,24 @@
9679     FITNESS FOR A PARTICULAR PURPOSE.
9680  */
9681  
9682 +
9683  #include "tac_plus.h"
9684  
9685 +#include "hash.h"
9686 +#include "utils.h"
9687 +
9688 +
9689  struct entry {
9690      char *name;
9691      void *hash;
9692  };
9693  
9694 -typedef struct entry ENTRY;
9695 +static int calculate_hash TAC_ARGS((const char *name));
9696  
9697  /* Calculate hash value from a string */
9698  static int
9699  calculate_hash(name)
9700 -char *name;
9701 +const char *name;
9702  {
9703      int i;
9704      int len = strlen(name);
9705 @@ -43,12 +48,14 @@ char *name;
9706      return (hashval);
9707  }
9708  
9709 +void *hash_lookup TAC_ARGS((void **hashtab, const char *name));
9710 +
9711  /* Lookup a name in a hash table.  Return its node if it exists, NULL
9712     otherwise */
9713  void *
9714  hash_lookup(hashtab, name)
9715  void **hashtab;
9716 -char *name;
9717 +const char *name;
9718  {
9719      ENTRY *entry;
9720      int hashval = calculate_hash(name);
9721 @@ -64,6 +71,8 @@ char *name;
9722      return (NULL);
9723  }
9724  
9725 +void *hash_add_entry TAC_ARGS((void **hashtab, ENTRY *newentry));
9726 +
9727  /* Add a node to a hash table.  Return node if it exists, NULL
9728     otherwise */
9729  void *
9730 @@ -86,6 +95,8 @@ ENTRY *newentry;
9731  }
9732  
9733  
9734 +void **hash_get_entries TAC_ARGS((void **hashtab));
9735 +
9736  /* Return an array of pointers to all the entries in a hash table */
9737  void **
9738  hash_get_entries(hashtab)
9739 diff --git a/hash.h b/hash.h
9740 new file mode 100644
9741 index 0000000..a808f05
9742 --- /dev/null
9743 +++ b/hash.h
9744 @@ -0,0 +1,17 @@
9745 +#ifndef HASH_H
9746 +#define HASH_H 1
9747 +
9748 +#include "tac_plus.h"
9749 +
9750 +
9751 +#define HASH_TAB_SIZE 157        /* user and group hash table sizes */
9752 +
9753 +typedef struct entry ENTRY;
9754 +
9755 +
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));
9759 +
9760 +
9761 +#endif /* HASH_H */
9762 diff --git a/ldap_author.c b/ldap_author.c
9763 index ca1a8ef..c788e82 100644
9764 --- a/ldap_author.c
9765 +++ b/ldap_author.c
9766 @@ -36,21 +36,30 @@ Port name isn't required.. I would like to change format with :
9767  */
9768  
9769  
9770 -#if defined(USE_LDAP)
9771 +#include "tac_plus.h"
9772 +
9773 +#ifdef USE_LDAP
9774 +
9775  #include <stdio.h>
9776  #include <string.h>
9777 +#include <stdlib.h>
9778  #include <lber.h>
9779  #include <ldap.h>
9780  #include <ldap_cdefs.h>
9781  
9782 -#include "tac_plus.h"
9783 -#include "ldap.h"
9784 +#include "ldap_author.h"
9785 +#include "main.h"
9786 +#include "utils.h"
9787 +#include "report.h"
9788 +
9789  
9790 +int ldap_verify TAC_ARGS((const char *user, const char *users_passwd, const char *str_conn));
9791  
9792  int
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 */
9799  {
9800    char *buf;
9801    char *ldapServer;
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);
9805  
9806 -  buf=(char *)malloc(strlen(str_conn)+1);
9807 -  if (buf == NULL ){ 
9808 -       report(LOG_DEBUG, "Error can't allocate memory");
9809 -        return(1);
9810 -  }
9811 +  buf = (char *) tac_malloc(strlen(str_conn)+1);
9812  
9813    strcpy(buf,str_conn);
9814    ldapServer=strstr(buf, "://");
9815 @@ -99,7 +104,7 @@ char *str_conn;                 /* String connection to database */
9816        return 1;
9817      }
9818  
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);
9821  
9822    if(err != LDAP_SUCCESS)
9823      {
9824 @@ -116,4 +121,9 @@ char *str_conn;                 /* String connection to database */
9825       return 0;
9826      }
9827  }
9828 -#endif /* LDAP */
9829 +
9830 +#else /* USE_LDAP */
9831 +
9832 +TAC_SOURCEFILE_EMPTY
9833 +
9834 +#endif /* USE_LDAP */
9835 diff --git a/ldap_author.h b/ldap_author.h
9836 index 6479426..ecd71dd 100644
9837 --- a/ldap_author.h
9838 +++ b/ldap_author.h
9839 @@ -1 +1,14 @@
9840 -int ldap_verify();
9841 +#ifndef LDAP_AUTHOR_H
9842 +#define LDAP_AUTHOR_H 1
9843 +
9844 +#include "tac_plus.h"
9845 +
9846 +#ifdef USE_LDAP
9847 +
9848 +
9849 +extern int ldap_verify TAC_ARGS((const char *user, const char *users_passwd, const char *str_conn));
9850 +
9851 +
9852 +#endif /* USE_LDAP */
9853 +
9854 +#endif /* LDAP_AUTHOR_H */
9855 diff --git a/main.c b/main.c
9856 index cf0ffd8..c356b75 100644
9857 --- a/main.c
9858 +++ b/main.c
9859 @@ -14,7 +14,7 @@
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.
9863 -
9864 + *
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,
9868 @@ -22,37 +22,87 @@
9869   * FITNESS FOR A PARTICULAR PURPOSE.
9870  */
9871  
9872 +
9873  #include "tac_plus.h"
9874 -#include "sys/wait.h"
9875 -#include "signal.h"
9876 +
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>
9885 +#include <netdb.h>
9886 +#include <errno.h>
9887 +#ifdef HAVE_SYS_TIME_H
9888 +#include <sys/time.h>
9889 +#endif
9890 +#ifdef HAVE_UNISTD_H
9891 +#include <unistd.h>
9892 +#endif
9893 +#ifdef HAVE_SYSLOG_H
9894 +#include <syslog.h>
9895 +#endif
9896 +#ifdef HAVE_SYS_SYSLOG_H
9897 +#include <sys/syslog.h>
9898 +#endif
9899 +#ifdef HAVE_FCNTL_H
9900 +#include <fcntl.h>
9901 +#endif
9902 +#ifdef HAVE_SYS_IOCTL_H
9903 +#include <sys/ioctl.h>
9904 +#endif
9905 +
9906 +#include "main.h"
9907 +#include "report.h"
9908 +#include "utils.h"
9909 +#include "cfgfile.h"
9910 +#include "packet.h"
9911 +#include "dump.h"
9912 +#include "author.h"
9913 +#include "acct.h"
9914 +#include "authen.h"
9915 +#include "do_acct.h"
9916 +#include "parse.h"
9917 +
9918 +#ifdef MAXSESS
9919 +#include "maxsess.h"
9920 +#endif
9921 +
9922 +
9923 +static void version TAC_ARGS((void));
9924 +static void start_session TAC_ARGS((void));
9925 +
9926 +
9927 +/* Configurable:
9928 + */
9929 +
9930 +#ifndef TAC_PLUS_PORT
9931 +#define        TAC_PLUS_PORT                   49
9932 +#endif
9933 +
9934  
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;
9946 -
9947 -struct timeval started_at;
9948  
9949  struct session session;     /* session data */
9950  
9951  static char pidfilebuf[75]; /* holds current name of the pidfile */
9952  
9953 -void start_session();
9954  
9955  #ifndef REAPCHILD
9956 -static
9957 -#ifdef VOIDSIG
9958 -void 
9959 -#else
9960 -int
9961 -#endif /* VOIDSIG */
9962 -reapchild()
9963 +static RETSIGTYPE reapchild TAC_ARGS((int signo));
9964 +
9965 +static RETSIGTYPE
9966 +reapchild(signo)
9967 +int signo;
9968  {
9969  #ifdef UNIONWAIT
9970      union wait status;
9971 @@ -61,6 +111,8 @@ reapchild()
9972  #endif
9973      int pid;
9974  
9975 +    signal(SIGCHLD, reapchild);
9976 +
9977      for (;;) {
9978         pid = wait3(&status, WNOHANG, 0);
9979         if (pid <= 0)
9980 @@ -71,6 +123,8 @@ reapchild()
9981  }
9982  #endif /* REAPCHILD */
9983  
9984 +static void die TAC_ARGS((int signum));
9985 +
9986  static void
9987  die(signum)
9988  int signum;
9989 @@ -80,6 +134,8 @@ int signum;
9990      tac_exit(0);
9991  }
9992  
9993 +static void init TAC_ARGS((void));
9994 +
9995  static void
9996  init()
9997  {
9998 @@ -104,26 +160,59 @@ init()
9999  
10000      initialised++;
10001  
10002 -    report(LOG_INFO, "Version %s Initialized %d", VERSION, initialised);
10003 +    report(LOG_INFO, "Version %s%s Initialized %d", VERSION, VERSION_TAIL, initialised);
10004  
10005  }
10006  
10007 -static void
10008 +/* 'handler()' will be called during initialization to setup signal handler,
10009 + * keep it in mind when modifying it!
10010 + */
10011 +
10012 +static int handler_occured = 0;
10013 +
10014 +static RETSIGTYPE handler TAC_ARGS((int signum));
10015 +
10016 +static RETSIGTYPE
10017  handler(signum)
10018  int signum;
10019  {
10020 -    report(LOG_INFO, "Received signal %d", signum);
10021 -    init();
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
10026 +     */
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);
10033 +
10034 +    /* DON'T interrupt! */
10035 +#ifdef HAVE_SIGINTERRUPT
10036 +    siginterrupt(SIGUSR1, 0 /* flag */);
10037 +    siginterrupt(SIGHUP , 0 /* flag */);
10038 +#endif
10039 +}
10040 +
10041 +static void check_handler_occured TAC_ARGS((void));
10042 +
10043 +static RETSIGTYPE
10044 +check_handler_occured()
10045 +{
10046 +
10047 +    if (!handler_occured)
10048 +       return;
10049 +
10050 +    handler_occured = 0;
10051 +    report(LOG_INFO, "Signal detected, reloading configuration");
10052 +    init();
10053  }
10054  
10055  /*
10056   * Return a socket bound to an appropriate port number/address. Exits
10057   * the program on failure */
10058  
10059 +static int get_socket TAC_ARGS((void));
10060 +
10061 +static int
10062  get_socket()
10063  {
10064      int s;
10065 @@ -171,6 +260,8 @@ get_socket()
10066      return (s);
10067  }
10068  
10069 +static void open_logfile TAC_ARGS((void));
10070 +
10071  static void
10072  open_logfile()
10073  {
10074 @@ -182,6 +273,29 @@ open_logfile()
10075      setlogmask(LOG_UPTO(LOG_DEBUG));
10076  }
10077  
10078 +static void prep_session_peer TAC_ARGS((const struct sockaddr_in *from));
10079 +
10080 +static void
10081 +prep_session_peer(from)
10082 +const struct sockaddr_in *from;
10083 +{
10084 +    struct hostent *hp;
10085 +
10086 +    if (session.peer_addr && session.peer_addr != session.peer)
10087 +       free(session.peer_addr);
10088 +    if (session.peer)
10089 +       free(session.peer);
10090 +
10091 +    session.peer_addr = tac_strdup( (char *) inet_ntoa(from->sin_addr) );
10092 +
10093 +    hp = gethostbyaddr((char *) &from->sin_addr.s_addr, sizeof(from->sin_addr.s_addr), AF_INET);
10094 +
10095 +    if (hp)
10096 +       session.peer = tac_strdup(hp->h_name);
10097 +    else
10098 +       session.peer = session.peer_addr;
10099 +}
10100 +
10101  /*
10102   * main
10103   *
10104 @@ -189,6 +303,9 @@ open_logfile()
10105   * Parse arguments and act appropiately.
10106   */
10107  
10108 +int main TAC_ARGS((int argc, char **argv));
10109 +
10110 +int
10111  main(argc, argv)
10112  int argc;
10113  char **argv;
10114 @@ -214,6 +331,10 @@ char **argv;
10115      port = TAC_PLUS_PORT;
10116  #endif
10117  
10118 +#ifdef MAINTAINER_MODE
10119 +    session.cfgfile = "/etc/tacacs/tac_plus.cfg";
10120 +#endif
10121 +
10122      if (argc <= 1) {
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;
10126  
10127      init();
10128  
10129 -    signal(SIGUSR1, handler);
10130 -    signal(SIGHUP, handler);
10131 +    handler(-1 /* signum */);          /* connect to the signals */
10132 +    handler_occured = 0;               /* post-fix cludge */
10133 +
10134      signal(SIGTERM, die);
10135      signal(SIGPIPE, SIG_IGN);
10136  
10137 @@ -293,31 +415,27 @@ char **argv;
10138         tac_exit(0);
10139  
10140      if (debug)
10141 -       report(LOG_DEBUG, "tac_plus server %s starting", VERSION);
10142 +       report(LOG_DEBUG, "tac_plus server %s%s starting", VERSION, VERSION_TAIL);
10143  
10144      if (!standalone) {
10145         /* running under inetd */
10146         struct sockaddr_in name;
10147 -       int name_len;
10148 -       int on = 1;
10149 +       socklen_t name_len;
10150 +#ifdef FIONBIO
10151 +       int fionbio_on = 1;
10152 +#endif
10153  
10154         name_len = sizeof(name);
10155  
10156 -       session.sock = 0;
10157         if (getpeername(session.sock, (struct sockaddr *) &name, &name_len)) {
10158             report(LOG_ERR, "getpeername failure %s", sys_errlist[errno]);
10159 -       } else {
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);
10165 -           }
10166 -           session.peer = tac_strdup(hp ? hp->h_name : 
10167 -                                 (char *) inet_ntoa(name.sin_addr));
10168 -       }
10169 +           prep_session_peer(NULL);
10170 +       } else
10171 +           prep_session_peer(&name);
10172 +
10173 +       session.sock = 0;
10174  #ifdef FIONBIO
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]);
10178             tac_exit(1);
10179         }
10180 @@ -351,23 +469,29 @@ char **argv;
10181  
10182  #ifndef REAPCHILD
10183  
10184 -#ifdef LINUX
10185 +#ifdef SETPGRP_VOID
10186         if (setpgrp() == -1)
10187 -#else /* LINUX */
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");
10193  
10194 +#ifdef TIOCNOTTY
10195         c = open("/dev/tty", O_RDWR);
10196         if (c >= 0) {
10197             ioctl(c, TIOCNOTTY, (char *) 0);
10198             (void) close(c);
10199         }
10200 +#endif
10201         signal(SIGCHLD, reapchild);
10202  
10203  #else /* REAPCHILD */
10204  
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");
10211  
10212         signal(SIGHUP, SIG_IGN);
10213 @@ -423,7 +547,7 @@ char **argv;
10214  
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());
10219         fclose(fp);
10220      } else
10221         report(LOG_ERR, "Cannot write pid to %s %s",
10222 @@ -446,38 +570,45 @@ char **argv;
10223  #endif /* MAXSESS */
10224  
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);
10228  
10229      for (;;) {
10230         int pid;
10231         struct sockaddr_in from;
10232 -       int from_len;
10233 +       socklen_t from_len;
10234         int newsockfd;
10235 -       struct hostent *hp = NULL;
10236 +
10237 +       check_handler_occured();
10238  
10239         bzero((char *) &from, sizeof(from));
10240         from_len = sizeof(from);
10241  
10242 +       /* PERMIT interrupt of accept()! */
10243 +#ifdef HAVE_SIGINTERRUPT
10244 +       siginterrupt(SIGUSR1, 1 /* flag */);
10245 +       siginterrupt(SIGHUP , 1 /* flag */);
10246 +#endif
10247 +
10248 +       errno = 0;
10249         newsockfd = accept(s, (struct sockaddr *) &from, &from_len);
10250  
10251 +       /* DON'T interrupt! */
10252 +#ifdef HAVE_SIGINTERRUPT
10253 +       siginterrupt(SIGUSR1, 0 /* flag */);
10254 +       siginterrupt(SIGHUP , 0 /* flag */);
10255 +#endif
10256 +
10257 +       check_handler_occured();
10258 +
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)
10263                 continue;
10264  
10265             report(LOG_ERR, "accept: %s", sys_errlist[errno]);
10266             continue;
10267         }
10268 -
10269 -       if (lookup_peer) {
10270 -           hp = gethostbyaddr((char *) &from.sin_addr.s_addr,
10271 -                              sizeof(from.sin_addr.s_addr), AF_INET);
10272 -       }
10273 -
10274 -       if (session.peer) {
10275 -           free(session.peer);
10276 -       }
10277 -       session.peer = tac_strdup(hp ? hp->h_name : 
10278 -                                 (char *) inet_ntoa(from.sin_addr));
10279 +       prep_session_peer(&from);
10280  
10281         if (debug & DEBUG_PACKET_FLAG)
10282             report(LOG_DEBUG, "session request from %s sock=%d",
10283 @@ -521,8 +652,10 @@ getdtablesize()
10284  }
10285  #endif /* GETDTABLESIZE */
10286  
10287 +static int bad_version_check TAC_ARGS((u_char *pak));
10288 +
10289  /* Make sure version number is kosher. Return 0 if it is */
10290 -int
10291 +static int
10292  bad_version_check(pak)
10293  u_char *pak;
10294  {
10295 @@ -555,17 +688,21 @@ u_char *pak;
10296   *
10297   */
10298  
10299 -void
10300 +static void start_session TAC_ARGS((void));
10301 +
10302 +static void
10303  start_session()
10304  {
10305 -    u_char *pak, *read_packet();
10306 +    u_char *pak;
10307      HDR *hdr;
10308 -    void authen();
10309  
10310      session.seq_no = 0;
10311      session.aborted = 0;
10312      session.version = 0;
10313  
10314 +    /* Now we are starting our new 'request' cycle */
10315 +    cfg_request_scan_begin();
10316 +
10317      pak = read_packet();
10318      if (!pak) {
10319         return;
10320 @@ -608,9 +745,12 @@ start_session()
10321      }
10322  }
10323  
10324 +static void version TAC_ARGS((void));
10325 +
10326 +static void
10327  version()
10328  {
10329 -    fprintf(stdout, "tac_plus version %s\n", VERSION);
10330 +    fprintf(stdout, "tac_plus version %s%s\n", VERSION, VERSION_TAIL);
10331  #ifdef AIX
10332      fprintf(stdout,"AIX\n");
10333  #endif
10334 @@ -644,9 +784,6 @@ version()
10335  #ifdef LINUX
10336      fprintf(stdout,"LINUX\n");
10337  #endif
10338 -#ifdef LITTLE_ENDIAN
10339 -    fprintf(stdout,"LITTLE_ENDIAN\n");
10340 -#endif
10341  #ifdef LOG_LOCAL6
10342      fprintf(stdout,"LOG_LOCAL6\n");
10343  #endif
10344 @@ -662,15 +799,9 @@ version()
10345  #ifdef NETBSD
10346      fprintf(stdout,"NETBSD\n");
10347  #endif
10348 -#ifdef NO_PWAGE
10349 -    fprintf(stdout,"NO_PWAGE\n");
10350 -#endif
10351  #ifdef REAPCHILD
10352      fprintf(stdout,"REAPCHILD\n");
10353  #endif
10354 -#ifdef REARMSIGNAL
10355 -    fprintf(stdout,"REARMSIGNAL\n");
10356 -#endif
10357  #ifdef SHADOW_PASSWORDS
10358      fprintf(stdout,"SHADOW_PASSWORDS\n");
10359  #endif
10360 @@ -692,14 +823,8 @@ version()
10361  #ifdef SO_REUSEADDR
10362      fprintf(stdout,"SO_REUSEADDR\n");
10363  #endif
10364 -#ifdef STDLIB_MALLOC
10365 -    fprintf(stdout,"STDLIB_MALLOC\n");
10366 -#endif
10367 -#ifdef STRCSPN
10368 -    fprintf(stdout,"STRCSPN\n");
10369 -#endif
10370 -#ifdef SYSLOG_IN_SYS
10371 -    fprintf(stdout,"SYSLOG_IN_SYS\n");
10372 +#ifdef HAVE_STRCSPN
10373 +    fprintf(stdout,"HAVE_STRCSPN\n");
10374  #endif
10375  #ifdef SYSV
10376      fprintf(stdout,"SYSV\n");
10377 @@ -713,15 +838,9 @@ version()
10378  #ifdef TACPLUS_USERID
10379      fprintf(stdout,"TACPLUS_USERID\n");
10380  #endif
10381 -#ifdef TRACE
10382 -    fprintf(stdout,"TRACE\n");
10383 -#endif
10384  #ifdef UNIONWAIT
10385      fprintf(stdout,"UNIONWAIT\n");
10386  #endif
10387 -#ifdef VOIDSIG
10388 -    fprintf(stdout,"VOIDSIG\n");
10389 -#endif
10390  #ifdef _BSD1
10391      fprintf(stdout,"_BSD1\n");
10392  #endif
10393 diff --git a/main.h b/main.h
10394 new file mode 100644
10395 index 0000000..79c643a
10396 --- /dev/null
10397 +++ b/main.h
10398 @@ -0,0 +1,59 @@
10399 +#ifndef MAIN_H
10400 +#define MAIN_H 1
10401 +
10402 +#include "tac_plus.h"
10403 +
10404 +#include <sys/types.h>         /* for u_* */
10405 +
10406 +
10407 +#define NAS_PORT_MAX_LEN                255
10408 +
10409 +struct session {
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 */
10425 +};
10426 +
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 */
10432 +
10433 +/* Debugging flags */
10434 +
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
10451 +
10452 +
10453 +extern struct session session;     /* the session */
10454 +extern int main TAC_ARGS((int argc, char **argv));
10455 +
10456 +
10457 +#endif /* MAIN_H */
10458 diff --git a/maxsess.c b/maxsess.c
10459 index 83e0815..aa81a9a 100644
10460 --- a/maxsess.c
10461 +++ b/maxsess.c
10462 @@ -17,9 +17,62 @@
10463     FITNESS FOR A PARTICULAR PURPOSE.
10464  */
10465  
10466 +
10467  #include "tac_plus.h"
10468  
10469  #ifdef MAXSESS
10470 +
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>
10480 +#endif
10481 +#include <string.h>
10482 +#include <errno.h>
10483 +#ifdef HAVE_SYS_TIME_H
10484 +#include <sys/time.h>
10485 +#endif
10486 +#ifdef HAVE_UNISTD_H
10487 +#include <unistd.h>
10488 +#endif
10489 +#include <netdb.h>
10490 +
10491 +#include "maxsess.h"
10492 +#include "report.h"
10493 +#include "utils.h"
10494 +#include "cfgfile.h"
10495 +#include "main.h"
10496 +#include "do_acct.h"
10497 +#include "parse.h"
10498 +
10499 +
10500 +void maxsess_loginit TAC_ARGS((void));
10501 +
10502 +
10503 +/* Configurable:
10504 + */
10505 +
10506 +/* This is a shared file used to maintain a record of who's on
10507 + */
10508 +#define WHOLOG_DEFAULT "/var/log/tac_who.log"
10509 +
10510 +
10511 +/*
10512 + * This is state kept per user/session
10513 + */
10514 +struct peruser {
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 */
10519 +};
10520 +
10521 +
10522  char *wholog = WHOLOG_DEFAULT;
10523  /*
10524   * initialize wholog file for tracking of user logins/logouts from
10525 @@ -41,6 +94,8 @@ maxsess_loginit()
10526      }
10527  }
10528  
10529 +static char *portname TAC_ARGS((char *oldport));
10530 +
10531  /*
10532   * Given a port description, return it in a canonical format.
10533   *
10534 @@ -67,6 +122,8 @@ char *oldport;
10535      return (p);
10536  }
10537  
10538 +static void write_record TAC_ARGS((char *name, FILE *fp, void *buf, int size, long int offset));
10539 +
10540  /*
10541   * Seek to offset and write a buffer into the file pointed to by fp
10542   */
10543 @@ -79,7 +136,7 @@ void *buf;
10544  char *name;
10545  {
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]);
10550      }
10551      if (fwrite(buf, size, 1, fp) != 1) {
10552 @@ -88,6 +145,8 @@ char *name;
10553      }
10554  }
10555  
10556 +static void process_stop_record TAC_ARGS((struct identity *idp));
10557 +
10558  static void
10559  process_stop_record(idp)
10560  struct identity *idp;
10561 @@ -133,6 +192,8 @@ struct identity *idp;
10562      fclose(fp);
10563  }
10564  
10565 +static void process_start_record TAC_ARGS((struct identity *idp));
10566 +
10567  static void
10568  process_start_record(idp)
10569  struct identity *idp;
10570 @@ -215,10 +276,13 @@ struct identity *idp;
10571  }
10572  
10573  
10574 +void loguser TAC_ARGS((struct acct_rec *rec));
10575 +
10576  /*
10577   * Given a start or a stop accounting record, update the file of
10578   * records which tracks who's logged on and where.
10579   */
10580 +void
10581  loguser(rec)
10582  struct acct_rec *rec;
10583  {
10584 @@ -260,10 +324,12 @@ struct acct_rec *rec;
10585   * Return -1 on error, eof or timeout. Otherwise return number of
10586   * bytes read. */
10587  
10588 -int
10589 +static int timed_read TAC_ARGS((int fd, void *ptr, int nbytes, int timeout));
10590 +
10591 +static int
10592  timed_read(fd, ptr, nbytes, timeout)
10593  int fd;
10594 -u_char *ptr;
10595 +void *ptr;
10596  int nbytes;
10597  int timeout;
10598  {
10599 @@ -348,6 +414,8 @@ int timeout;
10600   * with a maximum possible width of 10.
10601   */
10602  
10603 +static int ckfinger TAC_ARGS((char *user, char *nas, struct identity *idp));
10604 +
10605  static int
10606  ckfinger(user, nas, idp)
10607  char *user, *nas;
10608 @@ -372,7 +440,7 @@ struct identity *idp;
10609  
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;
10618      return (count);
10619  }
10620  
10621 +static int countusers_by_finger TAC_ARGS((struct identity *idp));
10622 +
10623  /*
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;
10627      return (nsess);
10628  }
10629  
10630 +static int countuser TAC_ARGS((struct identity *idp));
10631 +
10632  /*
10633   * Estimate how many sessions a named user currently owns by looking in
10634   * the wholog file.
10635 @@ -604,6 +676,8 @@ struct identity *idp;
10636      return (nsess);
10637  }
10638  
10639 +static int is_async TAC_ARGS((char *portname));
10640 +
10641  /*
10642   * is_async()
10643   * Tell if the named NAS port is an async-like device.
10644 @@ -622,6 +696,8 @@ char *portname;
10645      return (0);
10646  }
10647  
10648 +int maxsess_check_count TAC_ARGS((char *user, struct author_data *data));
10649 +
10650  /*
10651   * See if this user can have more sessions.
10652   */
10653 @@ -636,7 +712,7 @@ struct author_data *data;
10654      /* No max session configured--don't check */
10655      id = data->id;
10656  
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);
10659      if (!maxsess) {
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;
10663  
10664  #else /* MAXSESS */
10665  
10666 -/*
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
10671 - */
10672 -
10673 -static int dummy = 0;
10674 +TAC_SOURCEFILE_EMPTY
10675  
10676  #endif /* MAXSESS */
10677 diff --git a/maxsess.h b/maxsess.h
10678 new file mode 100644
10679 index 0000000..c96d2b8
10680 --- /dev/null
10681 +++ b/maxsess.h
10682 @@ -0,0 +1,25 @@
10683 +#ifndef MAXSESS_H
10684 +#define MAXSESS_H 1
10685 +
10686 +#include "tac_plus.h"
10687 +
10688 +#ifdef MAXSESS
10689 +
10690 +#include "do_author.h"
10691 +
10692 +
10693 +/* This is a shared file used to maintain a record of who's on
10694 + */
10695 +extern char *wholog;
10696 +
10697 +
10698 +struct acct_rec;
10699 +
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));
10703 +
10704 +
10705 +#endif /* MAXSESS */
10706 +
10707 +#endif /* MAXSESS_H */
10708 diff --git a/md4.c b/md4.c
10709 index d99c84c..5ac377d 100644
10710 --- a/md4.c
10711 +++ b/md4.c
10712 @@ -43,19 +43,27 @@
10713   */
10714  
10715  
10716 +#include "tac_plus.h"
10717 +
10718 +#ifdef MSCHAP
10719 +
10720  #include <string.h>
10721 +
10722  #include "md4.h"
10723  /*
10724  #include "master.h"
10725  #include <ciscolib.h>
10726  */
10727  
10728 +
10729  typedef unsigned char *POINTER;
10730  typedef unsigned short int UINT2;
10731  typedef unsigned long int UINT4;
10732  
10733 -#define PROTO_LIST(list) ()
10734 -#define const 
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));
10738 +
10739  
10740  /* Constants for MD4Transform routine.
10741   */
10742 @@ -72,12 +80,6 @@ typedef unsigned long int UINT4;
10743  #define S33 11
10744  #define S34 15
10745  
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));
10751 -
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] = {
10756  
10757  /* MD4 initialization. Begins an MD4 operation, writing a new context.
10758   */
10759 +
10760 +void MD4Init TAC_ARGS((MD4_CTX *context));
10761 +
10762  void MD4Init (context)
10763  MD4_CTX *context;                                        /* context */
10764  {
10765 @@ -128,6 +133,9 @@ MD4_CTX *context;                                        /* context */
10766       operation, processing another message block, and updating the
10767       context.
10768   */
10769 +
10770 +void MD4Update TAC_ARGS((MD4_CTX *context, const unsigned char *input, unsigned int inputLen));
10771 +
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.
10778   */
10779 +
10780 +void MD4Final TAC_ARGS((unsigned char digest[16], MD4_CTX *context));
10781 +
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 */
10786  
10787  /* MD4 basic transformation. Transforms state based on block.
10788   */
10789 +
10790 +static void MD4Transform TAC_ARGS((UINT4 state[4], const unsigned char block[64]));
10791 +
10792  static void MD4Transform (state, block)
10793  UINT4 state[4];
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
10797       a multiple of 4.
10798   */
10799 +
10800 +static void Encode TAC_ARGS((unsigned char *output, UINT4 *input, unsigned int len));
10801 +
10802  static void Encode (output, input, len)
10803  unsigned char *output;
10804  UINT4 *input;
10805 @@ -289,8 +306,10 @@ unsigned int len;
10806  /* Decodes input (unsigned char) into output (UINT4). Assumes len is
10807       a multiple of 4.
10808   */
10809 -static void Decode (output, input, len)
10810  
10811 +static void Decode TAC_ARGS((UINT4 *output, const unsigned char *input, unsigned int len));
10812 +
10813 +static void Decode (output, input, len)
10814  UINT4 *output;
10815  const unsigned char *input;
10816  unsigned int len;
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);
10820  }
10821 +
10822 +#else /* MSCHAP */
10823 +
10824 +TAC_SOURCEFILE_EMPTY
10825 +
10826 +#endif /* MSCHAP */
10827 diff --git a/md4.h b/md4.h
10828 index d821229..38d0a81 100644
10829 --- a/md4.h
10830 +++ b/md4.h
10831 @@ -1,3 +1,10 @@
10832 +#ifndef MD4_H
10833 +#define MD4_H 1
10834 +
10835 +#include "tac_plus.h"
10836 +
10837 +#ifdef MSCHAP
10838 +
10839  /*
10840     Copyright (c) 1995-1998 by Cisco systems, Inc.
10841  
10842 @@ -42,8 +49,6 @@
10843     documentation and/or software.
10844   */
10845  
10846 -#ifndef _MD4_H_
10847 -#define _MD4_H_
10848  /* MD4 context. */
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 */
10853  } MD4_CTX;
10854  
10855 -void   MD4Init();
10856 -void   MD4Update();
10857 -void   MD4Final();
10858 -char * MD4End();
10859 -char * MD4File();
10860 -char * MD4Data();
10861  
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));
10866 +
10867 +
10868 +#endif /* MSCHAP */
10869 +
10870 +#endif /* MD4_H */
10871 diff --git a/md5.c b/md5.c
10872 index 06225b0..32ca404 100644
10873 --- a/md5.c
10874 +++ b/md5.c
10875 @@ -47,12 +47,20 @@
10876   * to contain all the information that RFC 1321's global.h contains.
10877   */
10878  
10879 +
10880 +#include "tac_plus.h"
10881 +
10882  #include "md5.h"
10883  
10884 +
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));
10888 +
10889 +
10890  /* Constants for MD5Transform routine.
10891   */
10892  
10893 -
10894  #define S11 7
10895  #define S12 12
10896  #define S13 17
10897 @@ -70,24 +78,6 @@
10898  #define S43 15
10899  #define S44 21
10900  
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));
10906 -
10907 -#if !defined(MD5_NEED_MEM_FUNCS)
10908 -
10909 -#define MD5_memcpy(out,in,len) memcpy(out, in, len)
10910 -#define MD5_memset(ptr,val,len) memset(ptr, val, len)
10911 -
10912 -#else                          /* !defined(MD5_NEED_MEM_FUNCS) */
10913 -
10914 -static void MD5_memcpy PROTO_LIST((POINTER, POINTER, unsigned int));
10915 -static void MD5_memset PROTO_LIST((POINTER, int, unsigned int));
10916 -
10917 -#endif                         /* !defined(MD5_NEED_MEM_FUNCS) */
10918 -
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.
10923   (a) += (b); \
10924    }
10925  
10926 +void MD5Init TAC_ARGS((MD5_CTX *context));
10927 +
10928  /* MD5 initialization. Begins an MD5 operation, writing a new context.
10929   */
10930  void
10931 @@ -143,6 +135,8 @@ MD5_CTX *context;           /* context */
10932      context->state[3] = 0x10325476;
10933  }
10934  
10935 +void MD5Update TAC_ARGS((MD5_CTX *context, unsigned char *input, unsigned int inputLen));
10936 +
10937  /* MD5 block update operation. Continues an MD5 message-digest
10938     operation, processing another message block, and updating the
10939     context.
10940 @@ -168,8 +162,7 @@ unsigned int inputLen;              /* length of input block */
10941  
10942      /* Transform as many times as possible. */
10943      if (inputLen >= partLen) {
10944 -       MD5_memcpy
10945 -           ((POINTER) & context->buffer[index], (POINTER) input, partLen);
10946 +       memcpy((POINTER) & context->buffer[index], (POINTER) input, partLen);
10947         MD5Transform(context->state, context->buffer);
10948  
10949         for (i = partLen; i + 63 < inputLen; i += 64)
10950 @@ -180,11 +173,12 @@ unsigned int inputLen;            /* length of input block */
10951         i = 0;
10952  
10953      /* Buffer remaining input */
10954 -    MD5_memcpy
10955 -       ((POINTER) & context->buffer[index], (POINTER) & input[i],
10956 +    memcpy((POINTER) & context->buffer[index], (POINTER) & input[i],
10957         inputLen - i);
10958  }
10959  
10960 +void MD5Final TAC_ARGS((unsigned char *digest, MD5_CTX *context));
10961 +
10962  /* MD5 finalization. Ends an MD5 message-digest operation, writing the
10963     the message digest and zeroizing the context.
10964     */
10965 @@ -211,9 +205,11 @@ MD5_CTX *context;          /* context */
10966      Encode(digest, context->state, 16);
10967  
10968      /* Zeroize sensitive information. */
10969 -    MD5_memset((POINTER) context, 0, sizeof(*context));
10970 +    memset((POINTER) context, 0, sizeof(*context));
10971  }
10972  
10973 +static void MD5Transform TAC_ARGS((UINT4 *state, unsigned char *block));
10974 +
10975  /* MD5 basic transformation. Transforms state based on block.
10976   */
10977  static void
10978 @@ -303,9 +299,11 @@ unsigned char block[64];
10979      state[3] += d;
10980  
10981      /* Zeroize sensitive information. */
10982 -    MD5_memset((POINTER) x, 0, sizeof(x));
10983 +    memset((POINTER) x, 0, sizeof(x));
10984  }
10985  
10986 +static void Encode TAC_ARGS((unsigned char *output, UINT4 *input, unsigned int len));
10987 +
10988  /* Encodes input (UINT4) into output (unsigned char). Assumes len is
10989     a multiple of 4.
10990     */
10991 @@ -325,6 +323,8 @@ unsigned int len;
10992      }
10993  }
10994  
10995 +static void Decode TAC_ARGS((UINT4 *output, unsigned char *input, unsigned int len));
10996 +
10997  /* Decodes input (unsigned char) into output (UINT4). Assumes len is
10998     a multiple of 4.
10999     */
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);
11003  }
11004 -
11005 -#if defined(MD5_NEED_MEM_FUNC)
11006 -
11007 -/* Note: Replace "for loop" with standard memcpy if possible.
11008 - */
11009 -static void
11010 -MD5_memcpy(output, input, len)
11011 -POINTER output;
11012 -POINTER input;
11013 -unsigned int len;
11014 -{
11015 -    unsigned int i;
11016 -
11017 -    for (i = 0; i < len; i++)
11018 -       output[i] = input[i];
11019 -}
11020 -
11021 -
11022 -/* Note: Replace "for loop" with standard memset if possible.
11023 - */
11024 -static void
11025 -MD5_memset(output, value, len)
11026 -POINTER output;
11027 -int value;
11028 -unsigned int len;
11029 -{
11030 -    unsigned int i;
11031 -
11032 -    for (i = 0; i < len; i++)
11033 -       ((char *) output)[i] = (char) value;
11034 -}
11035 -
11036 -#endif                         /* defined(MD5_NEED_MEM_FUNC) */
11037 diff --git a/md5.h b/md5.h
11038 index 097156e..90f9021 100644
11039 --- a/md5.h
11040 +++ b/md5.h
11041 @@ -1,3 +1,8 @@
11042 +#ifndef MD5_H
11043 +#define MD5_H 1
11044 +
11045 +#include "tac_plus.h"
11046 +
11047  /*
11048     Copyright (c) 1995-1998 by Cisco systems, Inc.
11049  
11050 @@ -44,8 +49,6 @@
11051   * documentation and/or software.
11052   */
11053  
11054 -#ifndef _MD5_H
11055 -#define _MD5_H
11056  
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)
11061  
11062  /* typedef a 32-bit type */
11063 -typedef unsigned long int UINT4;
11064 +typedef tac_uint32 UINT4;
11065  
11066  /* typedef a generic pointer type */
11067  typedef unsigned char *POINTER;
11068  
11069 -/* enable prototyping */
11070 -/* #define PROTO_LIST(x) x */
11071 -/* disable prototyping */
11072 -#define PROTO_LIST(x) ()
11073 -
11074  #endif /* defined(CISCO_MD5_MODS) */
11075  
11076  /* MD5 context. */
11077 @@ -72,10 +70,10 @@ typedef struct {
11078    unsigned char buffer[64];                         /* input buffer */
11079  } MD5_CTX;
11080  
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 *));
11085 +
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));
11089  
11090  
11091 -#endif                          /* _MD5_H */
11092 +#endif /* MD5_H */
11093 diff --git a/mschap.h b/mschap.h
11094 index 192d9d2..d98b84b 100644
11095 --- a/mschap.h
11096 +++ b/mschap.h
11097 @@ -1,3 +1,8 @@
11098 +#ifndef MSCHAP_H
11099 +#define MSCHAP_H 1
11100 +
11101 +#include "tac_plus.h"
11102 +
11103  /*
11104     Copyright (c) 1995-1998 by Cisco systems, Inc.
11105  
11106 @@ -17,4 +22,8 @@
11107     FITNESS FOR A PARTICULAR PURPOSE.
11108  */
11109  
11110 +
11111  #define MSCHAP_KEY "Contact Microsoft for the MSCHAP key"
11112 +
11113 +
11114 +#endif /* MSCHAP_H */
11115 diff --git a/packet.c b/packet.c
11116 index f3f7023..2e003d1 100644
11117 --- a/packet.c
11118 +++ b/packet.c
11119 @@ -17,14 +17,51 @@
11120     FITNESS FOR A PARTICULAR PURPOSE.
11121  */
11122  
11123 +
11124  #include "tac_plus.h"
11125  
11126 +#include <stdlib.h>
11127 +#include <netinet/in.h>                /* for ntohl() */
11128 +#include <errno.h>
11129 +#include <time.h>
11130 +#ifdef HAVE_SYS_TIME_H
11131 +#include <sys/time.h>
11132 +#endif
11133 +#include <sys/types.h>
11134 +#ifdef HAVE_UNISTD_H
11135 +#include <unistd.h>
11136 +#endif
11137 +
11138 +#include "packet.h"
11139 +#include "utils.h"
11140 +#include "report.h"
11141 +#include "dump.h"
11142 +#include "cfgfile.h"
11143 +#include "encrypt.h"
11144 +#include "main.h"
11145 +#include "do_author.h"
11146 +
11147 +
11148 +static int write_packet TAC_ARGS((u_char *pak));
11149 +
11150 +
11151 +/* Configurable:
11152 + */
11153 +
11154 +#define TAC_PLUS_READ_TIMEOUT          180     /* seconds */
11155 +#define TAC_PLUS_WRITE_TIMEOUT         180     /* seconds */
11156 +
11157 +
11158  /* Everything to do with reading and writing packets */
11159  
11160 +void send_acct_reply TAC_ARGS((unsigned status, const char *msg, const char *data));
11161 +
11162  /* send an accounting response packet */
11163 +void
11164  send_acct_reply(status, msg, data)
11165 -    u_char status;
11166 -    char *msg, *data;
11167 +unsigned status;                       /* promoted "u_char" type */
11168 +const char *msg;
11169 +const char *data;
11170  {
11171      u_char *pak, *p;
11172      HDR *hdr;
11173 @@ -73,13 +110,16 @@ send_acct_reply(status, msg, data)
11174      free(pak);
11175  }
11176  
11177 +void send_author_reply TAC_ARGS((unsigned status, const char *msg, const char *data, int arg_cnt, /* const */ char **args));
11178 +
11179  /* send an authorization reply packet */
11180 +void
11181  send_author_reply(status, msg, data, arg_cnt, args)
11182 -u_char status;
11183 -char *msg;
11184 -char *data;
11185 +unsigned status;                       /* promoted "u_char" type */
11186 +const char *msg;
11187 +const char *data;
11188  int arg_cnt;
11189 -char **args;
11190 +/* const */ char **args;
11191  {
11192      u_char *pak, *p;
11193      HDR *hdr;
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 */
11197  
11198 +void send_authen_error TAC_ARGS((const char *msg));
11199 +
11200 +void
11201  send_authen_error(msg)
11202 -char *msg;
11203 +const char *msg;
11204  {
11205      char buf[255];
11206  
11207 @@ -176,13 +219,16 @@ char *msg;
11208  
11209  /* create and send an authentication reply packet from tacacs+ to a NAS */
11210  
11211 +void send_authen_reply TAC_ARGS((int status, const char *msg, unsigned msg_len, const unsigned char *data, unsigned data_len, unsigned flags));
11212 +
11213 +void
11214  send_authen_reply(status, msg, msg_len, data, data_len, flags)
11215  int status;
11216 -char *msg;
11217 -u_short msg_len;
11218 -char *data;
11219 -u_short data_len;
11220 -u_char flags;
11221 +const char *msg;
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 */
11226  {
11227      u_char *pak, *p;
11228      HDR *hdr;
11229 @@ -228,12 +274,14 @@ u_char flags;
11230  }
11231  
11232  
11233 +u_char *get_authen_continue TAC_ARGS((void));
11234 +
11235  /* read an authentication GETDATA packet from a NAS. Return 0 on failure */
11236  u_char *
11237  get_authen_continue()
11238  {
11239      HDR *hdr;
11240 -    u_char *pak, *read_packet();
11241 +    u_char *pak;
11242      struct authen_cont *cont;
11243      char msg[255];
11244  
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);
11248  
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
11261   * bytes read. */
11262  
11263 -int
11264 +static int sockread TAC_ARGS((int fd, u_char *ptr, int nbytes, int timeout));
11265 +
11266 +static int
11267  sockread(fd, ptr, nbytes, timeout)
11268  int fd;
11269  u_char *ptr;
11270 @@ -354,7 +404,9 @@ int timeout;
11271   * Return -1 on error, eof or timeout. Otherwise return number of
11272   * bytes written. */
11273  
11274 -int
11275 +static int sockwrite TAC_ARGS((int fd, u_char *ptr, int bytes, int timeout));
11276 +
11277 +static int
11278  sockwrite(fd, ptr, bytes, timeout)
11279  int fd;
11280  u_char *ptr;
11281 @@ -416,16 +468,32 @@ int timeout;
11282      return (bytes - remaining);
11283  }
11284  
11285 +static const char *get_session_key TAC_ARGS((void));
11286 +
11287 +static const char *
11288 +get_session_key()
11289 +{
11290 +    const char *retval = NULL;
11291 +
11292 +    if ((retval = cfg_get_host_key(session.peer_addr)))
11293 +       return (retval);
11294 +    if (session.peer_addr != session.peer
11295 +     && (retval = cfg_get_host_key(session.peer     )))
11296 +       return (retval);
11297 +    return (session.key);
11298 +}
11299 +
11300  /* read a packet from the wire, and decrypt it. Increment the global
11301   seq_no return NULL on failure */
11302  
11303 +u_char *read_packet TAC_ARGS((void));
11304 +
11305  u_char *
11306  read_packet()
11307  {
11308      HDR hdr;
11309      u_char *pkt, *data;
11310      int len;
11311 -    char *tkey;
11312  
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) {
11317         report(LOG_ERR,
11318                "%s: Illegal data size: %lu\n",
11319 -              session.peer, ntohl(hdr.datalength));
11320 +              session.peer, (unsigned long) ntohl(hdr.datalength));
11321         return(NULL);
11322      }
11323      pkt = (u_char *) tac_malloc(len);
11324 @@ -463,9 +531,9 @@ read_packet()
11325      data = pkt + TAC_PLUS_HDR_SIZE;
11326  
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);
11334         return (NULL);
11335      }
11336 @@ -480,10 +548,7 @@ read_packet()
11337      }
11338  
11339      /* decrypt the data portion */
11340 -    if ( !(tkey=(char *)cfg_get_host_key(session.peer)) )
11341 -               tkey = session.key;     
11342 -
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",
11346                session.peer);
11347         return (NULL);
11348 @@ -498,14 +563,16 @@ read_packet()
11349      return (pkt);
11350  }
11351  
11352 +static int write_packet TAC_ARGS((u_char *pak));
11353 +
11354  /* write a packet to the wire, encrypting it */
11355 +static int
11356  write_packet(pak)
11357  u_char *pak;
11358  {
11359      HDR *hdr = (HDR *) pak;
11360      u_char *data;
11361      int len;
11362 -    char *tkey;
11363  
11364      len = TAC_PLUS_HDR_SIZE + ntohl(hdr->datalength);
11365  
11366 @@ -513,10 +580,7 @@ u_char *pak;
11367      data = pak + TAC_PLUS_HDR_SIZE;
11368  
11369      /* encrypt the data portion */
11370 -   if ( !(tkey=(char *)cfg_get_host_key(session.peer)) )
11371 -                tkey = session.key;
11372 -
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);
11376         return (-1);
11377      }
11378 @@ -528,6 +592,9 @@ u_char *pak;
11379      return (0);
11380  }
11381  
11382 +void send_error_reply TAC_ARGS((int type, char *msg));
11383 +
11384 +void
11385  send_error_reply(type, msg)
11386  int type;
11387  char *msg;
11388 diff --git a/packet.h b/packet.h
11389 new file mode 100644
11390 index 0000000..83a4d9c
11391 --- /dev/null
11392 +++ b/packet.h
11393 @@ -0,0 +1,217 @@
11394 +#ifndef PACKET_H
11395 +#define PACKET_H 1
11396 +
11397 +#include "tac_plus.h"
11398 +
11399 +#include <sys/types.h>         /* for u_* */
11400 +
11401 +
11402 +/* All tacacs+ packets have the same header format */
11403 +
11404 +struct tac_plus_pak_hdr {
11405 +    u_char version;
11406 +
11407 +#define TAC_PLUS_MAJOR_VER_MASK 0xf0
11408 +#define TAC_PLUS_MAJOR_VER      0xc0
11409 +
11410 +#define TAC_PLUS_MINOR_VER_0    0x0
11411 +#define TAC_PLUS_VER_0  (TAC_PLUS_MAJOR_VER | TAC_PLUS_MINOR_VER_0)
11412 +
11413 +#define TAC_PLUS_MINOR_VER_1    0x01
11414 +#define TAC_PLUS_VER_1  (TAC_PLUS_MAJOR_VER | TAC_PLUS_MINOR_VER_1)
11415 +
11416 +    u_char type;
11417 +
11418 +#define TAC_PLUS_AUTHEN                        1
11419 +#define TAC_PLUS_AUTHOR                        2
11420 +#define TAC_PLUS_ACCT                  3
11421 +
11422 +    u_char seq_no;             /* packet sequence number */
11423 +    u_char encryption;         /* packet is encrypted or cleartext */
11424 +
11425 +#define TAC_PLUS_ENCRYPTED 0x0         /* packet is encrypted */
11426 +#define TAC_PLUS_CLEAR     0x1         /* packet is not encrypted */
11427 +
11428 +    int session_id;            /* session identifier FIXME: Is this needed? */
11429 +    int datalength;            /* length of encrypted data following this
11430 +                                * header */
11431 +    /* datalength bytes of encrypted data */
11432 +};
11433 +
11434 +#define TAC_PLUS_HDR_SIZE 12
11435 +
11436 +typedef struct tac_plus_pak_hdr HDR;
11437 +
11438 +/* Authentication packet NAS sends to us */
11439 +
11440 +struct authen_start {
11441 +    u_char action;
11442 +
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
11447 +
11448 +    u_char priv_lvl;
11449 +
11450 +#define TAC_PLUS_PRIV_LVL_MIN 0x0
11451 +#define TAC_PLUS_PRIV_LVL_MAX 0xf
11452 +
11453 +    u_char authen_type;
11454 +
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
11459 +#ifdef MSCHAP
11460 +#define TAC_PLUS_AUTHEN_TYPE_MSCHAP 5
11461 +#endif /* MSCHAP */
11462 +
11463 +    u_char service;
11464 +
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
11473 +
11474 +    u_char user_len;
11475 +    u_char port_len;
11476 +    u_char rem_addr_len;
11477 +    u_char data_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> */
11482 +};
11483 +
11484 +#define TAC_AUTHEN_START_FIXED_FIELDS_SIZE 8
11485 +
11486 +/* Authentication continue packet NAS sends to us */
11487 +struct authen_cont {
11488 +    u_short user_msg_len;
11489 +    u_short user_data_len;
11490 +    u_char flags;
11491 +
11492 +#define TAC_PLUS_CONTINUE_FLAG_ABORT 0x1
11493 +
11494 +    /* <user_msg_len bytes of u_char data> */
11495 +    /* <user_data_len bytes of u_char data> */
11496 +};
11497 +
11498 +#define TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE 5
11499 +
11500 +/* Authentication reply packet we send to NAS */
11501 +struct authen_reply {
11502 +    u_char status;
11503 +
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
11512 +
11513 +    u_char flags;
11514 +
11515 +#define TAC_PLUS_AUTHEN_FLAG_NOECHO     0x1
11516 +
11517 +    u_short msg_len;
11518 +    u_short data_len;
11519 +
11520 +    /* <msg_len bytes of char data> */
11521 +    /* <data_len bytes of u_char data> */
11522 +};
11523 +
11524 +#define TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE 6
11525 +
11526 +/* An authorization request packet */
11527 +struct author {
11528 +    u_char authen_method;
11529 +    u_char priv_lvl;
11530 +    u_char authen_type;
11531 +    u_char service;
11532 +
11533 +    u_char user_len;
11534 +    u_char port_len;
11535 +    u_char rem_addr_len;
11536 +    u_char arg_cnt;            /* the number of args */
11537 +
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> */
11543 +};
11544 +
11545 +#define TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE 8
11546 +
11547 +/* An authorization reply packet */
11548 +struct author_reply {
11549 +    u_char status;
11550 +    u_char arg_cnt;
11551 +    u_short msg_len;
11552 +    u_short data_len;
11553 +
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> */
11558 +};
11559 +
11560 +#define TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE 6
11561 +
11562 +struct acct {
11563 +    u_char flags;
11564 +
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
11569 +
11570 +    u_char authen_method;
11571 +    u_char priv_lvl;
11572 +    u_char authen_type;
11573 +    u_char authen_service;
11574 +    u_char user_len;
11575 +    u_char port_len;
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 */
11583 +};
11584 +
11585 +#define TAC_ACCT_REQ_FIXED_FIELDS_SIZE 9
11586 +
11587 +struct acct_reply {
11588 +    u_short msg_len;
11589 +    u_short data_len;
11590 +    u_char status;
11591 +
11592 +#define TAC_PLUS_ACCT_STATUS_SUCCESS 0x1
11593 +#define TAC_PLUS_ACCT_STATUS_ERROR   0x2
11594 +#define TAC_PLUS_ACCT_STATUS_FOLLOW  0x21
11595 +
11596 +};
11597 +
11598 +#define TAC_ACCT_REPLY_FIXED_FIELDS_SIZE 5
11599 +
11600 +
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));
11608 +
11609 +
11610 +#endif /* PACKET_H */
11611 diff --git a/parse.c b/parse.c
11612 index 6ac6908..b9f3360 100644
11613 --- a/parse.c
11614 +++ b/parse.c
11615 @@ -19,8 +19,15 @@
11616  
11617  /* Keywords of the configuration language */
11618  
11619 +
11620  #include "tac_plus.h"
11621  
11622 +#include "parse.h"
11623 +#include "utils.h"
11624 +#include "report.h"
11625 +#include "hash.h"
11626 +
11627 +
11628  static void *wordtable[HASH_TAB_SIZE]; /* Table of keyword declarations */
11629  
11630  struct keyword {
11631 @@ -31,6 +38,8 @@ struct keyword {
11632  
11633  typedef struct keyword KEYWORD;
11634  
11635 +static void declare TAC_ARGS((char *name, int value));
11636 +
11637  static void
11638  declare(name, value)
11639      char *name;
11640 @@ -53,6 +62,8 @@ declare(name, value)
11641  
11642  /* Declare keywords of the "configuration language". */
11643  
11644 +void parser_init TAC_ARGS((void));
11645 +
11646  void
11647  parser_init()
11648  {
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);
11670  }
11671  
11672 +int keycode TAC_ARGS((const char *keyword));
11673 +
11674  /* Return a keyword code if a keyword is recognized. 0 otherwise */
11675  int
11676  keycode(keyword)
11677 -char *keyword;
11678 +const char *keyword;
11679  {
11680      KEYWORD *k = hash_lookup(wordtable, keyword);
11681  
11682 @@ -129,7 +150,9 @@ char *keyword;
11683      return (S_unknown);
11684  }
11685  
11686 -char *
11687 +const char *codestring TAC_ARGS((int type));
11688 +
11689 +const char *
11690  codestring(type)
11691  int type;
11692  {
11693 @@ -156,8 +179,6 @@ int type;
11694         return ("group");
11695      case S_host:
11696         return ("host");
11697 -    case S_type:
11698 -       return ("type");
11699      case S_file:
11700         return ("file");
11701      case S_skey:
11702 @@ -250,5 +271,23 @@ int type;
11703         return("lcp");
11704      case S_time:
11705         return("time");
11706 +    case S_and:
11707 +       return("and");
11708 +    case S_closeparen:
11709 +       return(")");
11710 +    case S_enlist:
11711 +       return("enlist");
11712 +    case S_first:
11713 +       return("first");
11714 +    case S_not:
11715 +       return("not");
11716 +    case S_openparen:
11717 +       return("(");
11718 +    case S_or:
11719 +       return("or");
11720 +    case S_recursive:
11721 +       return("recursive");
11722 +    case S_when:
11723 +       return("when");
11724      }
11725  }
11726 diff --git a/parse.h b/parse.h
11727 index e5be7f7..34d72ee 100644
11728 --- a/parse.h
11729 +++ b/parse.h
11730 @@ -1,3 +1,8 @@
11731 +#ifndef PARSE_H
11732 +#define PARSE_H 1
11733 +
11734 +#include "tac_plus.h"
11735 +
11736  /*
11737     Copyright (c) 1995-1998 by Cisco systems, Inc.
11738  
11739 @@ -17,8 +22,6 @@
11740     FITNESS FOR A PARTICULAR PURPOSE.
11741  */
11742  
11743 -/* Dummy password, if nopasswd is specified */
11744 -extern char *nopasswd_str;
11745  
11746  /* Keywords & values */
11747  
11748 @@ -82,9 +85,24 @@ extern char *nopasswd_str;
11749  #define S_db             44
11750  #define S_db_accounting          45
11751  #endif  /*DB*/
11752 -#define S_type           46
11753  #ifdef USE_LDAP
11754  #define S_ldap            47
11755  #endif /* LDAP */
11756  #define S_time           48
11757 +#define S_and            49
11758 +#define S_closeparen     50
11759 +#define S_enlist         51
11760 +#define S_first                  52
11761 +#define S_not            53
11762 +#define S_openparen      54
11763 +#define S_or             55
11764 +#define S_recursive      56
11765 +#define S_when           57
11766 +
11767 +
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));
11771 +
11772  
11773 +#endif /* PARSE_H */
11774 diff --git a/programs.c b/programs.c
11775 index bce0178..ac42b23 100644
11776 --- a/programs.c
11777 +++ b/programs.c
11778 @@ -19,10 +19,29 @@
11779  
11780  /* Routines to fork children and communicate with them via pipes */
11781  
11782 +
11783  #include "tac_plus.h"
11784 -#include "sys/wait.h"
11785 +
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"
11792 +#endif
11793 +#include <signal.h>
11794 +#ifdef HAVE_SYSLOG_H
11795 +#include <syslog.h>
11796 +#endif
11797 +#ifdef HAVE_SYS_SYSLOG_H
11798 +#include <sys/syslog.h>
11799 +#endif
11800 +
11801 +#include "programs.h"
11802 +#include "utils.h"
11803 +#include "report.h"
11804 +#include "do_author.h"                 /* for "struct author_data" */
11805 +#include "main.h"
11806 +
11807  
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) */
11813  
11814 +static char *lookup TAC_ARGS((char *sym, struct author_data *data));
11815 +
11816  static char *
11817  lookup(sym, data)
11818  char *sym;
11819 @@ -96,12 +117,14 @@ struct author_data *data;
11820     values for the various $ variables by looking in the authorization
11821     data */
11822  
11823 +static char *substitute TAC_ARGS((const char *string, struct author_data *data));
11824 +
11825  static char *
11826  substitute(string, data)
11827 -char *string;
11828 +const char *string;
11829  struct author_data *data;
11830  {
11831 -    char *cp;
11832 +    const char *cp;
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;
11837  
11838         } else {
11839             /* copy symbol into sym */
11840 -           while (*cp && isalpha(*cp))
11841 +           while (*cp && isalpha((int) *cp))
11842                 *symp++ = *cp++;
11843         }
11844  
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. */
11848  
11849 +static int waitfor TAC_ARGS((int pid));
11850 +
11851  static int
11852  waitfor(pid)
11853  int pid;
11854 @@ -189,6 +214,8 @@ int pid;
11855      return (WEXITSTATUS(status));
11856  }
11857  
11858 +static int write_args TAC_ARGS((int fd, char **args, int arg_cnt));
11859 +
11860  /* Write an argv array of strings to fd, adding a newline to each one */
11861  static int
11862  write_args(fd, args, arg_cnt)
11863 @@ -211,6 +238,8 @@ char **args;
11864      return (0);
11865  }
11866  
11867 +static void close_fds TAC_ARGS((int fd1, int fd2, int fd3));
11868 +
11869  /* Close the three given file-descruptors */
11870  static void
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 */
11875  
11876 +static int my_popen TAC_ARGS((char *cmd, int *readfdp, int *writefdp, int *errorfdp));
11877 +
11878  static int
11879  my_popen(cmd, readfdp, writefdp, errorfdp)
11880  char *cmd;
11881 @@ -297,6 +328,8 @@ int *readfdp, *writefdp, *errorfdp;
11882      return(0); /* keep Codecenter quiet */
11883  }
11884  
11885 +static int read_string TAC_ARGS((int fd, char *string, int len));
11886 +
11887  /* read the file descriptor and stuff the data into the given array for
11888   * the number of bytes given. Throw the rest away.
11889   */
11890 @@ -305,7 +338,7 @@ read_string (fd, string, len)
11891  int fd, len;
11892  char *string;
11893  {
11894 -    uint i, ret;
11895 +    int i, ret;
11896      char c;
11897  
11898      i=0;
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 */
11902  
11903 +static char **read_args TAC_ARGS((int n, int fd));
11904 +
11905  static char **
11906  read_args(n, fd)
11907  int n, 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 */
11911  
11912 +int call_pre_process TAC_ARGS((const char *string, struct author_data *data, char ***outargsp, int *outargs_cntp, char *error, int err_len));
11913 +
11914  int
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;
11919  char ***outargsp;
11920 -int *outargs_cntp, err_len;
11921 +int *outargs_cntp;
11922 +char *error;
11923 +int err_len;
11924  {
11925      char **new_args;
11926      int readfd, writefd, errorfd;
11927 @@ -402,8 +441,8 @@ int *outargs_cntp, err_len;
11928  
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);
11935      }
11936  
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 */
11941  
11942 +int call_post_process TAC_ARGS((const char *string, struct author_data *data, char ***outargsp, int *outargs_cntp));
11943 +
11944  int
11945  call_post_process(string, data, outargsp, outargs_cntp)
11946 -char *string;
11947 +const char *string;
11948  struct author_data *data;
11949  char ***outargsp;
11950  int *outargs_cntp;
11951 diff --git a/programs.h b/programs.h
11952 new file mode 100644
11953 index 0000000..31ebef3
11954 --- /dev/null
11955 +++ b/programs.h
11956 @@ -0,0 +1,13 @@
11957 +#ifndef PROGRAMS_H
11958 +#define PROGRAMS_H 1
11959 +
11960 +#include "tac_plus.h"
11961 +
11962 +
11963 +struct author_data;
11964 +
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));
11967 +
11968 +
11969 +#endif /* PROGRAMS_H */
11970 diff --git a/pw.c b/pw.c
11971 index 96c761e..a749262 100644
11972 --- a/pw.c
11973 +++ b/pw.c
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 */
11977  
11978 +
11979  #include "tac_plus.h"
11980 +
11981 +#include <stdlib.h>
11982  #include <pwd.h>
11983  #include <string.h>
11984  
11985 +#include "pw.h"
11986 +#include "report.h"
11987 +#include "main.h"
11988 +
11989 +
11990  static struct passwd pw_passwd;
11991  
11992 +struct passwd *tac_passwd_lookup TAC_ARGS((const char *name, const char *file));
11993 +
11994  struct passwd *
11995  tac_passwd_lookup(name, file)
11996 -    char *name, *file;
11997 +const char *name;
11998 +const char *file;
11999  {
12000      FILE *passwd_fp = NULL;
12001  
12002 @@ -113,10 +124,12 @@ tac_passwd_lookup(name, file)
12003  
12004          pw_passwd.pw_name    = uname;
12005          pw_passwd.pw_passwd  = password;
12006 -#ifndef NO_PWAGE
12007 +#ifdef HAVE_PASSWD_PW_AGE
12008          pw_passwd.pw_age     = NULL;
12009 +#endif
12010 +#ifdef HAVE_PASSWD_PW_COMMENT
12011          pw_passwd.pw_comment = NULL;
12012 -#endif /* NO_PWAGE */
12013 +#endif
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
12020 --- /dev/null
12021 +++ b/pw.h
12022 @@ -0,0 +1,10 @@
12023 +#ifndef PW_H
12024 +#define PW_H 1
12025 +
12026 +#include "tac_plus.h"
12027 +
12028 +
12029 +extern struct passwd *tac_passwd_lookup TAC_ARGS((const char *name, const char *file));
12030 +
12031 +
12032 +#endif /* PW_H */
12033 diff --git a/pwlib.c b/pwlib.c
12034 index 75f90b1..70a468e 100644
12035 --- a/pwlib.c
12036 +++ b/pwlib.c
12037 @@ -17,39 +17,61 @@
12038     FITNESS FOR A PARTICULAR PURPOSE.
12039  */
12040  
12041 +
12042  #include "tac_plus.h"
12043 -#include "expire.h"
12044 -#include "time_limit.h"
12045 +
12046 +#ifdef HAVE_UNISTD_H
12047 +#include <unistd.h>
12048 +#endif
12049 +#include <pwd.h>
12050 +#include <sys/types.h>
12051 +#include <string.h>
12052 +#include <errno.h>
12053 +#include <stdlib.h>
12054 +#include <time.h>
12055  
12056  #ifdef SHADOW_PASSWORDS
12057 +#ifdef HAVE_SHADOW_H
12058  #include <shadow.h>
12059  #endif
12060 +#endif
12061  
12062 -#ifdef USE_PAM
12063 -int
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"
12072 +#include "pw.h"
12073 +#include "choose_authen.h"                     /* for "struct authen_data" */
12074 +#include "packet.h"
12075 +#include "main.h"
12076 +#include "parse.h"
12077  
12078 -/* For database verification */
12079 +#ifdef USE_PAM
12080 +#include "tac_pam.h"
12081 +#endif
12082  #ifdef DB
12083 -int db_verify();
12084 -#endif /* DB */
12085 -
12086 -/* For LDAP verification */
12087 +#include "db.h"                        /* For database verification */
12088 +#endif
12089  #ifdef USE_LDAP
12090 -#include "ldap.h"
12091 -#endif /* LDAP */
12092 +#include "ldap_author.h"               /* For LDAP verification */
12093 +#endif
12094 +
12095 +
12096 +static int passwd_file_verify TAC_ARGS((const char *user, const char *supplied_passwd, struct authen_data *data, const char *filename));
12097 +
12098  
12099  /* Generic password verification routines for des, file and cleartext
12100     passwords */
12101  
12102 -static int passwd_file_verify();
12103 -
12104  /* Adjust data->status depending on whether a user has expired or not */
12105  
12106 +void set_expiration_status TAC_ARGS((const char *exp_date, struct authen_data *data));
12107 +
12108  void
12109  set_expiration_status(exp_date, data)
12110 -char *exp_date;
12111 +const char *exp_date;
12112  struct authen_data *data;
12113  {
12114      int expired;
12115 @@ -105,18 +127,18 @@ struct authen_data *data;
12116  
12117     Return 1 if password is valid */
12118  
12119 +int verify TAC_ARGS((const char *name, const char *passwd, struct authen_data *data, int recurse));
12120 +
12121  int
12122  verify(name, passwd, data, recurse)
12123 -char *name, *passwd;
12124 +const char *name;
12125 +const char *passwd;
12126  struct authen_data *data;
12127  int recurse;
12128  {
12129 -    char *exp_date;
12130 -    char *timestamp;
12131 -    char *cfg_passwd;
12132 -    char *p;
12133 +    const char *exp_date, *cfg_passwd, *p, *timestamp;
12134  
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 */
12142  
12143      if (!cfg_passwd) {
12144 -       char *file = cfg_get_authen_default();
12145 +       const char *file = cfg_get_authen_default();
12146         switch (cfg_get_authen_default_method()) {
12147 -       case (S_file):
12148  
12149 -       if (file) {
12150 +       case (S_file):
12151 +           if (file)
12152                 return (passwd_file_verify(name, passwd, data, file));
12153 -       }
12154             break;
12155 +
12156  #ifdef DB
12157         case (S_db):
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;
12165  #ifdef USE_PAM
12166          case (S_pam):
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;
12178         return (0);
12179 -
12180         }
12181 -}
12182 +    }
12183  
12184      /* We have a configured password. Deal with it depending on its
12185         type */
12186 @@ -323,11 +344,15 @@ int recurse;
12187      return (0);
12188  }
12189  
12190 +static int etc_passwd_file_verify TAC_ARGS((const char *user, const char *supplied_passwd, struct authen_data *data));
12191 +
12192  /* verify that this user/password is valid per /etc/passwd.
12193 -   Return 0 if invalid. */
12194 + * Return 0 if invalid.
12195 + */
12196  static int
12197  etc_passwd_file_verify(user, supplied_passwd, data)
12198 -char *user, *supplied_passwd;
12199 +const char *user;
12200 +const char *supplied_passwd;
12201  struct authen_data *data;
12202  {
12203      struct passwd *pw;
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. */
12207  
12208 +static int passwd_file_verify TAC_ARGS((const char *user, const char *supplied_passwd, struct authen_data *data, const char *filename));
12209 +
12210  static int
12211  passwd_file_verify(user, supplied_passwd, data, filename)
12212 -char *user, *supplied_passwd;
12213 +const char *user;
12214 +const char *supplied_passwd;
12215  struct authen_data *data;
12216 -char *filename;
12217 +const char *filename;
12218  {
12219      struct passwd *pw;
12220      char *exp_date;
12221 @@ -467,9 +495,12 @@ char *filename;
12222   * return 1 if verified, 0 otherwise.
12223   */
12224  
12225 +int des_verify TAC_ARGS((const char *users_passwd, const char *encrypted_passwd));
12226 +
12227  int
12228  des_verify(users_passwd, encrypted_passwd)
12229 -char *users_passwd, *encrypted_passwd;
12230 +const char *users_passwd;
12231 +const char *encrypted_passwd;
12232  {
12233      char *ep;
12234  
12235 diff --git a/pwlib.h b/pwlib.h
12236 new file mode 100644
12237 index 0000000..92b54af
12238 --- /dev/null
12239 +++ b/pwlib.h
12240 @@ -0,0 +1,14 @@
12241 +#ifndef PWLIB_H
12242 +#define PWLIB_H 1
12243 +
12244 +#include "tac_plus.h"
12245 +
12246 +
12247 +struct authen_data;
12248 +
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));
12252 +
12253 +
12254 +#endif /* PWLIB_H */
12255 diff --git a/report.c b/report.c
12256 index a458617..d46abfd 100644
12257 --- a/report.c
12258 +++ b/report.c
12259 @@ -17,20 +17,37 @@
12260     FITNESS FOR A PARTICULAR PURPOSE.
12261  */
12262  
12263 +
12264  #include "tac_plus.h"
12265 -#include <stdio.h>
12266  
12267 -#ifdef AIX
12268 +#include <stdio.h>
12269  #include <sys/types.h>
12270 -#else
12271  #include <time.h>
12272 +#include <sys/stat.h>
12273 +#ifdef HAVE_FCNTL_H
12274 +#include <fcntl.h>
12275  #endif
12276 -
12277 -#ifdef __STDC__
12278 -#include <stdarg.h>            /* ANSI C, variable length args */
12279 -#else
12280 -#include <varargs.h>           /* has 'vararg' definitions */
12281 +#include <string.h>
12282 +#ifdef HAVE_UNISTD_H
12283 +#include <unistd.h>
12284 +#endif
12285 +#ifdef HAVE_SYSLOG_H
12286 +#include <syslog.h>
12287  #endif
12288 +#ifdef HAVE_SYS_SYSLOG_H
12289 +#include <sys/syslog.h>
12290 +#endif
12291 +
12292 +#include "report.h"
12293 +#include "utils.h"
12294 +#include "main.h"
12295 +
12296 +
12297 +/* Configurable:
12298 + */
12299 +
12300 +#define LOGFILE_DEFAULT "/var/log/tac_plus.log"
12301 +
12302  
12303  FILE *ostream = NULL;
12304  
12305 @@ -45,21 +62,30 @@ char *logfile = LOGFILE_DEFAULT;
12306   * All other priorities are always logged to syslog.
12307   */
12308  
12309 +void report TAC_ARGS((int priority, const char *fmt, ...)) G_GNUC_PRINTF(2, 3);
12310 +
12311  #ifdef __STDC__
12312 +
12313 +#include <stdarg.h>            /* ANSI C, variable length args */
12314  void
12315 -report(int priority, char *fmt,...)
12316 -#else
12317 +report(int priority, const char *fmt,...)
12318 +
12319 +#else /* __STDC__ */
12320 +
12321 +#include <varargs.h>           /* has 'vararg' definitions */
12322  /* VARARGS2 */
12323  void
12324  report(priority, fmt, va_alist)
12325  int priority;
12326 -char *fmt;
12327 +const char *fmt;
12328  va_dcl                         /* no terminating semi-colon */
12329 -#endif
12330 +
12331 +#endif /* __STDC__ */
12332  {
12333      char msg[255];             /* temporary string */
12334 -    char *fp, *bufp, *charp;
12335 -    int len, m, i, n;
12336 +    const char *fp;
12337 +    char *bufp, *charp = NULL /* GCC paranoia */;
12338 +    int len, m = 0 /* GCC paranoia */, i, n;
12339      char digits[16];
12340      va_list ap;
12341  
12342 @@ -119,6 +145,9 @@ va_dcl                              /* no terminating semi-colon */
12343             m = strlen(digits);
12344             charp = digits;
12345             break;
12346 +       default:
12347 +           syslog(LOG_ERR, "Unknown format character '%c', ignoring it", *fp);
12348 +           continue;
12349         }
12350  
12351         if ((len + m + 1) >= n) {
12352 @@ -167,7 +196,7 @@ va_dcl                              /* no terminating semi-colon */
12353  
12354             ct[24] = '\0';
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);
12363  }
12364  
12365 +void report_hex TAC_ARGS((int priority, u_char *p, int len));
12366 +
12367  /* format a hex dump for syslog */
12368  void
12369  report_hex(priority, p, len)
12370 @@ -225,6 +256,8 @@ int len;
12371  }
12372  
12373  
12374 +void report_string TAC_ARGS((int priority, u_char *p, int len));
12375 +
12376  /* format a non-null terminated string for syslog */
12377  void
12378  report_string(priority, p, len)
12379 @@ -251,10 +284,11 @@ int len;
12380      report(priority, "%s", buf);
12381  }
12382  
12383 +void tac_regerror TAC_ARGS((const char *s));
12384 +
12385  void
12386 -regerror(s)
12387 -char *s;
12388 +tac_regerror(s)
12389 +const char *s;
12390  {
12391      report(LOG_ERR, "in regular expression %s", s);
12392  }
12393 -
12394 diff --git a/report.h b/report.h
12395 new file mode 100644
12396 index 0000000..5e5d1bb
12397 --- /dev/null
12398 +++ b/report.h
12399 @@ -0,0 +1,26 @@
12400 +#ifndef REPORT_H
12401 +#define REPORT_H 1
12402 +
12403 +#include "tac_plus.h"
12404 +
12405 +#include <stdio.h>
12406 +#include <sys/types.h>         /* for u_* */
12407 +#ifdef HAVE_SYSLOG_H
12408 +#include <syslog.h>            /* for LOG_* level values */
12409 +#endif
12410 +#ifdef HAVE_SYS_SYSLOG_H
12411 +#include <sys/syslog.h>                /* for LOG_* level values */
12412 +#endif
12413 +
12414 +
12415 +extern FILE *ostream;              /* for logging to console */
12416 +extern char *logfile;
12417 +
12418 +
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));
12423 +
12424 +
12425 +#endif /* REPORT_H */
12426 diff --git a/sendauth.c b/sendauth.c
12427 index 68e5482..2076dc9 100644
12428 --- a/sendauth.c
12429 +++ b/sendauth.c
12430 @@ -17,21 +17,43 @@
12431     FITNESS FOR A PARTICULAR PURPOSE.
12432  */
12433  
12434 +
12435  #include "tac_plus.h"
12436 +
12437 +#include <stdlib.h>
12438 +
12439 +#include "sendauth.h"
12440  #include "expire.h"
12441  #include "md5.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"
12449 +#include "main.h"
12450  
12451 -static int do_sendauth_fn();
12452 -static void outbound_chap();
12453  #ifdef MSCHAP
12454 -static void outbound_mschap();
12455 -#endif /* MSCHAP */
12456 -void outbound_pap();
12457 +#include "default_fn.h"
12458 +#endif
12459 +
12460 +
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));
12464 +
12465 +#ifdef MSCHAP
12466 +static void outbound_mschap TAC_ARGS((struct authen_data *data));
12467 +#endif
12468 +
12469 +
12470 +int sendauth_fn TAC_ARGS((struct authen_data *data));
12471  
12472  int sendauth_fn(data)
12473  struct authen_data *data;
12474  {
12475 -    int status;
12476 +    int retval;
12477      char *name, *p;
12478  
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;
12484 +       retval = 0;
12485      } else {
12486 -       status = do_sendauth_fn(data);
12487 +       retval = do_sendauth_fn(data);
12488      }
12489  
12490      if (debug) {
12491 @@ -71,7 +94,7 @@ struct authen_data *data;
12492                (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ?
12493                "accepted" : "rejected");
12494      }
12495 -    return(status);
12496 +    return (retval);
12497  }
12498  
12499  /*
12500 @@ -84,11 +107,13 @@ struct authen_data *data;
12501   * Return 0 if data->status is valid, otherwise 1
12502   */
12503  
12504 +static int do_sendauth_fn TAC_ARGS((struct authen_data *data));
12505 +
12506  static int
12507  do_sendauth_fn(data)
12508  struct authen_data *data;
12509  {
12510 -    char *name, *exp_date;
12511 +    const char *name, *exp_date;
12512  
12513      data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
12514  
12515 @@ -129,11 +154,13 @@ struct authen_data *data;
12516      return (0);
12517  }
12518  
12519 -void
12520 +static void outbound_pap TAC_ARGS((struct authen_data *data));
12521 +
12522 +static void
12523  outbound_pap(data)
12524  struct authen_data *data;
12525  {
12526 -    char *secret, *p, *name;
12527 +    const char *secret, *p, *name;
12528  
12529      name = data->NAS_id->username;
12530  
12531 @@ -163,17 +190,19 @@ struct authen_data *data;
12532         return;
12533      }
12534  
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;
12540  }
12541  
12542 +static void outbound_chap TAC_ARGS((struct authen_data *data));
12543 +
12544  static void
12545  outbound_chap(data)
12546  struct authen_data *data;
12547  {
12548 -    char *name, *secret, *chal, digest[MD5_LEN];
12549 -    char *p;
12550 +    const char *name, *secret, *chal, *p;
12551 +    char digest[MD5_LEN];
12552      u_char *mdp;
12553      char id;
12554      int chal_len, inlen;
12555 @@ -262,12 +291,13 @@ struct authen_data *data;
12556  
12557  #ifdef MSCHAP
12558  
12559 +static void outbound_mschap TAC_ARGS((struct authen_data *data));
12560 +
12561  static void
12562  outbound_mschap(data)
12563  struct authen_data *data;
12564  {
12565 -    char *name, *secret, *chal;
12566 -    char *p;
12567 +    const char *name, *secret, *chal, *p;
12568      char id;
12569      int chal_len;
12570  
12571 diff --git a/sendauth.h b/sendauth.h
12572 new file mode 100644
12573 index 0000000..d3e2fbc
12574 --- /dev/null
12575 +++ b/sendauth.h
12576 @@ -0,0 +1,12 @@
12577 +#ifndef SENDAUTH_H
12578 +#define SENDAUTH_H 1
12579 +
12580 +#include "tac_plus.h"
12581 +
12582 +
12583 +struct authen_data;
12584 +
12585 +extern int sendauth_fn TAC_ARGS((struct authen_data *data));
12586 +
12587 +
12588 +#endif /* SENDAUTH_H */
12589 diff --git a/sendpass.c b/sendpass.c
12590 index f7f0b3c..9d8ab00 100644
12591 --- a/sendpass.c
12592 +++ b/sendpass.c
12593 @@ -17,11 +17,24 @@
12594     FITNESS FOR A PARTICULAR PURPOSE.
12595  */
12596  
12597 +
12598  #include "tac_plus.h"
12599 +
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" */
12607 +#include "main.h"
12608 +#include "packet.h"
12609  
12610 -static int
12611 -do_sendpass_fn();
12612 +
12613 +static int do_sendpass_fn TAC_ARGS((struct authen_data *data));
12614 +
12615 +
12616 +int sendpass_fn TAC_ARGS((struct authen_data *data));
12617  
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.
12623   *
12624 - * Return 0 if data->status is valid, otherwise 1 */
12625 + * Return 0 if data->status is valid, otherwise 1
12626 + */
12627 +
12628 +static int do_sendpass_fn TAC_ARGS((struct authen_data *data));
12629  
12630  static int
12631  do_sendpass_fn(data)
12632  struct authen_data *data;
12633  {
12634 -    char *name;
12635 -    char *p;
12636 +    const char *name, *exp_date, *secret, *p;
12637      int expired;
12638 -    char *exp_date;
12639 -    char *secret;
12640  
12641      data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
12642  
12643 @@ -159,8 +172,8 @@ struct authen_data *data;
12644             return(0);
12645         }
12646  
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
12657 --- /dev/null
12658 +++ b/sendpass.h
12659 @@ -0,0 +1,12 @@
12660 +#ifndef SENDPASS_H
12661 +#define SENDPASS_H 1
12662 +
12663 +#include "tac_plus.h"
12664 +
12665 +
12666 +struct authen_data;
12667 +
12668 +extern int sendpass_fn TAC_ARGS((struct authen_data *data));
12669 +
12670 +
12671 +#endif /* SENDPASS_H */
12672 diff --git a/skey_fn.c b/skey_fn.c
12673 index d3c9860..0a74fa8 100644
12674 --- a/skey_fn.c
12675 +++ b/skey_fn.c
12676 @@ -17,17 +17,22 @@
12677     FITNESS FOR A PARTICULAR PURPOSE.
12678  */
12679  
12680 -#ifdef SKEY
12681 +
12682  #include "tac_plus.h"
12683 +
12684 +#ifdef SKEY
12685 +
12686 +#include <skey.h>
12687 +
12688 +#include "skey_fn.h"
12689  #include "expire.h"
12690  
12691 +
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 */
12696  
12697 -#include <skey.h>
12698 -
12699  struct private_data {
12700      struct skey skey;
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 */
12705  
12706 +static int skey_verify TAC_ARGS((char *passwd, struct authen_data *data)); 
12707 +
12708  static int
12709  skey_verify(passwd, data)
12710  char *passwd;
12711 @@ -73,6 +80,8 @@ struct authen_data *data;
12712   * Return 0 if data->status is valid, otherwise 1
12713   */
12714  
12715 +int skey_fn TAC_ARGS((struct authen_data *data));
12716 +
12717  int
12718  skey_fn(data)
12719  struct authen_data *data;
12720 @@ -222,12 +231,9 @@ struct authen_data *data;
12721         return (1);
12722      }
12723  }
12724 -#else /* SKEY */
12725  
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 */
12729 +#else /* SKEY */
12730  
12731 -static int dummy = 0;
12732 +TAC_SOURCEFILE_EMPTY
12733  
12734  #endif /* SKEY */
12735 diff --git a/skey_fn.h b/skey_fn.h
12736 new file mode 100644
12737 index 0000000..1b7474a
12738 --- /dev/null
12739 +++ b/skey_fn.h
12740 @@ -0,0 +1,14 @@
12741 +#ifndef SKEY_FN_H
12742 +#define SKEY_FN_H 1
12743 +
12744 +#include "tac_plus.h"
12745 +
12746 +#ifdef SKEY
12747 +
12748 +
12749 +extern int skey_fn TAC_ARGS((struct authen_data *data));
12750 +
12751 +
12752 +#endif /* SKEY */
12753 +
12754 +#endif /* SKEY_FN_H */
12755 diff --git a/tac_pam.c b/tac_pam.c
12756 index bf1b215..4f088a0 100644
12757 --- a/tac_pam.c
12758 +++ b/tac_pam.c
12759 @@ -1,12 +1,10 @@
12760 -#ifdef USE_PAM
12761 -
12762  /* tac_pam.auth.c
12763   * A simple pam authentication  routine written by
12764   * Max Liccardo <ravel@tiscalinet.it>
12765   * PAM_RUSER=username/rem_addr.
12766   */
12767  
12768 - /*
12769 +/*
12770      This program was contributed by Shane Watts
12771      [modifications by AGM]
12772  
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
12777 -   */
12778 +*/
12779 +
12780 +
12781 +#include "tac_plus.h"
12782 +
12783 +#ifdef USE_PAM
12784  
12785  #include <stdio.h>
12786  #include <stdlib.h>
12787  #include <string.h>
12788  #include <security/pam_appl.h>
12789 -#include "tac_plus.h"
12790  
12791 -typedef struct
12792 -{
12793 -       char *UserName;
12794 -       char *Passwd;
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" */
12800 +#include "main.h"
12801 +
12802 +
12803 +typedef struct {
12804 +    const char *UserName;
12805 +    const char *Passwd;
12806  } UserCred;
12807  
12808  
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));
12812 +
12813 +static int fconv(num_msg, msg, resp, appdata_ptr)
12814 +int num_msg;
12815 +const struct pam_message **msg;
12816 +struct pam_response **resp;
12817 +void *appdata_ptr;
12818  {
12819      int i;
12820      UserCred *lUserCred;
12821 @@ -38,19 +52,16 @@ static int fconv(int num_msg, const struct pam_message **msg,
12822  
12823      lUserCred = appdata_ptr;
12824  
12825 -       if(lUserCred == NULL)
12826 -       {
12827 +    if(lUserCred == NULL) {
12828         report(LOG_ERR,"argh....maybe a SunOs 5.6 ???");
12829         return(PAM_CONV_ERR);
12830      }
12831  
12832 +    *resp = (struct pam_response *) tac_malloc(num_msg * sizeof(struct pam_response));
12833  
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) {
12837  
12838 -       for(i=0;i<num_msg;i++)
12839 -       {
12840 -               switch(msg[i]->msg_style)
12841 -               {
12842         case PAM_PROMPT_ECHO_OFF:
12843             resp[i]->resp = strdup(lUserCred->Passwd);
12844             break;
12845 @@ -60,6 +71,7 @@ static int fconv(int num_msg, const struct pam_message **msg,
12846             break;
12847  
12848         default:
12849 +           resp[i]->resp = NULL;
12850             report(LOG_DEBUG,"conv default");
12851             break;
12852         }
12853 @@ -70,12 +82,16 @@ static int fconv(int num_msg, const struct pam_message **msg,
12854  }
12855  
12856  
12857 -
12858 +int tac_pam_auth TAC_ARGS((const char *aszUserName, const char *aszPassword, struct authen_data *data, const char *aszService));
12859  
12860  int
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;
12867  {
12868 -       pam_handle_t    *pamh=NULL;
12869 +    pam_handle_t *pamh = NULL;
12870      int retval;
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;
12875  
12876  
12877 -       if((lpszRemoteUser = calloc(strlen(aszUserName)+strlen(data->NAS_id->NAC_address)+2,sizeof(char))) == NULL)
12878 -       {
12879 -        report(LOG_ERR,"cannot malloc");
12880 -               return(1);
12881 -       }
12882 +    lpszRemoteUser = tac_malloc((strlen(aszUserName)+1+strlen(data->NAS_id->NAC_address)+1) * sizeof(char));
12883  
12884      retval = pam_start(aszService,aszUserName , &s_conv, &pamh);
12885  
12886 -       if (retval != PAM_SUCCESS)
12887 -       {
12888 +    if (retval != PAM_SUCCESS) {
12889         report(LOG_ERR, "cannot start pam-authentication");
12890 +       free(lpszRemoteUser);
12891         pamh = NULL;
12892         return(1);
12893      }
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>
12896  */
12897  
12898 +int tac_pam_authorization TAC_ARGS((const char *aszUserName, struct author_data *data, const char *aszService));
12899 +
12900  int
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;
12906  {
12907 -       pam_handle_t    *pamh=NULL;
12908 +    pam_handle_t *pamh = NULL;
12909      int retval;
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;
12915  
12916 -       if (aszService== NULL) 
12917 -       {
12918 +    if (aszService== NULL) {
12919         report(LOG_ERR,"Service Name doesn't available So authorize him");
12920         return(0);
12921      }
12922  
12923 -
12924 -       if((lpszRemoteUser = calloc(strlen(aszUserName)+strlen(data->id->NAC_address)+2,sizeof(char))) == NULL)
12925 -       {
12926 -        report(LOG_ERR,"cannot malloc");
12927 -               return(1);
12928 -       }
12929 +    lpszRemoteUser = tac_malloc((strlen(aszUserName)+strlen(data->id->NAC_address)+2) * sizeof(char));
12930  
12931      retval = pam_start(aszService,aszUserName , &s_conv, &pamh);
12932  
12933 -       if (retval != PAM_SUCCESS)
12934 -       {
12935 +    if (retval != PAM_SUCCESS) {
12936         report(LOG_ERR, "cannot start pam-authentication");
12937 +       free(lpszRemoteUser);
12938         pamh = NULL;
12939         return(1);
12940      }
12941 @@ -177,11 +188,12 @@ tac_pam_authorization (char *aszUserName,struct author_data *data,char *aszServi
12942  
12943      retval = pam_acct_mgmt(pamh, 0);           /* Is user permit to gain access system */
12944  
12945 -    if(retval != PAM_SUCCESS)
12946 +    if (retval != PAM_SUCCESS)
12947         report(LOG_ERR, "Pam Account Managment:%s",pam_strerror(pamh,retval));
12948 -    else 
12949 +    else {
12950         if (debug & DEBUG_AUTHOR_FLAG)
12951             report(LOG_DEBUG, "PAM authorization allow user");
12952 +    }
12953  
12954     if (pam_end(pamh,retval) != PAM_SUCCESS) {          /* close Linux-PAM */
12955         pamh = NULL;
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 */
12958  }
12959  
12960 +#else /* USE_PAM */
12961  
12962 -#endif /* USE_PAM */
12963 -
12964 -
12965 -
12966 +TAC_SOURCEFILE_EMPTY
12967  
12968 +#endif /* USE_PAM */
12969 diff --git a/tac_pam.h b/tac_pam.h
12970 new file mode 100644
12971 index 0000000..c8306ba
12972 --- /dev/null
12973 +++ b/tac_pam.h
12974 @@ -0,0 +1,18 @@
12975 +#ifndef TAC_PAM_H
12976 +#define TAC_PAM_H 1
12977 +
12978 +#include "tac_plus.h"
12979 +
12980 +#ifdef USE_PAM
12981 +
12982 +
12983 +struct authen_data;
12984 +struct author_data;
12985 +
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));
12988 +
12989 +
12990 +#endif /* USE_PAM */
12991 +
12992 +#endif /* TAC_PAM_H */
12993 diff --git a/tac_plus.1 b/tac_plus.1
12994 index 579c7ee..69f3502 100644
12995 --- a/tac_plus.1
12996 +++ b/tac_plus.1
12997 @@ -111,6 +111,8 @@ the following values are recognised:
12998  .nf
12999  
13000  Value   Meaning
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
13015  
13016  .fi
13017  .TP
13018 diff --git a/tac_plus.cfg b/tac_plus.cfg
13019 index 31e53f5..d217258 100644
13020 --- a/tac_plus.cfg
13021 +++ b/tac_plus.cfg
13022 @@ -51,4 +51,3 @@ user = DEFAULT {
13023  #group = staff {
13024  #    time = "Wd1800-1817|!Wd1819-2000"
13025  #}
13026 -
13027 diff --git a/tac_plus.h b/tac_plus.h
13028 index 99d95e0..1bb658f 100644
13029 --- a/tac_plus.h
13030 +++ b/tac_plus.h
13031 @@ -1,3 +1,6 @@
13032 +#ifndef TAC_PLUS_H
13033 +#define TAC_PLUS_H 1
13034 +
13035  /*
13036     Copyright (c) 1995-1998 by Cisco systems, Inc.
13037  
13038 @@ -16,8 +19,12 @@
13039     WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
13040     FITNESS FOR A PARTICULAR PURPOSE.
13041  */
13042 -/* For autoconfig */
13043 +
13044 +
13045 +#ifdef HAVE_CONFIG_H
13046  #include "config.h"
13047 +#endif
13048 +
13049  
13050  /*
13051   * If you are defining a system from scratch, the following may be useful.
13052 @@ -33,25 +40,9 @@
13053  /* Do you need tacacs+ versions of bzero etc. */
13054  /* #define NEED_BZERO */
13055  
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
13058 - * /etc/shadow */
13059 -/*#define SHADOW_PASSWORDS*/
13060 -
13061 -/* Define this if your malloc is defined in malloc.h instead of stdlib.h */
13062 -/* #define STDLIB_MALLOC */
13063 -
13064  /* Define this if your wait call status is a union as opposed to an int */
13065  /* #define UNIONWAIT */
13066  
13067 -/* Define this if your signal() uses a function returning void instead 
13068 - * of int
13069 - */
13070 -/* #define VOIDSIG */
13071 -
13072 -/* Define this if your password file does not contain age and comment fields. */
13073 -/* #define NO_PWAGE */
13074 -
13075  /* Define this if you need a getdtablesize routine defined */
13076  /* #define GETDTABLESIZE */
13077  
13078 @@ -64,23 +55,14 @@
13079   */
13080  /* #define ARAP_DES */
13081  
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
13084 - * used once
13085 - */
13086 -/* #define REARMSIGNAL */
13087 -
13088 -#define VERSION "F4.0.3.alpha.v8 (Extended Tac_plus)"
13089 +#define VERSION_TAIL " (Extended Tac_plus)"
13090  
13091  /*
13092   * System definitions.
13093   */
13094  
13095  #ifdef NETBSD
13096 -#define STDLIB_MALLOC
13097 -#define NO_PWAGE
13098  #define CONST_SYSERRLIST
13099 -#define VOIDSIG
13100  #endif
13101  
13102  #ifdef AIX
13103 @@ -97,15 +79,10 @@
13104  #define _BSD 1
13105  #define _BSD_INCLUDES
13106  #define UNIONWAIT
13107 -#define NO_PWAGE
13108  #endif /* AIX */
13109  
13110  #ifdef LINUX
13111 -#define VOIDSIG
13112 -#define NO_PWAGE
13113  #define REAPCHILD
13114 -#include <unistd.h>
13115 -#define REARMSIGNAL
13116  #ifdef GLIBC
13117  #define CONST_SYSERRLIST
13118  #endif
13119 @@ -122,30 +99,17 @@
13120  #define SYSV
13121  #define GETDTABLESIZE
13122  #define REAPCHILD
13123 -#define SHADOW_PASSWORDS
13124  #define NEED_BZERO
13125 -#define REARMSIGNAL
13126  #endif /* SOLARIS */
13127  
13128  #ifdef HPUX
13129  #define SYSV
13130  #define GETDTABLESIZE
13131  #define REAPCHILD
13132 -#define SYSLOG_IN_SYS
13133 -#define REARMSIGNAL
13134  #endif /* HPUX */
13135  
13136  #ifdef FREEBSD
13137  #define CONST_SYSERRLIST
13138 -#define STDLIB_MALLOC
13139 -#define VOIDSIG
13140 -#define NO_PWAGE
13141 -#endif
13142 -
13143 -#ifdef BSDI
13144 -#define VOIDSIG
13145 -#define STDLIB_MALLOC
13146 -#define NO_PWAGE
13147  #endif
13148  
13149  #define MD5_LEN           16
13150 @@ -153,36 +117,26 @@
13151  #define MSCHAP_DIGEST_LEN 49
13152  #endif /* MSCHAP */
13153  
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>
13161 -
13162 -#include <stdio.h>
13163 -#include <errno.h>
13164 -#include <pwd.h>
13165 -#include <netdb.h>
13166 -
13167 -#ifdef SYSLOG_IN_SYS
13168 -#include <syslog.h>
13169 -#else
13170 -#include <sys/syslog.h>
13171 -#endif
13172 -
13173 -#include <utmp.h>
13174 -
13175 -#include <unistd.h>
13176 -
13177  #ifdef SYSV
13178 +#ifdef HAVE_FCNTL_H
13179  #include <fcntl.h>
13180 +#endif
13181  #define index strchr
13182 -#else /* ! SYSV */
13183 -#include <strings.h>
13184  #endif /* SYSV */
13185  
13186 +/* Sometimes are bzero/bcopy/bcmp declared as prototypes with non-void argument
13187 + * pointers. In such case we would generate too much warnings.
13188 + */
13189 +#include <string.h>
13190 +#ifdef HAVE_STRINGS_H
13191 +#include <strings.h>
13192 +#endif
13193 +
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))
13197 +
13198 +
13199  #ifndef TACPLUS_PIDFILE
13200  #define TACPLUS_PIDFILE "/var/run/tac_plus.pid"
13201  #endif
13202 @@ -193,559 +147,94 @@
13203   * know what you are doing.
13204   */
13205  
13206 -#define DOLLARSIGN '$'
13207 -
13208 -/*
13209 - * XTACACSP protocol defintions
13210 - */
13211 -
13212 -/*
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
13217 - */
13218 +/* Stolen from pbmplus.h of netpbm: */
13219  
13220 -#define AUTHEN_NAME_SIZE 128
13221 +#if __STDC__
13222 +#define TAC_ARGS(alist) alist
13223 +#else /*__STDC__*/
13224 +#define TAC_ARGS(alist) ()
13225 +#endif /*__STDC__*/
13226  
13227 -struct authen_type {
13228 -    char authen_name[AUTHEN_NAME_SIZE];
13229 -    int (*authen_func)();
13230 -    int authen_type;
13231 -};
13232 +/* Stolen from glib of Gnome/GTK+ environment: */
13233  
13234 -/*
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.
13243   */
13244 -
13245 -struct identity {
13246 -    char *username;
13247 -    char *NAS_name;
13248 -    char *NAS_port;
13249 -    char *NAC_address;
13250 -    int priv_lvl;
13251 -};
13252 -
13253 -/*
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__ */
13272 +
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.
13277   */
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)))
13284  
13285 -struct authen_data {
13286 -    struct identity *NAS_id;   /* user identity */
13287 -    char *server_msg;          /* null-terminated output msg */
13288 -
13289 -    int server_dlen;           /* output data length */
13290 -    char *server_data;         /* output data */
13291 -
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)))
13296  
13297 -    int client_dlen;           /* input data length */
13298 -    char *client_data;         /* input data */
13299  
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 */
13306 -};
13307 -
13308 -
13309 -/* return values for  choose_authen(); */
13310 -
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 */
13315 -
13316 -
13317 -/*
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:
13322   */
13323 -struct author_data {
13324 -    struct identity *id;       /* user id */
13325 -    int authen_method;         /* authentication method */
13326 -
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
13334 -
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 */
13340 -
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
13345 -
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 */
13350 -
13351 -};
13352 -
13353 -/* An API accounting record structure */
13354 -struct acct_rec {
13355 -    int acct_type;             /* start, stop, update */
13356 -
13357 -#define ACCT_TYPE_START      1
13358 -#define ACCT_TYPE_STOP       2
13359 -#define ACCT_TYPE_UPDATE     3
13360 -
13361 -    struct identity *identity;
13362 -    int authen_method;
13363 -    int authen_type;
13364 -    int authen_service;
13365 -    char *msg;       /* output field */
13366 -    char *admin_msg; /* output field */
13367 -    int num_args;
13368 -    char **args;
13369 -};
13370 -
13371 -#ifndef TAC_PLUS_PORT
13372 -#define        TAC_PLUS_PORT                   49
13373 +#ifdef HAVE_SYS_PARAM_H
13374 +#include <sys/param.h>
13375  #endif
13376  
13377 -/* Define tac_plus name for hosts.* files */ 
13378 -#ifdef TCPWRAPPER
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.
13384 + */
13385 +#ifndef        NULL
13386 +#define        NULL    ((void*) 0)
13387  #endif
13388  
13389 -#define TAC_PLUS_READ_TIMEOUT          180     /* seconds */
13390 -#define TAC_PLUS_WRITE_TIMEOUT         180     /* seconds */
13391 -
13392 -#define NAS_PORT_MAX_LEN                255
13393 -
13394 -struct session {
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 */
13408 -};
13409 -
13410 -extern struct session session;     /* the session */
13411 -
13412 -/* Global variables */
13413 -
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 */
13421 -
13422 -/* All tacacs+ packets have the same header format */
13423 -
13424 -struct tac_plus_pak_hdr {
13425 -    u_char version;
13426 -
13427 -#define TAC_PLUS_MAJOR_VER_MASK 0xf0
13428 -#define TAC_PLUS_MAJOR_VER      0xc0
13429 -
13430 -#define TAC_PLUS_MINOR_VER_0    0x0
13431 -#define TAC_PLUS_VER_0  (TAC_PLUS_MAJOR_VER | TAC_PLUS_MINOR_VER_0)
13432 -
13433 -#define TAC_PLUS_MINOR_VER_1    0x01
13434 -#define TAC_PLUS_VER_1  (TAC_PLUS_MAJOR_VER | TAC_PLUS_MINOR_VER_1)
13435 -
13436 -    u_char type;
13437 +#undef MAX
13438 +#define MAX(a, b)  (((a) > (b)) ? (a) : (b))
13439  
13440 -#define TAC_PLUS_AUTHEN                        1
13441 -#define TAC_PLUS_AUTHOR                        2
13442 -#define TAC_PLUS_ACCT                  3
13443 -
13444 -    u_char seq_no;             /* packet sequence number */
13445 -    u_char encryption;         /* packet is encrypted or cleartext */
13446 -
13447 -#define TAC_PLUS_ENCRYPTED 0x0         /* packet is encrypted */
13448 -#define TAC_PLUS_CLEAR     0x1         /* packet is not encrypted */
13449 -
13450 -    int session_id;            /* session identifier FIXME: Is this needed? */
13451 -    int datalength;            /* length of encrypted data following this
13452 -                                * header */
13453 -    /* datalength bytes of encrypted data */
13454 -};
13455 -
13456 -#define HASH_TAB_SIZE 157        /* user and group hash table sizes */
13457 -
13458 -#define TAC_PLUS_HDR_SIZE 12
13459 -
13460 -typedef struct tac_plus_pak_hdr HDR;
13461 -
13462 -/* Authentication packet NAS sends to us */ 
13463 -
13464 -struct authen_start {
13465 -    u_char action;
13466 -
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
13471 +#undef MIN
13472 +#define MIN(a, b)  (((a) < (b)) ? (a) : (b))
13473  
13474 -    u_char priv_lvl;
13475  
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 */
13481  
13482 -    u_char authen_type;
13483 +#define TAC_SOURCEFILE_EMPTY \
13484 +       static int dummy_unused G_GNUC_UNUSED = 0;
13485  
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
13490 -#ifdef MSCHAP
13491 -#define TAC_PLUS_AUTHEN_TYPE_MSCHAP 5
13492 -#endif /* MSCHAP */
13493  
13494 -    u_char service;
13495 -
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
13504 -
13505 -    u_char user_len;
13506 -    u_char port_len;
13507 -    u_char rem_addr_len;
13508 -    u_char data_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> */
13513 -};
13514 -
13515 -#define TAC_AUTHEN_START_FIXED_FIELDS_SIZE 8
13516 -
13517 -/* Authentication continue packet NAS sends to us */ 
13518 -struct authen_cont {
13519 -    u_short user_msg_len;
13520 -    u_short user_data_len;
13521 -    u_char flags;
13522 -
13523 -#define TAC_PLUS_CONTINUE_FLAG_ABORT 0x1
13524 -
13525 -    /* <user_msg_len bytes of u_char data> */
13526 -    /* <user_data_len bytes of u_char data> */
13527 -};
13528 -
13529 -#define TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE 5
13530 -
13531 -/* Authentication reply packet we send to NAS */ 
13532 -struct authen_reply {
13533 -    u_char status;
13534 -
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
13543 -
13544 -    u_char flags;
13545 -
13546 -#define TAC_PLUS_AUTHEN_FLAG_NOECHO     0x1
13547 -
13548 -    u_short msg_len;
13549 -    u_short data_len;
13550 -
13551 -    /* <msg_len bytes of char data> */
13552 -    /* <data_len bytes of u_char data> */
13553 -};
13554 -
13555 -#define TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE 6
13556 -
13557 -/* An authorization request packet */
13558 -struct author {
13559 -    u_char authen_method;
13560 -    u_char priv_lvl;
13561 -    u_char authen_type;
13562 -    u_char service;
13563 -
13564 -    u_char user_len;
13565 -    u_char port_len;
13566 -    u_char rem_addr_len;
13567 -    u_char arg_cnt;            /* the number of args */
13568 -
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> */
13574 -};
13575 -
13576 -#define TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE 8
13577 -
13578 -/* An authorization reply packet */
13579 -struct author_reply {
13580 -    u_char status;
13581 -    u_char arg_cnt;
13582 -    u_short msg_len;
13583 -    u_short data_len;
13584 -
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> */
13589 -};
13590 -
13591 -#define TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE 6
13592 -
13593 -struct acct {
13594 -    u_char flags;
13595 -
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
13600 -           
13601 -    u_char authen_method;
13602 -    u_char priv_lvl;
13603 -    u_char authen_type;
13604 -    u_char authen_service;
13605 -    u_char user_len;
13606 -    u_char port_len;
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 */
13614 -};
13615 -
13616 -#define TAC_ACCT_REQ_FIXED_FIELDS_SIZE 9
13617 -
13618 -struct acct_reply {
13619 -    u_short msg_len;
13620 -    u_short data_len;
13621 -    u_char status;
13622 -
13623 -#define TAC_PLUS_ACCT_STATUS_SUCCESS 0x1
13624 -#define TAC_PLUS_ACCT_STATUS_ERROR   0x2
13625 -#define TAC_PLUS_ACCT_STATUS_FOLLOW  0x21
13626 -
13627 -};
13628 -
13629 -#define TAC_ACCT_REPLY_FIXED_FIELDS_SIZE 5
13630 +#define DOLLARSIGN '$'
13631  
13632  /* Odds and ends */
13633 -#define TAC_PLUS_MAX_ITERATIONS 50
13634 -#undef MIN
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
13638  
13639 -/* Debugging flags */
13640 -
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
13657 -
13658 -extern char *codestring();
13659 -extern int keycode();
13660 -
13661 -#define TAC_IS_USER           1
13662 -#define TAC_PLUS_RECURSE      1
13663 -#define TAC_PLUS_NORECURSE    0
13664 -
13665 -#define DEFAULT_USERNAME "DEFAULT"
13666 -
13667 -#include "parse.h"
13668 -
13669 -/* Node types */
13670 -
13671 -#define N_arg           50
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
13679 -#define N_deny          58
13680 -#define N_svc           59
13681 -
13682 -/* A parse tree node */
13683 -struct 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 */
13690 -};
13691 -
13692 -typedef struct node NODE;
13693 -
13694 -union v {
13695 -    int intval;
13696 -    void *pval;
13697 -};
13698 -
13699 -typedef union v VALUE;
13700 -
13701 -/* acct.c */
13702 -extern void accounting();
13703 -
13704 -/* report.c */
13705 -extern void report_string();
13706 -extern void report_hex();
13707 -#ifdef __STDC__
13708 -extern void report(int priority, char *fmt,...);
13709 -#else
13710 -extern void report();
13711 -#endif
13712 -
13713 -/* packet.c */
13714 -extern u_char *get_authen_continue();
13715 -extern int send_authen_reply();
13716 -
13717 -/* utils.c */
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();
13723 -
13724 -/* dump.c */
13725 -extern char *summarise_outgoing_packet_type();
13726 -extern char *summarise_incoming_packet_type();
13727 -
13728 -/* author.c */
13729 -extern void author();
13730 -
13731 -/* hash.c */
13732 -extern void *hash_add_entry();
13733 -extern void **hash_get_entries();
13734 -extern void *hash_lookup();
13735 -
13736 -/* config.c */
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();
13749 -#ifdef MSCHAP
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();
13755 -#ifdef USE_PAM
13756 -extern char *cfg_get_pam_service();
13757 -#endif / *PAM */ 
13758 -extern void cfg_clean_config();
13759 -extern char *cfg_nodestring();
13760 -
13761 -/* pw.c */
13762 -extern struct passwd *tac_passwd_lookup();
13763 -
13764 -/* parse.c */
13765 -extern void parser_init();
13766 -
13767 -/* pwlib.c */
13768 -extern void set_expiration_status();
13769 -
13770  /* miscellaneous */
13771  #ifdef CONST_SYSERRLIST
13772  extern const char *const sys_errlist[];
13773  #else
13774  extern char *sys_errlist[];
13775  #endif
13776 -extern int errno;
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();
13783 -#ifdef MSCHAP
13784 -extern void mschap_lmchallengeresponse();
13785 -extern void mschap_ntchallengeresponse();
13786 -#endif /* MSCHAP */
13787 -
13788 -#ifdef MAXSESS
13789 -
13790 -extern void maxsess_loginit();
13791 -extern int maxsess_check_count();
13792 -
13793 -/*
13794 - * This is a shared file used to maintain a record of who's on
13795 - */
13796 -#define WHOLOG_DEFAULT "/var/log/tac_who.log"
13797 -extern char *wholog;
13798 -/*
13799 - * This is state kept per user/session
13800 - */
13801 -struct peruser {
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 */
13806 -};
13807 -
13808 -#endif /* MAXSESS */
13809 -
13810 -#ifdef USE_PAM
13811 -extern int tac_pam_authorization();
13812 -#endif
13813  
13814 -#define LOGFILE_DEFAULT "/var/log/tac_plus.log"
13815  
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
13824 --- /dev/null
13825 +++ b/tac_plus.pam
13826 @@ -0,0 +1,5 @@
13827 +#%PAM-1.0
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
13835 --- /dev/null
13836 +++ b/tac_plus.spec.in
13837 @@ -0,0 +1,145 @@
13838 +# This is tac_plus rpm spec file
13839 +
13840 +%define ver    @VERSION@
13841 +%define rel    1
13842 +%define prefix /usr
13843 +
13844 +Summary:       Cisco Tacacs+ Daemon
13845 +Name:          tac_plus
13846 +Version:       %ver
13847 +Release:       %rel
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
13855 +
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
13858 +
13859 +%description
13860 +TACACS+ daemon using with Cisco's NASs (Or other vendors) for AAA (Authentication , Authorization and Accounting) propose. 
13861 +
13862 +
13863 +%prep
13864 +%setup
13865 +
13866 +%build
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
13879 +
13880 +%configure --with-pam --with-db 
13881 +make
13882 +
13883 +%install
13884 +rm -rf "$RPM_BUILD_ROOT"
13885 +%makeinstall
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
13890 +
13891 +%clean
13892 +rm -rf "$RPM_BUILD_ROOT"
13893 +
13894 +%post
13895 +/sbin/chkconfig --add tac_plus
13896 +
13897 +%preun
13898 +if [ $1 = 0 ]; then
13899 +   if [ -f /var/lock/subsys/tac_plus ]; then
13900 +      %{_sysconfdir}/rc.d/init.d/tac_plus stop
13901 +   fi
13902 +   /sbin/chkconfig --del tac_plus 
13903 +fi
13904 +
13905 +%files
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/*                       
13917 +
13918 +%changelog
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
13938 +
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
13946 +
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
13953 +
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 
13960 +
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)
13966 +
13967 +* Sun Oct 24 1999 D'mon <dimone@ikar.ugol.ru>
13968 +- I moved to RedHat 6.0 =)
13969 +- changes of the package internals!
13970 +
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
13974 +
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
13978 +
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
13982 +
13983 diff --git a/tac_regexp.c b/tac_regexp.c
13984 index 9c0357a..390c5f8 100644
13985 --- a/tac_regexp.c
13986 +++ b/tac_regexp.c
13987 @@ -42,9 +42,23 @@
13988   * precedence is structured in regular expressions.  Serious changes in
13989   * regular-expression syntax might require a total rethink.
13990   */
13991 +
13992 +
13993 +#include "tac_plus.h"
13994 +
13995 +#ifdef WITH_INCLUDED_REGEX
13996 +
13997  #include <stdio.h>
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>
14004 +#endif
14005 +
14006 +#include "tac_regexp.h"
14007 +#include "tac_regmagic.h"
14008 +#include "report.h"                    /* for regerror() */
14009 +
14010  
14011  /*
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)
14015  #endif
14016  
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    "^$.[()|?+*\\"
14021  
14022 @@ -164,7 +178,7 @@
14023  /*
14024   * Global work variables for regcomp().
14025   */
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; &regdummy = don't. */
14031 @@ -173,23 +187,24 @@ static long regsize;              /* Code size. */
14032  /*
14033   * Forward declarations for regcomp()'s friends.
14034   */
14035 -#ifndef STATIC
14036 -#define        STATIC  static
14037 -#endif
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();
14048 -#ifdef STRCSPN
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));
14065  #endif
14066  
14067 +
14068  /*
14069   - regcomp - compile a regular expression into internal code
14070   *
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.
14074   */
14075 -regexp *
14076 -regcomp(exp)
14077 -char *exp;
14078 +
14079 +tac_regexp *tac_regcomp TAC_ARGS((const char *exp));
14080 +
14081 +tac_regexp *
14082 +tac_regcomp(exp)
14083 +const char *exp;
14084  {
14085 -       register regexp *r;
14086 +       register tac_regexp *r;
14087         register char *scan;
14088         register char *longest;
14089         register int len;
14090         int flags;
14091 -       extern char *malloc();
14092  
14093         if (exp == NULL)
14094                 FAIL("NULL argument");
14095 @@ -233,7 +250,7 @@ char *exp;
14096                 FAIL("regexp too big");
14097  
14098         /* Allocate space. */
14099 -       r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
14100 +       r = (tac_regexp *)malloc(sizeof(tac_regexp) + (unsigned)regsize);
14101         if (r == NULL)
14102                 FAIL("out of space");
14103  
14104 @@ -272,7 +289,7 @@ char *exp;
14105                         longest = NULL;
14106                         len = 0;
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));
14112                                 }
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.
14116   */
14117 +
14118 +static char *reg TAC_ARGS((int paren, int *flagp));
14119 +
14120  static char *
14121  reg(paren, flagp)
14122  int paren;                     /* Parenthesized? */
14123 @@ -301,7 +321,7 @@ int *flagp;
14124         register char *ret;
14125         register char *br;
14126         register char *ender;
14127 -       register int parno;
14128 +       register int parno = 0 /* GCC paranoia */;
14129         int flags;
14130  
14131         *flagp = HASWIDTH;      /* Tentatively. */
14132 @@ -365,6 +385,9 @@ int *flagp;
14133   *
14134   * Implements the concatenation operator.
14135   */
14136 +
14137 +static char *regbranch TAC_ARGS((int *flagp));
14138 +
14139  static char *
14140  regbranch(flagp)
14141  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.
14145   */
14146 +
14147 +static char *regpiece TAC_ARGS((int *flagp));
14148 +
14149  static char *
14150  regpiece(flagp)
14151  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.
14155   */
14156 +
14157 +static char *regatom TAC_ARGS((int *flagp));
14158 +
14159  static char *
14160  regatom(flagp)
14161  int *flagp;
14162 @@ -577,9 +606,12 @@ int *flagp;
14163  /*
14164   - regnode - emit a node
14165   */
14166 +
14167 +static char *regnode TAC_ARGS((int op));
14168 +
14169  static char *                  /* Location. */
14170  regnode(op)
14171 -char op;
14172 +int op;                                /* promoted "char" type */
14173  {
14174         register char *ret;
14175         register char *ptr;
14176 @@ -602,9 +634,12 @@ char op;
14177  /*
14178   - regc - emit (if appropriate) a byte of code
14179   */
14180 +
14181 +static void regc TAC_ARGS((int b));
14182 +
14183  static void
14184  regc(b)
14185 -char b;
14186 +int b;                         /* promoted "char" type */
14187  {
14188         if (regcode != &regdummy)
14189                 *regcode++ = b;
14190 @@ -617,9 +652,12 @@ char b;
14191   *
14192   * Means relocating the operand.
14193   */
14194 +
14195 +static void reginsert TAC_ARGS((int op, char *opnd));
14196 +
14197  static void
14198  reginsert(op, opnd)
14199 -char op;
14200 +int op;                                /* promoted "char" type */
14201  char *opnd;
14202  {
14203         register char *src;
14204 @@ -646,6 +684,9 @@ char *opnd;
14205  /*
14206   - regtail - set the next-pointer at the end of a node chain
14207   */
14208 +
14209 +static void regtail TAC_ARGS((char *p, char *val));
14210 +
14211  static void
14212  regtail(p, val)
14213  char *p;
14214 @@ -678,6 +719,9 @@ char *val;
14215  /*
14216   - regoptail - regtail on operand of first argument; nop if operandless
14217   */
14218 +
14219 +static void regoptail TAC_ARGS((char *p, char *val));
14220 +
14221  static void
14222  regoptail(p, val)
14223  char *p;
14224 @@ -696,44 +740,40 @@ char *val;
14225  /*
14226   * Global work variables for regexec().
14227   */
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. */
14236  
14237 -/*
14238 - * Forwards.
14239 - */
14240 -STATIC int regtry();
14241 -STATIC int regmatch();
14242 -STATIC int regrepeat();
14243  
14244  #ifdef DEBUG
14245  int regnarrate = 0;
14246 -void regdump();
14247 -STATIC char *regprop();
14248 +static char *regprop TAC_ARGS((char *op));
14249 +static void regdump TAC_ARGS((tac_regexp *r));
14250  #endif
14251  
14252  /*
14253   - regexec - match a regexp against a string
14254   */
14255 +
14256 +int tac_regexec TAC_ARGS((register tac_regexp *prog, register const char *string));
14257 +
14258  int
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;
14265  {
14266 -       register char *s;
14267 -       extern char *strchr();
14268 +       register const char *s;
14269  
14270         /* Be paranoid... */
14271         if (prog == NULL || string == NULL) {
14272 -               regerror("NULL parameter");
14273 +               tac_regerror("NULL parameter");
14274                 return(0);
14275         }
14276  
14277         /* Check validity of program. */
14278         if (UCHARAT(prog->program) != MAGIC) {
14279 -               regerror("corrupted program");
14280 +               tac_regerror("corrupted program");
14281                 return(0);
14282         }
14283  
14284 @@ -779,14 +819,17 @@ register char *string;
14285  /*
14286   - regtry - try match at specific point
14287   */
14288 +
14289 +static int regtry TAC_ARGS((tac_regexp *prog, const char *string));
14290 +
14291  static int                     /* 0 failure, 1 success */
14292  regtry(prog, string)
14293 -regexp *prog;
14294 -char *string;
14295 +tac_regexp *prog;
14296 +const char *string;
14297  {
14298         register int i;
14299 -       register char **sp;
14300 -       register char **ep;
14301 +       register const char **sp;
14302 +       register const char **ep;
14303  
14304         reginput = string;
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
14308   * by recursion.
14309   */
14310 +
14311 +static int regmatch TAC_ARGS((char *prog));
14312 +
14313  static int                     /* 0 failure, 1 success */
14314  regmatch(prog)
14315  char *prog;
14316  {
14317         register char *scan;    /* Current node. */
14318         char *next;             /* Next node. */
14319 -       extern char *strchr();
14320  
14321         scan = prog;
14322  #ifdef DEBUG
14323 @@ -888,7 +933,7 @@ char *prog;
14324                 case OPEN+8:
14325                 case OPEN+9: {
14326                                 register int no;
14327 -                               register char *save;
14328 +                               register const char *save;
14329  
14330                                 no = OP(scan) - OPEN;
14331                                 save = reginput;
14332 @@ -916,7 +961,7 @@ char *prog;
14333                 case CLOSE+8:
14334                 case CLOSE+9: {
14335                                 register int no;
14336 -                               register char *save;
14337 +                               register const char *save;
14338  
14339                                 no = OP(scan) - CLOSE;
14340                                 save = reginput;
14341 @@ -935,7 +980,7 @@ char *prog;
14342                         }
14343                         break;
14344                 case BRANCH: {
14345 -                               register char *save;
14346 +                               register const char *save;
14347  
14348                                 if (OP(next) != BRANCH)         /* No choice. */
14349                                         next = OPERAND(scan);   /* Avoid recursion. */
14350 @@ -956,7 +1001,7 @@ char *prog;
14351                 case PLUS: {
14352                                 register char nextch;
14353                                 register int no;
14354 -                               register char *save;
14355 +                               register const char *save;
14356                                 register int min;
14357  
14358                                 /*
14359 @@ -985,7 +1030,7 @@ char *prog;
14360                         return(1);      /* Success! */
14361                         break;
14362                 default:
14363 -                       regerror("memory corruption");
14364 +                       tac_regerror("memory corruption");
14365                         return(0);
14366                         break;
14367                 }
14368 @@ -997,21 +1042,23 @@ char *prog;
14369          * We get here only if there's trouble -- normally "case END" is
14370          * the terminating point.
14371          */
14372 -       regerror("corrupted pointers");
14373 +       tac_regerror("corrupted pointers");
14374         return(0);
14375  }
14376  
14377  /*
14378   - regrepeat - repeatedly match something simple, report how many
14379   */
14380 +
14381 +static int regrepeat TAC_ARGS((char *p));
14382 +
14383  static int
14384  regrepeat(p)
14385  char *p;
14386  {
14387         register int count = 0;
14388 -       register char *scan;
14389 +       register const char *scan;
14390         register char *opnd;
14391 -       extern char *strchr();
14392  
14393         scan = reginput;
14394         opnd = OPERAND(p);
14395 @@ -1039,7 +1086,7 @@ char *p;
14396                 }
14397                 break;
14398         default:                /* Oh dear.  Called inappropriately. */
14399 -               regerror("internal foulup");
14400 +               tac_regerror("internal foulup");
14401                 count = 0;      /* Best compromise. */
14402                 break;
14403         }
14404 @@ -1051,6 +1098,9 @@ char *p;
14405  /*
14406   - regnext - dig the "next" pointer out of a node
14407   */
14408 +
14409 +static char *regnext TAC_ARGS((register char *p));
14410 +
14411  static char *
14412  regnext(p)
14413  register char *p;
14414 @@ -1072,19 +1122,19 @@ register char *p;
14415  
14416  #ifdef DEBUG
14417  
14418 -STATIC char *regprop();
14419 -
14420  /*
14421   - regdump - dump a regexp onto stdout in vaguely comprehensible form
14422   */
14423 -void
14424 +
14425 +static void regdump TAC_ARGS((tac_regexp *r));
14426 +
14427 +static void
14428  regdump(r)
14429 -regexp *r;
14430 +tac_regexp *r;
14431  {
14432         register char *s;
14433         register char op = EXACTLY;     /* Arbitrary non-END op. */
14434         register char *next;
14435 -       extern char *strchr();
14436  
14437  
14438         s = r->program + 1;
14439 @@ -1121,6 +1171,9 @@ regexp *r;
14440  /*
14441   - regprop - printable representation of opcode
14442   */
14443 +
14444 +static char *regprop TAC_ARGS((char *op));
14445 +
14446  static char *
14447  regprop(op)
14448  char *op;
14449 @@ -1192,7 +1245,7 @@ char *op;
14450                 p = "PLUS";
14451                 break;
14452         default:
14453 -               regerror("corrupted opcode");
14454 +               tac_regerror("corrupted opcode");
14455                 break;
14456         }
14457         if (p != NULL)
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.
14461   */
14462 -#ifdef STRCSPN
14463 +#ifndef HAVE_STRCSPN
14464  /*
14465   * strcspn - find length of initial segment of s1 consisting entirely
14466   * of characters not from s2
14467   */
14468  
14469 +static int strcspn TAC_ARGS((char *s1, char *s2));
14470 +
14471  static int
14472  strcspn(s1, s2)
14473  char *s1;
14474 @@ -1231,4 +1286,10 @@ char *s2;
14475         }
14476         return(count);
14477  }
14478 -#endif
14479 +#endif /* HAVE_STRCSPN */
14480 +
14481 +#else /* WITH_INCLUDED_REGEX */
14482 +
14483 +TAC_SOURCEFILE_EMPTY
14484 +
14485 +#endif /* WITH_INCLUDED_REGEX */
14486 diff --git a/tac_regexp.h b/tac_regexp.h
14487 index b23d97e..7a1a884 100644
14488 --- a/tac_regexp.h
14489 +++ b/tac_regexp.h
14490 @@ -1,3 +1,10 @@
14491 +#ifndef TAC_REGEXP_H
14492 +#define TAC_REGEXP_H 1
14493 +
14494 +#include "tac_plus.h"
14495 +
14496 +#ifdef WITH_INCLUDED_REGEX
14497 +
14498  /*
14499     Copyright (c) 1995-1998 by Cisco systems, Inc.
14500  
14501 @@ -17,6 +24,7 @@
14502     FITNESS FOR A PARTICULAR PURPOSE.
14503  */
14504  
14505 +
14506  /*
14507   * Definitions etc. for regexp(3) routines.
14508   *
14509 @@ -24,17 +32,21 @@
14510   * not the System V one.
14511   */
14512  #define NSUBEXP  10
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. */
14524 -} regexp;
14525 +} tac_regexp;
14526 +
14527 +
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));
14530 +
14531 +
14532 +#endif /* WITH_INCLUDED_REGEX */
14533  
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
14543 @@ -1,3 +1,8 @@
14544 +#ifndef REGMAGIC_H
14545 +#define REGMAGIC_H 1
14546 +
14547 +#include "tac_plus.h"
14548 +
14549  /*
14550     Copyright (c) 1995-1998 by Cisco systems, Inc.
14551  
14552 @@ -17,8 +22,12 @@
14553     FITNESS FOR A PARTICULAR PURPOSE.
14554  */
14555  
14556 +
14557  /*
14558   * The first byte of the regexp internal "program" is actually this magic
14559   * number; the start node begins in the second byte.
14560   */
14561  #define        MAGIC   0234
14562 +
14563 +
14564 +#endif /* REGMAGIC_H */
14565 diff --git a/tcpwrap.c b/tcpwrap.c
14566 index ef3d3ad..744a1df 100644
14567 --- a/tcpwrap.c
14568 +++ b/tcpwrap.c
14569 @@ -4,21 +4,41 @@
14570     Writen by Devrim SERAL<devrim@gazi.edu.tr>. This file protected by
14571     GNU Copyright agreement.
14572  */
14573 +
14574 +
14575 +#include "tac_plus.h"
14576 +
14577  #ifdef TCPWRAPPER
14578 +
14579  #include <tcpd.h>
14580 -#include "tac_plus.h"
14581  
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" */
14587 +#include "main.h"
14588 +
14589 +
14590 +int allow_severity = LOG_INFO;         /* *_severity accessed from libwrap */
14591  int deny_severity = LOG_WARNING;
14592  
14593  
14594 +/* Configurable:
14595 + */
14596 +
14597 +/* Define tac_plus name for hosts.* files */
14598 +#define        TACNAME                         "tac_plus"
14599 +
14600 +
14601 +int check_from_wrap TAC_ARGS((struct identity *datap));
14602 +
14603  int
14604  check_from_wrap(datap)
14605  struct identity *datap;
14606  {
14607      struct request_info req;
14608  
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))
14613        {
14614 @@ -34,4 +54,9 @@ struct identity *datap;
14615  return 1;
14616  
14617  }
14618 +
14619 +#else /* TCPWRAPPER */
14620 +
14621 +TAC_SOURCEFILE_EMPTY
14622 +
14623  #endif /* TCPWRAPPER */
14624 diff --git a/tcpwrap.h b/tcpwrap.h
14625 new file mode 100644
14626 index 0000000..e8e9455
14627 --- /dev/null
14628 +++ b/tcpwrap.h
14629 @@ -0,0 +1,16 @@
14630 +#ifndef TCPWRAP_H
14631 +#define TCPWRAP_H 1
14632 +
14633 +#include "tac_plus.h"
14634 +
14635 +#ifdef TCPWRAPPER
14636 +
14637 +
14638 +struct identity;
14639 +
14640 +extern int check_from_wrap TAC_ARGS((struct identity *datap));
14641 +
14642 +
14643 +#endif /* TCPWRAPPER */
14644 +
14645 +#endif /* TCPWRAP_H */
14646 diff --git a/time_limit.c b/time_limit.c
14647 index 08f6c55..75062f2 100644
14648 --- a/time_limit.c
14649 +++ b/time_limit.c
14650 @@ -25,180 +25,224 @@ Software Foundation; either version 2, or (at your option) any later version.
14651  
14652  */
14653  
14654 -#include"time_limit.h"
14655 +
14656  #include "tac_plus.h"
14657  
14658 -int problem=0;
14659 +#include <stdlib.h>
14660 +#include <string.h>
14661 +#include <ctype.h>
14662 +#include <time.h>
14663 +
14664 +#include "time_limit.h"
14665 +#include "report.h"
14666 +#include "main.h"
14667 +#include "utils.h"
14668 +
14669 +
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));
14674 +
14675 +
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};
14678 +
14679 +static int problem = 0;
14680 +
14681 +
14682 +int time_limit_process TAC_ARGS((const char *str));
14683  
14684  int
14685  time_limit_process(str)
14686 -char *str;
14687 +const char *str;
14688  {
14689 -int ret=0;
14690 -char *tmp_str;
14691 +    int ret=0;
14692 +    char *tmp_str, *str_copy;
14693  
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,",|");
14700 +
14701 +    while ( tmp_str != NULL) {
14702 +       ret |= str_token_proc(tmp_str);
14703 +       tmp_str = (char *) strtok(NULL,",");
14704      }
14705 -return (ret); 
14706 +    free(str_copy);
14707 +
14708 +    return (ret);
14709  }
14710  
14711 -int 
14712 +static int str_token_proc TAC_ARGS((char *str));
14713 +
14714 +static int
14715  str_token_proc(str)
14716  char *str;
14717  {
14718 -int inv=0,ret;
14719 +    int inv = 0, ret;
14720  
14721 -/* Pass space characters */ 
14722 -while (isspace(*str)) str++;
14723 +    /* Pass space characters */
14724 +    while (isspace((int) *str))
14725 +       str++;
14726  
14727 -if (*str=='!') { 
14728 -               inv=1;str++; 
14729 -}
14730 +    if (*str=='!') {
14731 +       inv=1;
14732 +       str++;
14733 +    }
14734  
14735 -ret=process(str);
14736 +    ret=process(str);
14737  
14738 -if (problem) {
14739 +    if (problem) {
14740         if ( debug & DEBUG_AUTHEN_FLAG )
14741             report(LOG_DEBUG,"Timestamp format incorrect");
14742         problem=0;
14743         return(0);
14744 -} 
14745 +    }
14746  
14747 -if (inv) 
14748 +    if (inv)
14749         ret=!ret;
14750 -return(ret);   
14751 +
14752 +    return(ret);
14753  }
14754  
14755  
14756 -int
14757 +static void str_up TAC_ARGS((char *str));
14758 +
14759 +static void
14760 +str_up(str)
14761 +char *str;
14762 +{
14763 +    while (*str) {
14764 +       if (islower((int) *str))
14765 +           *str = toupper((int) *str);
14766 +       str++;
14767 +    }
14768 +}
14769 +
14770 +
14771 +static int process TAC_ARGS((char *str));
14772 +
14773 +static int
14774  process(str)
14775  char *str;
14776  {
14777 -int count=0,ret=0,i,j,localtm;
14778 -char *head,*buf,*gec;
14779 -long sec;
14780 -struct tm *tms;
14781 +    int count = 0, ret = 0, i, j, localtm;
14782 +    char *head, *buf, *gec;
14783 +    time_t sec;
14784 +    struct tm *tms;
14785  
14786 -/* Pass space characters  */
14787 -while (isspace(*str)) str++;
14788 +    /* Pass space characters  */
14789 +    while (isspace((int) *str))
14790 +       str++;
14791  
14792 -head=str;
14793 +    head=str;
14794  
14795 -/* Count alphanumeric char */
14796 -while (isalpha(*str)) { 
14797 +    /* Count alphanumeric char */
14798 +    while (isalpha((int) *str)) {
14799         count++;
14800         str++;
14801 -}
14802 +    }
14803  
14804 -if ( count==0 || count%2 ) { 
14805 +    if ( count==0 || count%2 ) {
14806         problem++;
14807         return 0;
14808 -}
14809 +    }
14810  
14811 -buf=(char *)malloc(count+1);
14812 -strncpy(buf,head,count);
14813 -gec=buf;
14814 -str_up(buf);
14815 +    buf = (char *) tac_malloc(count+1);
14816 +    strncpy(buf, head, count);
14817 +    gec = buf;
14818 +    str_up(buf);
14819  
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];
14824 -                }
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];
14829 +       gec += 2;
14830      }
14831 -       gec+=2;
14832 -}
14833  
14834 -/* We finished to use buffer so free it */
14835 -free(buf);
14836 +    /* We finished to use buffer so free it */
14837 +    free(buf);
14838  
14839 -sec=time(0);
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);
14847  
14848 -if (ret>0) 
14849 +    if (ret>0)
14850         return (1);
14851 -else 
14852 -       return(0); 
14853 +    else
14854 +       return (0);
14855  }
14856  
14857 -str_up(str)
14858 -char *str;
14859 -{
14860 -  while(*str) {
14861 -       if(islower(*str)) *str=toupper(*str);
14862 -       str++;
14863 -  }
14864 -}
14865  
14866 -int 
14867 -time_calc(str,lct)
14868 +static int time_calc TAC_ARGS((char *str, int lct));
14869 +
14870 +static int
14871 +time_calc(str, lct)
14872  char *str;
14873  int lct;
14874  {
14875 -char *t1,*t2,*head;
14876 -int say1,say2,count=0;
14877 +    char *t1, *t2, *head;
14878 +    int say1, say2, count=0;
14879  
14880 -head=str;
14881 +    head = str;
14882  
14883 - while (isdigit(*head) || *head=='-') {
14884 +    while (isdigit((int) *head) || *head=='-') {
14885          count++;
14886         head++;
14887      }
14888  
14889 -if (*str=='\0' || count!= TPL ) {
14890 +    if ( *str=='\0' || count!= TPL ) {
14891         problem++;
14892         return (0);
14893 -}
14894 +    }
14895  
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 */
14900  
14901 -  t2=(char *) strstr(t1,"-"); /* Find next time part */
14902 +    t2 = (char *) strstr(t1,"-");              /* Find next time part */
14903  
14904 -if (t2==NULL) {
14905 +    if (t2==NULL) {
14906         free(t1);
14907         problem++;
14908         return(0);
14909 -}
14910 +    }
14911  
14912 -*t2='\0';t2++;
14913 +    *t2++ = '\0';
14914  
14915 -if ( strlen(t1)<4 || strlen(t2)<4 ) {
14916 +    if ( strlen(t1)<4 || strlen(t2)<4 ) {
14917         free(t1);
14918         problem++;
14919         return(0);
14920 -}
14921 -       say1=antoi(t1,2)*60+antoi(t1+2,2);
14922 -       say2=antoi(t2,2)*60+antoi(t2+2,2);
14923 +    }
14924 +    say1 = antoi(t1,2)*60 + antoi(t1+2,2);
14925 +    say2 = antoi(t2,2)*60 + antoi(t2+2,2);
14926  
14927 -free(t1);
14928 +    free(t1);
14929  
14930 -if (say1<=say2) { 
14931 -       if( (lct>=say1) && (lct<=say2) ) return(1); 
14932 -}
14933 -else {
14934 -       if( (lct>=say1) || (lct<=say2) ) return(1); 
14935 +    if (say1 <= say2) {
14936 +       if( (lct>=say1) && (lct<=say2) )
14937 +           return(1);
14938 +    } else {
14939 +       if( (lct>=say1) || (lct<=say2) )
14940 +           return(1);
14941 +    }
14942 +    return(0);
14943  }
14944 -return(0);
14945  
14946 -}
14947 +static int antoi TAC_ARGS((char *str, int n));
14948  
14949 -int 
14950 -antoi(str,n)
14951 -char *str;int n;
14952 +static int
14953 +antoi(str, n)
14954 +char *str;
14955 +int n;
14956  {
14957 -char *buf;
14958 -int ret;
14959 +    char *buf;
14960 +    int ret;
14961  
14962 -  buf=(char *) malloc(n);
14963 -  strncpy(buf,str,n);
14964 -  ret=atoi(buf);
14965 +    buf = (char *) tac_malloc(n);
14966 +    strncpy(buf, str, n);
14967 +    ret = atoi(buf);
14968      free(buf);
14969  
14970 -return(ret);
14971 +    return(ret);
14972  }
14973 diff --git a/time_limit.h b/time_limit.h
14974 index e8bb6fb..eac2096 100644
14975 --- a/time_limit.h
14976 +++ b/time_limit.h
14977 @@ -1,13 +1,14 @@
14978 -#include<stdlib.h>
14979 -#include<ctype.h>
14980 -#include<stdio.h>
14981 -#include<time.h>
14982 -#include<string.h>
14983 +#ifndef TIME_LIMIT_H
14984 +#define TIME_LIMIT_H 1
14985 +
14986 +#include "tac_plus.h"
14987 +
14988 +
14989  #define NUM 10
14990  #define TPL  9 /* time part len */
14991  
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};
14995  
14996 -extern int time_limit_process();
14997 +extern int time_limit_process TAC_ARGS((const char *str));
14998 +
14999 +
15000 +#endif /* TIME_LIMIT_H */
15001 diff --git a/users_guide b/users_guide
15002 index 2626115..c1a8cfd 100644
15003 --- a/users_guide
15004 +++ b/users_guide
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.
15008  
15009 +MEMBERSHIP IN MULTIPLE GROUPS
15010 +-----------------------------
15011 +
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:
15015 +
15016 +user = fred {
15017 +    # fred is a member of both groups: admins_company_A, admins_company_B
15018 +    member = admins_company_A
15019 +    member = admins_company_B
15020 +}
15021 +
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
15026 +}
15027 +group = admins_company_A_privilege_X {
15028 +}
15029 +group = admins_company_A_privilege_Y {
15030 +}
15031 +
15032 +group = admins_company_B {
15033 +    # group admins_company_B is not a member of any group
15034 +}
15035 +
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:
15041 +
15042 +       fred
15043 +       admins_company_A
15044 +       admins_company_A_privilege_X
15045 +       admins_company_A_privilege_Y
15046 +       admins_company_B
15047 +
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:
15050 +
15051 +group = city_X_NASes {
15052 +}
15053 +host  first.NAS.X.city {
15054 +       member = city_X_NASes
15055 +}
15056 +host second.NAS.X.city {
15057 +       member = city_X_NASes
15058 +}
15059 +
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:
15062 +
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
15065 +
15066 +The example would be re-written using "enlist" keyword as:
15067 +
15068 +group = city_X_NASes {
15069 +       enlist = host  first.NAS.X.city
15070 +       enlist = host second.NAS.X.city
15071 +}
15072 +
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:
15078 +
15079 +host =  first.NAS.X.city {
15080 +}
15081 +
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.
15085 +
15086  CONFIGURING USER AUTHENTICATION
15087  -------------------------------
15088  
15089 @@ -1013,6 +1090,229 @@ group = admin {
15090  }
15091  
15092  
15093 +CONFIGURATION RESPECTING NAS HOST OF THE USER
15094 +---------------------------------------------
15095 +
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.)
15104 +
15105 +For this purposes there exists another entity 'host':
15106 +
15107 +               user wilma
15108 +               group admin
15109 +               host 198.133.219.25
15110 +               host nas.cisco.com
15111 +
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.
15115 +
15116 +You have two methods of utilizing the differences between NASes:
15117 +
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
15121 +   member:
15122 +
15123 +       ( user "current_user" |  user DEFAULT )
15124 +        |
15125 +        +-- host "current_NAS_IP_address"
15126 +        |    |
15127 +        |    +- group DEFAULT
15128 +        |
15129 +        +-- host "current_NAS_hostname"
15130 +        |    |
15131 +        |    +-- group DEFAULT
15132 +        |
15133 +        +-- group DEFAULT
15134 +
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.
15138 +
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.
15142 +
15143 +   According to this auto-connections, you can for example permit some command
15144 +   to ALL the users on such NAS:
15145 +
15146 +user = fred {
15147 +    login = cleartext LLLL
15148 +}
15149 +host = machine.A.company {
15150 +    cmd = write  {
15151 +       permit terminal
15152 +    }
15153 +}
15154 +
15155 +   In this configuration file ALL the valid users can do "write terminal" when
15156 +   logged in on NAS "machine.A.company".
15157 +
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
15164 +   consequences.)
15165 +
15166 +authorization = recursive
15167 +user = fred {
15168 +    login = cleartext LLLL
15169 +}
15170 +host = machine.A.company {
15171 +    when = user fred {
15172 +       cmd = write  {
15173 +           permit terminal
15174 +       }
15175 +    }
15176 +}
15177 +
15178 +    This file has the same effect as:
15179 +
15180 +authorization = recursive
15181 +user = fred {
15182 +   login = cleartext LLLL
15183 +   when = host machine.A.company {
15184 +       cmd = write  {
15185 +           permit terminal
15186 +       }
15187 +    }
15188 +}
15189 +
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!
15196 +   
15197 +   Unfortunately you cannot use "when" to limit any items, just a few of them
15198 +   are possible:
15199 +
15200 +member
15201 +enlist
15202 +cmd
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)
15207 +
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.
15213 +
15214 +   "when" command has the form "when = CONDITION { BLOCK }", CONDITION can be:
15215 +
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 ...
15224 +not CONDITION
15225 +( CONDITION )
15226 +
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 )
15231 +
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.)
15235 +
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
15238 +
15239 +   Sometimes the "when" condition is so-called unresolvable. Example:
15240 +
15241 +group = GRP { }
15242 +user = USR {
15243 +    when = group GRP {
15244 +       member = GRP
15245 +       }
15246 +}
15247 +
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:
15251 +
15252 +       Unable to resolve expression from line 243, some looping occured
15253 +
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.)
15261 +
15262 +FULL RECURSIVITY
15263 +----------------
15264 +
15265 +We have written in the previous examples line:
15266 +
15267 +authorization = recursive
15268 +
15269 +This changes some behaviour of Daemon:
15270 +
15271 +1) Looping of memberships: By default any looped memberships are reported as
15272 +   error with message: recursively defined groups: ...
15273 +
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.
15279 +
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).
15285 +
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).
15293 +
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".
15297 +
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
15305 +   authorization.
15306 +
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:
15311 +
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).
15315 +
15316  USING PROGRAMS TO DO AUTHORIZATION
15317  ----------------------------------
15318  
15319 diff --git a/utils.c b/utils.c
15320 index b597e70..43b50f3 100644
15321 --- a/utils.c
15322 +++ b/utils.c
15323 @@ -17,19 +17,36 @@
15324     FITNESS FOR A PARTICULAR PURPOSE.
15325  */
15326  
15327 -#include "tac_plus.h"
15328  
15329 -#ifdef STDLIB_MALLOC
15330 +#include "tac_plus.h"
15331  
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>
15336 +#endif
15337 +#include <string.h>
15338 +#ifdef HAVE_FCNTL_H
15339 +#include <fcntl.h>     /* for "struct flock" */
15340 +#endif
15341 +#include <errno.h>
15342 +#ifdef HAVE_UNISTD_H
15343 +#include <unistd.h>
15344 +#endif
15345 +#ifdef HAVE_SYSLOG_H
15346 +#include <syslog.h>
15347 +#endif
15348 +#ifdef HAVE_SYS_SYSLOG_H
15349 +#include <sys/syslog.h>
15350 +#endif
15351  
15352 -#else /* !STDLIB_MALLOC */
15353 +#include "utils.h"
15354 +#include "report.h"
15355 +#include "main.h"
15356  
15357 -#include <malloc.h>
15358  
15359 -#endif /* STDLIB_MALLOC */
15360 +void *tac_malloc TAC_ARGS((int size));
15361  
15362 -char *
15363 +void *
15364  tac_malloc(size)
15365  int size;
15366  {
15367 @@ -49,9 +66,11 @@ int size;
15368      return (p);
15369  }
15370  
15371 -char *
15372 +void *tac_realloc TAC_ARGS((void *ptr, int size));
15373 +
15374 +void *
15375  tac_realloc(ptr, size)
15376 -char *ptr;
15377 +void *ptr;
15378  int size;
15379  {
15380      char *p;
15381 @@ -70,6 +89,9 @@ int size;
15382      return (p);
15383  }
15384  
15385 +void tac_exit TAC_ARGS((int status)) G_GNUC_NORETURN;
15386 +
15387 +void
15388  tac_exit(status)
15389  int status;
15390  {
15391 @@ -78,9 +100,11 @@ int status;
15392      exit(status);
15393  }
15394  
15395 +char *tac_strdup TAC_ARGS((const char *p));
15396 +
15397  char *
15398  tac_strdup(p)
15399 -char *p;
15400 +const char *p;
15401  {
15402      char *n = strdup(p);
15403  
15404 @@ -91,6 +115,8 @@ char *p;
15405      return (n);
15406  }
15407  
15408 +char *tac_make_string TAC_ARGS((u_char *p, int len));
15409 +
15410  char *
15411  tac_make_string(p, len)
15412  u_char *p;
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.
15416  */
15417 -char *
15418 +
15419 +const char *tac_find_substring TAC_ARGS((const char *substring, const char *string));
15420 +
15421 +const char *
15422  tac_find_substring(substring, string)
15423 -char *substring, *string;
15424 +const char *substring;
15425 +const char *string;
15426  {
15427      int len;
15428  
15429 @@ -190,6 +220,8 @@ bcmp(s1,s2,n)
15430     are at the mercy of SUN's lockd, which is probably a bad idea
15431  */
15432  
15433 +int tac_lockfd TAC_ARGS((char *filename, int lockfd));
15434 +
15435  int
15436  tac_lockfd (filename, lockfd)
15437  char *filename;
15438 @@ -273,7 +305,8 @@ int lockfd;
15439     are at the mercy of SUN's lockd, which is probably a bad idea
15440  */
15441  
15442 -int
15443 +#if 0 /* unused */
15444 +static int
15445  tac_unlockfd (filename,lockfd)
15446  char *filename;
15447  int lockfd;
15448 @@ -303,3 +336,184 @@ int lockfd;
15449      }
15450      return(0);
15451  }
15452 +#endif /* unused */
15453 +
15454 +/* Management of bidirectional lists.
15455 +*/
15456 +
15457 +#ifdef TAC_LIST_PARANOIA
15458 +
15459 +static void tac_list_check_magic TAC_ARGS((const struct tac_list *list));
15460 +
15461 +static void
15462 +tac_list_check_magic(list)
15463 +const struct tac_list *list;
15464 +{
15465 +   if (list->_magic != TAC_LIST_MAGIC)
15466 +       report(LOG_ERR, "MAGIC fail for tac_list");
15467 +}
15468 +
15469 +static void tac_list_node_check_magic TAC_ARGS((const struct tac_list_node *node));
15470 +
15471 +static void
15472 +tac_list_node_check_magic(node)
15473 +const struct tac_list_node *node;
15474 +{
15475 +   if (node->_magic != TAC_LIST_NODE_MAGIC)
15476 +       report(LOG_ERR, "MAGIC fail for tac_list_node");
15477 +}
15478 +#else /* TAC_LIST_PARANOIA */
15479 +
15480 +#define tac_list_check_magic(list)
15481 +#define tac_list_node_check_magic(node)
15482 +
15483 +#endif /* TAC_LIST_PARANOIA */
15484 +
15485 +
15486 +void tac_list_init TAC_ARGS((struct tac_list *list));
15487 +
15488 +void
15489 +tac_list_init(list)
15490 +struct tac_list *list;
15491 +{
15492 +#ifdef TAC_LIST_PARANOIA
15493 +    list->_magic = TAC_LIST_MAGIC;
15494 +#endif
15495 +    list->_head = NULL;
15496 +    list->_tail = NULL;
15497 +
15498 +    tac_list_check_magic(list);
15499 +}
15500 +
15501 +void tac_list_node_init TAC_ARGS((struct tac_list_node *node));
15502 +
15503 +void
15504 +tac_list_node_init(node)
15505 +struct tac_list_node *node;
15506 +{
15507 +#ifdef TAC_LIST_PARANOIA
15508 +    node->_magic = TAC_LIST_NODE_MAGIC;
15509 +#endif
15510 +    node->_list = NULL;
15511 +
15512 +    tac_list_node_check_magic(node);
15513 +}
15514 +
15515 +struct tac_list *tac_list_node_get_list TAC_ARGS((struct tac_list_node *node));
15516 +
15517 +struct tac_list *
15518 +tac_list_node_get_list(node)
15519 +struct tac_list_node *node;
15520 +{
15521 +    tac_list_node_check_magic(node);
15522 +
15523 +    return (node->_list);
15524 +}
15525 +
15526 +struct tac_list_node *tac_list_first_node TAC_ARGS((struct tac_list *list));
15527 +
15528 +struct tac_list_node *
15529 +tac_list_first_node(list)
15530 +struct tac_list *list;
15531 +{
15532 +    tac_list_check_magic(list);
15533 +
15534 +    return (list->_head);
15535 +}
15536 +
15537 +#if 0 /* unused */
15538 +struct tac_list_node *tac_list_last_node TAC_ARGS((struct tac_list *list));
15539 +
15540 +struct tac_list_node *
15541 +tac_list_last_node(list)
15542 +struct tac_list *list;
15543 +{
15544 +    tac_list_check_magic(list);
15545 +
15546 +    return (list->_tail);
15547 +}
15548 +#endif /* unused */
15549 +
15550 +void tac_list_addhead TAC_ARGS((struct tac_list *list, struct tac_list_node *node));
15551 +
15552 +void
15553 +tac_list_addhead(list, node)
15554 +struct tac_list *list;
15555 +struct tac_list_node *node;
15556 +{
15557 +    tac_list_check_magic(list);
15558 +    tac_list_node_check_magic(node);
15559 +
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;
15567 +}
15568 +
15569 +void tac_list_addtail TAC_ARGS((struct tac_list *list, struct tac_list_node *node));
15570 +
15571 +void
15572 +tac_list_addtail(list, node)
15573 +struct tac_list *list;
15574 +struct tac_list_node *node;
15575 +{
15576 +    tac_list_check_magic(list);
15577 +    tac_list_node_check_magic(node);
15578 +
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;
15586 +}
15587 +
15588 +struct tac_list_node *tac_list_node_next TAC_ARGS((struct tac_list_node *node));
15589 +
15590 +struct tac_list_node *
15591 +tac_list_node_next(node)
15592 +struct tac_list_node *node;
15593 +{
15594 +    tac_list_node_check_magic(node);
15595 +
15596 +    return (node->_next);
15597 +}
15598 +    
15599 +#if 0 /* unused */
15600 +struct tac_list_node *tac_list_node_prev TAC_ARGS((struct tac_list_node *node));
15601 +
15602 +struct tac_list_node *
15603 +tac_list_node_prev(node)
15604 +struct tac_list_node *node;
15605 +{
15606 +    tac_list_node_check_magic(node);
15607 +
15608 +    return (node->_prev);
15609 +}
15610 +#endif /* unused */
15611 +
15612 +void tac_list_node_remove TAC_ARGS((struct tac_list_node *node));
15613 +
15614 +void
15615 +tac_list_node_remove(node)
15616 +struct tac_list_node *node;
15617 +{
15618 +    tac_list_node_check_magic(node);
15619 +    tac_list_check_magic(node->_list);
15620 +
15621 +    if (node->_next)
15622 +       node->_next->_prev = node->_prev;
15623 +    else
15624 +       node->_list->_tail = node->_prev;
15625 +
15626 +    if (node->_prev)
15627 +       node->_prev->_next = node->_next;
15628 +    else
15629 +       node->_list->_head = node->_next;
15630 +
15631 +    node->_list = NULL;
15632 +}
15633 diff --git a/utils.h b/utils.h
15634 new file mode 100644
15635 index 0000000..f8c39e8
15636 --- /dev/null
15637 +++ b/utils.h
15638 @@ -0,0 +1,59 @@
15639 +#ifndef UTILS_H
15640 +#define UTILS_H 1
15641 +
15642 +#include "tac_plus.h"
15643 +
15644 +#include <sys/types.h>         /* for u_* */
15645 +
15646 +
15647 +/* Configurable:
15648 + */
15649 +#define TAC_LIST_PARANOIA 1
15650 +
15651 +
15652 +/* Bidirectional lists */
15653 +
15654 +#ifdef TAC_LIST_PARANOIA
15655 +#define TAC_LIST_MAGIC      (0xBEF78147U)
15656 +#define TAC_LIST_NODE_MAGIC (0x297DA735U)
15657 +#endif
15658 +
15659 +struct tac_list {
15660 +#ifdef TAC_LIST_PARANOIA
15661 +    unsigned _magic;
15662 +#endif
15663 +    struct tac_list_node *_head, *_tail;
15664 +};
15665 +
15666 +struct tac_list_node {
15667 +#ifdef TAC_LIST_PARANOIA
15668 +    unsigned _magic;
15669 +#endif
15670 +    struct tac_list_node *_next, *_prev;
15671 +    struct tac_list *_list;
15672 +};
15673 +
15674 +
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));
15682 +
15683 +/* Bidirectional lists: */
15684 +
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));
15695 +
15696 +
15697 +#endif /* UTILS_H */