home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume44 / mailagent / patch14 < prev    next >
Internet Message Format  |  1994-09-22  |  46KB

  1. From: Raphael Manfredi <ram@acri.fr>
  2. Newsgroups: comp.sources.misc
  3. Subject: v44i088:  mailagent - Flexible mail filtering and processing package, v3.0, Patch14
  4. Date: 22 Sep 1994 12:13:09 -0500
  5. Organization: Advanced Computer Research Institute, Lyon, France
  6. Sender: kent@sparky.sterling.com
  7. Approved: kent@sparky.sterling.com
  8. Message-ID: <35sdv5$r5c@sparky.sterling.com>
  9. X-Md4-Signature: e92b7f719734101e1dc4f203bab5ae54
  10.  
  11. Submitted-by: Raphael Manfredi <ram@acri.fr>
  12. Posting-number: Volume 44, Issue 88
  13. Archive-name: mailagent/patch14
  14. Environment: UNIX, Perl
  15. Patch-To: mailagent: Volume 41, Issue 1-26
  16.  
  17. [The latest patch for mailagent version 3.0 is #16.]
  18.  
  19. System: mailagent version 3.0
  20. Patch #: 14
  21. Priority: MEDIUM
  22. Subject: patch #12, continued
  23. Date: Thu Sep 22 17:04:34 MET DST 1994
  24. From: Raphael Manfredi <ram@acri.fr>
  25.  
  26. Description:
  27.     See patch #12.
  28.  
  29.  
  30. Fix:    From rn, say "| patch -p -N -d DIR", where DIR is your mailagent source
  31.     directory.  Outside of rn, say "cd DIR; patch -p -N <thisarticle".
  32.     If you don't have the patch program, apply the following by hand,
  33.     or get patch (version 2.0, latest patchlevel).
  34.  
  35.     After patching:
  36.         *** DO NOTHING--INSTALL ALL PATCHES UP THROUGH #16 FIRST ***
  37.  
  38.     If patch indicates that patchlevel is the wrong version, you may need
  39.     to apply one or more previous patches, or the patch may already
  40.     have been applied.  See the patchlevel.h file to find out what has or
  41.     has not been applied.  In any event, don't continue with the patch.
  42.  
  43.     If you are missing previous patches they can be obtained from me:
  44.  
  45.         Raphael Manfredi <ram@acri.fr>
  46.  
  47.     If you send a mail message of the following form it will greatly speed
  48.     processing:
  49.  
  50.         Subject: Command
  51.         @SH mailpatch PATH mailagent 3.0 LIST
  52.                ^ note the c
  53.  
  54.     where PATH is a return path FROM ME TO YOU either in Internet notation,
  55.     or in bang notation from some well-known host, and LIST is the number
  56.     of one or more patches you need, separated by spaces, commas, and/or
  57.     hyphens.  Saying 35- says everything from 35 to the end.
  58.  
  59.     To get some more detailed instructions, send me the following mail:
  60.  
  61.         Subject: Command
  62.         @SH mailhelp PATH
  63.  
  64.  
  65. Index: patchlevel.h
  66. Prereq: 13
  67. 4c4
  68. < #define PATCHLEVEL 13
  69. ---
  70. > #define PATCHLEVEL 14
  71.  
  72. Index: agent/pl/eval.pl
  73. Prereq: 3.0
  74. *** agent/pl/eval.pl.old    Thu Sep 22 16:43:09 1994
  75. --- agent/pl/eval.pl    Thu Sep 22 16:43:09 1994
  76. ***************
  77. *** 1,4 ****
  78. ! ;# $Id: eval.pl,v 3.0 1993/11/29 13:48:42 ram Exp $
  79.   ;#
  80.   ;#  Copyright (c) 1990-1993, Raphael Manfredi
  81.   ;#  
  82. --- 1,4 ----
  83. ! ;# $Id: eval.pl,v 3.0.1.1 1994/09/22 14:18:11 ram Exp $
  84.   ;#
  85.   ;#  Copyright (c) 1990-1993, Raphael Manfredi
  86.   ;#  
  87. ***************
  88. *** 9,14 ****
  89. --- 9,17 ----
  90.   ;#  of the source tree for mailagent 3.0.
  91.   ;#
  92.   ;# $Log: eval.pl,v $
  93. + ;# Revision 3.0.1.1  1994/09/22  14:18:11  ram
  94. + ;# patch12: replaced all deprecated 'do sub' calls with '&sub'
  95. + ;#
  96.   ;# Revision 3.0  1993/11/29  13:48:42  ram
  97.   ;# Baseline for mailagent 3.0 netwide release.
  98.   ;#
  99. ***************
  100. *** 19,26 ****
  101.   
  102.   # Initialize the interpreter
  103.   sub init_interpreter {
  104. !     do set_priorities();    # Fill in %Priority
  105. !     do set_functions();        # Fill in %Function
  106.       $macro_T = "the Epoch";    # Default value for %T macro substitution
  107.   }
  108.   
  109. --- 22,29 ----
  110.   
  111.   # Initialize the interpreter
  112.   sub init_interpreter {
  113. !     &set_priorities;        # Fill in %Priority
  114. !     &set_functions;            # Fill in %Function
  115.       $macro_T = "the Epoch";    # Default value for %T macro substitution
  116.   }
  117.   
  118. ***************
  119. *** 57,63 ****
  120.   
  121.   # Print error messages -- asssumes $unit and $. correctly set.
  122.   sub error {
  123. !     do add_log("ERROR @_") if $loglvl > 1;
  124.   }
  125.   
  126.   # Add a value on the stack, modified by all the monadic operators.
  127. --- 60,66 ----
  128.   
  129.   # Print error messages -- asssumes $unit and $. correctly set.
  130.   sub error {
  131. !     &add_log("ERROR @_") if $loglvl > 1;
  132.   }
  133.   
  134.   # Add a value on the stack, modified by all the monadic operators.
  135. ***************
  136. *** 81,89 ****
  137.       local($val2) = pop(@val);        # Right value in algebraic notation
  138.       local($val1) = pop(@val);        # Left value in algebraic notation
  139.       local($func) = $Function{$op};    # Function to be called
  140. !     do macros_subst(*val1);            # Expand macros
  141. !     do macros_subst(*val2);
  142. !     push(@val, eval("do $func($val1, $val2)") ? 1: 0);
  143.   }
  144.   
  145.   # Given an operator, either we add it in the stack @op, because its
  146. --- 84,92 ----
  147.       local($val2) = pop(@val);        # Right value in algebraic notation
  148.       local($val1) = pop(@val);        # Left value in algebraic notation
  149.       local($func) = $Function{$op};    # Function to be called
  150. !     ¯os_subst(*val1);            # Expand macros
  151. !     ¯os_subst(*val2);
  152. !     push(@val, eval("&$func($val1, $val2)") ? 1: 0);
  153.   }
  154.   
  155.   # Given an operator, either we add it in the stack @op, because its
  156. ***************
  157. *** 94,104 ****
  158.   sub update_stack {
  159.       local($op) = shift(@_);        # Operator
  160.       if (!$Priority{$op}) {
  161. !         do error("illegal operator $op");
  162.           return;
  163.       } else {
  164.           if ($#val < 0) {
  165. !             do error("missing first operand for '$op' (diadic operator)");
  166.               return;
  167.           }
  168.           # Because of a bug in perl 4.0 PL19, I'm using a loop construct
  169. --- 97,107 ----
  170.   sub update_stack {
  171.       local($op) = shift(@_);        # Operator
  172.       if (!$Priority{$op}) {
  173. !         &error("illegal operator $op");
  174.           return;
  175.       } else {
  176.           if ($#val < 0) {
  177. !             &error("missing first operand for '$op' (diadic operator)");
  178.               return;
  179.           }
  180.           # Because of a bug in perl 4.0 PL19, I'm using a loop construct
  181. ***************
  182. *** 107,113 ****
  183.               $Priority{$op[$#op]} > $Priority{$op}    # Higher priority op
  184.               && $#val > 0                            # At least 2 values
  185.           ) {
  186. !             do execute();    # Execute an higer priority stacked operation
  187.           }
  188.           push(@op, $op);        # Everything at higher priority has been executed
  189.       }
  190. --- 110,116 ----
  191.               $Priority{$op[$#op]} > $Priority{$op}    # Higher priority op
  192.               && $#val > 0                            # At least 2 values
  193.           ) {
  194. !             &execute;    # Execute an higer priority stacked operation
  195.           }
  196.           push(@op, $op);        # Everything at higher priority has been executed
  197.       }
  198. ***************
  199. *** 127,169 ****
  200.           # A perl statement <<command>>
  201.           if (s/^<<//) {
  202.               if (s/^(.*)>>//) {
  203. !                 do push_val((system
  204.                       ('perl','-e', "if ($1) {exit 0;} else {exit 1;}"
  205.                       ))? 0 : 1);
  206.               } else {
  207. !                 do error("incomplete perl statement");
  208.               }
  209.           }
  210.           # A shell statement <command>
  211.           elsif (s/^<//) {
  212.               if (s/^(.*)>//) {
  213. !                 do push_val((system
  214.                       ("if $1 >/dev/null 2>&1; then exit 0; else exit 1; fi"
  215.                       ))? 0 : 1);
  216.               } else {
  217. !                 do error("incomplete shell statement");
  218.               }
  219.           }
  220.           # The '(' construct
  221.           elsif (s/^\(//) {
  222. !             do push_val(do eval_expr(*_));
  223.               # A final '\' indicates an end of line
  224. !             do error("missing final parenthesis") if !s/^\\//;
  225.           }
  226.           # Found a ')' or end of line
  227.           elsif (/^\)/ || /^$/) {
  228.               s/^\)/\\/;                        # Signals: left parenthesis found
  229.               $expr = $_;                        # Remove interpreted stuff
  230. !             do execute() while $#val > 0;    # Executed stacked operations
  231.               while ($#op >= 0) {
  232.                   $_ = pop(@op);
  233. !                 do error("missing second operand for '$_' (diadic operator)");
  234.               }
  235.               return $val[0];
  236.           }
  237.           # Diadic operators
  238.           elsif (s/^(\|\||&&|>=|<=|>|<|==|!=|=|\/=)//) {
  239. !             do update_stack($1);
  240.           }
  241.           # Unary operator '!'
  242.           elsif (s/^!//) {
  243. --- 130,172 ----
  244.           # A perl statement <<command>>
  245.           if (s/^<<//) {
  246.               if (s/^(.*)>>//) {
  247. !                 &push_val((system
  248.                       ('perl','-e', "if ($1) {exit 0;} else {exit 1;}"
  249.                       ))? 0 : 1);
  250.               } else {
  251. !                 &error("incomplete perl statement");
  252.               }
  253.           }
  254.           # A shell statement <command>
  255.           elsif (s/^<//) {
  256.               if (s/^(.*)>//) {
  257. !                 &push_val((system
  258.                       ("if $1 >/dev/null 2>&1; then exit 0; else exit 1; fi"
  259.                       ))? 0 : 1);
  260.               } else {
  261. !                 &error("incomplete shell statement");
  262.               }
  263.           }
  264.           # The '(' construct
  265.           elsif (s/^\(//) {
  266. !             &push_val(&eval_expr(*_));
  267.               # A final '\' indicates an end of line
  268. !             &error("missing final parenthesis") if !s/^\\//;
  269.           }
  270.           # Found a ')' or end of line
  271.           elsif (/^\)/ || /^$/) {
  272.               s/^\)/\\/;                        # Signals: left parenthesis found
  273.               $expr = $_;                        # Remove interpreted stuff
  274. !             &execute while $#val > 0;        # Executed stacked operations
  275.               while ($#op >= 0) {
  276.                   $_ = pop(@op);
  277. !                 &error("missing second operand for '$_' (diadic operator)");
  278.               }
  279.               return $val[0];
  280.           }
  281.           # Diadic operators
  282.           elsif (s/^(\|\||&&|>=|<=|>|<|==|!=|=|\/=)//) {
  283. !             &update_stack($1);
  284.           }
  285.           # Unary operator '!'
  286.           elsif (s/^!//) {
  287. ***************
  288. *** 171,177 ****
  289.           }
  290.           # Everything else is a value which stands for itself (atom)
  291.           elsif (s/^([\w'"%]+)//) {
  292. !             do push_val($1);
  293.           }
  294.           # Syntax error
  295.           else {
  296. --- 174,180 ----
  297.           }
  298.           # Everything else is a value which stands for itself (atom)
  299.           elsif (s/^([\w'"%]+)//) {
  300. !             &push_val($1);
  301.           }
  302.           # Syntax error
  303.           else {
  304. ***************
  305. *** 186,192 ****
  306.       local($val);                    # Value returned
  307.       local(*expr) = shift(@_);        # Expression to be parsed
  308.       while ($expr) {
  309. !         $val = do eval_expr(*expr);        # Expression will be modified
  310.           print "extra closing parenthesis ignored.\n" if $expr =~ s/^\\\)*//;
  311.           $expr = $val . $expr if $expr ne '';
  312.       }
  313. --- 189,195 ----
  314.       local($val);                    # Value returned
  315.       local(*expr) = shift(@_);        # Expression to be parsed
  316.       while ($expr) {
  317. !         $val = &eval_expr(*expr);    # Expression will be modified
  318.           print "extra closing parenthesis ignored.\n" if $expr =~ s/^\\\)*//;
  319.           $expr = $val . $expr if $expr ne '';
  320.       }
  321.  
  322. Index: agent/edusers.SH
  323. *** agent/edusers.SH.old    Thu Sep 22 16:42:47 1994
  324. --- agent/edusers.SH    Thu Sep 22 16:42:47 1994
  325. ***************
  326. *** 0 ****
  327. --- 1,104 ----
  328. + case $CONFIG in
  329. + '')
  330. +     if test -f config.sh; then TOP=.;
  331. +     elif test -f ../config.sh; then TOP=..;
  332. +     elif test -f ../../config.sh; then TOP=../..;
  333. +     elif test -f ../../../config.sh; then TOP=../../..;
  334. +     elif test -f ../../../../config.sh; then TOP=../../../..;
  335. +     else
  336. +         echo "Can't find config.sh."; exit 1
  337. +     fi
  338. +     . $TOP/config.sh
  339. +     ;;
  340. + esac
  341. + case "$0" in
  342. + */*) cd `expr X$0 : 'X\(.*\)/'` ;;
  343. + esac
  344. + echo "Extracting agent/edusers (with variable substitutions)"
  345. + $spitshell >edusers <<!GROK!THIS!
  346. + $startperl
  347. +     eval "exec perl -S \$0 \$*"
  348. +         if \$running_under_some_shell;
  349. + # $Id: edusers.SH,v 3.0.1.1 1994/09/22 13:39:28 ram Exp $
  350. + #
  351. + #  Copyright (c) 1990-1993, Raphael Manfredi
  352. + #  
  353. + #  You may redistribute only under the terms of the Artistic License,
  354. + #  as specified in the README file that comes with the distribution.
  355. + #  You may reuse parts of this distribution only within the terms of
  356. + #  that same Artistic License; a copy of which may be found at the root
  357. + #  of the source tree for mailagent 3.0.
  358. + #
  359. + # $Log: edusers.SH,v $
  360. + # Revision 3.0.1.1  1994/09/22  13:39:28  ram
  361. + # patch12: created
  362. + #
  363. + \$mversion = '$VERSION';
  364. + \$patchlevel = '$PATCHLEVEL';
  365. + \$defeditor = '$defeditor';
  366. + !GROK!THIS!
  367. + $spitshell >>edusers <<'!NO!SUBS!'
  368. + $userlist = "users";
  369. + $prog_name = $0;                # Who I am
  370. + $prog_name =~ s|^.*/(.*)|$1|;    # Keep only base name
  371. + $lockext = '.lock';                # Locking extension
  372. + *add_log = *stderr_log;            # Ensure logs will go to stderr also
  373. + $EDITOR = $ENV{'EDITOR'} || $ENV{'VISUAL'} || $defeditor;
  374. + &read_config;        # First, read configuration file (in ~/.mailagent)
  375. + &read_dist;            # Read distributions
  376. + &catch_signals;
  377. + $system = shift;        # Which system do we want
  378. + $version = shift;        # Which version it is
  379. + # If no system is specified, try locating a '.package', then source it
  380. + # to get information...
  381. + if ($system eq '') {
  382. +     die "$prog_name: you must specify a system name\n" unless &read_package;
  383. +     $system = $pkg'package;
  384. +     $version = $pkg'baserev;
  385. + }
  386. + # A single '-' or a missing version means "highest available" version.
  387. + $version = $Version{$system} if $version eq '-' || $version eq '';
  388. + # Full name of system for H table access
  389. + $pname = $system . "|" . $version;
  390. + die "$prog_name: no program called $system\n" unless $System{$system};
  391. + die "$prog_name: no package $system version $version\n"
  392. +     unless $Program{$pname};
  393. + # Go to the system directory.
  394. + chdir "$Location{$pname}" ||
  395. +     die "$prog_name: cannot go to $Location{$pname}\n";
  396. + -f $userlist || die "$prog_name: no $userlist file yet for $system $version.\n";
  397. + # Lock users file. That file should only be edited with the edusers script.
  398. + die "$prog_name: cannot lock $userlist.\n" if 0 != &acs_rqst($userlist);
  399. + system "$EDITOR $userlist";
  400. + warn "$prog_name: WARNING: edition failed...\n" if $?;
  401. + &free_file($userlist);
  402. + exit $?;
  403. + !NO!SUBS!
  404. + $grep -v '^;#' pl/fatal.pl >>edusers
  405. + $grep -v '^;#' pl/add_log.pl >>edusers
  406. + $grep -v '^;#' pl/read_conf.pl >>edusers
  407. + $grep -v '^;#' pl/distribs.pl >>edusers
  408. + $grep -v '^;#' pl/secure.pl >>edusers
  409. + $grep -v '^;#' pl/acs_rqst.pl >>edusers
  410. + $grep -v '^;#' pl/free_file.pl >>edusers
  411. + $grep -v '^;#' pl/checklock.pl >>edusers
  412. + $grep -v '^;#' pl/signals.pl >>edusers
  413. + $grep -v '^;#' pl/package.pl >>edusers
  414. + chmod 755 edusers
  415. + $eunicefix edusers
  416.  
  417. Index: agent/man/edusers.SH
  418. *** agent/man/edusers.SH.old    Thu Sep 22 16:42:56 1994
  419. --- agent/man/edusers.SH    Thu Sep 22 16:42:56 1994
  420. ***************
  421. *** 0 ****
  422. --- 1,106 ----
  423. + case $CONFIG in
  424. + '')
  425. +     if test -f config.sh; then TOP=.;
  426. +     elif test -f ../config.sh; then TOP=..;
  427. +     elif test -f ../../config.sh; then TOP=../..;
  428. +     elif test -f ../../../config.sh; then TOP=../../..;
  429. +     elif test -f ../../../../config.sh; then TOP=../../../..;
  430. +     else
  431. +         echo "Can't find config.sh."; exit 1
  432. +     fi
  433. +     . $TOP/config.sh
  434. +     ;;
  435. + esac
  436. + case "$0" in
  437. + */*) cd `expr X$0 : 'X\(.*\)/'` ;;
  438. + esac
  439. + echo "Extracting agent/man/edusers.$manext (with variable substitutions)"
  440. + $rm -f edusers.$manext
  441. + $spitshell >edusers.$manext <<!GROK!THIS!
  442. + .TH PACKAGE $manext
  443. + ''' @(#) Manual page for mailagent's edusers command
  444. + '''
  445. + ''' $Id: edusers.SH,v 3.0.1.1 1994/09/22 13:53:06 ram Exp $
  446. + '''
  447. + '''  Copyright (c) 1990-1993, Raphael Manfredi
  448. + '''  
  449. + '''  You may redistribute only under the terms of the Artistic License,
  450. + '''  as specified in the README file that comes with the distribution.
  451. + '''  You may reuse parts of this distribution only within the terms of
  452. + '''  that same Artistic License; a copy of which may be found at the root
  453. + '''  of the source tree for mailagent 3.0.
  454. + '''
  455. + ''' $Log: edusers.SH,v $
  456. + ''' Revision 3.0.1.1  1994/09/22  13:53:06  ram
  457. + ''' patch12: created
  458. + '''
  459. + ''' 
  460. + .de Ex        \" Start of Example
  461. + .sp
  462. + .in +5
  463. + .nf
  464. + ..
  465. + .de Ef        \" End of Example
  466. + .sp
  467. + .in -5
  468. + .fi
  469. + ..
  470. + .SH NAME
  471. + edusers \- edit users list created by package
  472. + .SH SYNOPSIS
  473. + \fBedusers\fR [\fIsystem\fR [\fIversion\fR]]
  474. + .SH DESCRIPTION
  475. + This command lets you safely edit the \fIusers\fR list created by the
  476. + .I package
  477. + command. It locks the file before launching the editor, hence protecting
  478. + against any concurrent update by some \fIpackage\fR command that could
  479. + arrive at the same time (by e-mail). The level of protection this locking
  480. + buys you depends on the locking policy you have configured in
  481. + your \fI~/.mailagent\fR.
  482. + .PP
  483. + If you are within a package source tree, all you need to say is
  484. + .Ex
  485. + edusers
  486. + .Ef
  487. + to edit the \fIusers\fR file for that package. In order for that particular
  488. + feature to work properly, the package must have been placed under dist control,
  489. + or at least the \fIpackinit\fR command from the dist package must have been
  490. + run.
  491. + .PP
  492. + Otherwise, you may specify
  493. + a system name, and optionally a version number if that is not enough to
  494. + disambiguate. Using '-' will get you the lattest version available.
  495. + .PP
  496. + In any case, there must be a proper setting of the \fIdistribs\fR file
  497. + to use this command. If that file is not accurate, the \fIpackage\fR
  498. + command will not be able to produce a \fIusers\fR file anyway.
  499. + .SH ENVIRONMENT
  500. + The editor is taken out of the EDITOR variable if defined, then from
  501. + the VISUAL variable, defaulting to
  502. + .I $defeditor
  503. + if none of the variables is set.
  504. + .SH FILES
  505. + .PD 0
  506. + .TP 20
  507. + ~/.mailagent
  508. + configuration file for mailagent.
  509. + .TP
  510. + Spool/distribs
  511. + distribution list, same file as the one used for mailpatch.
  512. + .TP
  513. + System/.package
  514. + file created by dist's packinit command to indicate
  515. + the root of the source tree for that package.
  516. + .TP
  517. + System/users
  518. + list of users of that system.
  519. + .TP
  520. + Log/agentlog
  521. + mailagent's log file.
  522. + .PD
  523. + .SH AUTHOR
  524. + Raphael Manfredi <ram@acri.fr>
  525. + .SH "SEE ALSO"
  526. + mailagent($manext), metaconfig($manext), package($manext), packinit($manext).
  527. + !GROK!THIS!
  528. + chmod 444 edusers.$manext
  529.  
  530. Index: agent/magent.SH
  531. Prereq: 3.0.1.2
  532. *** agent/magent.SH.old    Thu Sep 22 16:42:54 1994
  533. --- agent/magent.SH    Thu Sep 22 16:42:54 1994
  534. ***************
  535. *** 24,30 ****
  536.   # via the filter. Mine looks like this:
  537.   #   "|exec /users/ram/mail/filter >>/users/ram/.bak 2>&1"
  538.   
  539. ! # $Id: magent.SH,v 3.0.1.2 1994/07/01 14:54:29 ram Exp $
  540.   #
  541.   #  Copyright (c) 1990-1993, Raphael Manfredi
  542.   #  
  543. --- 24,30 ----
  544.   # via the filter. Mine looks like this:
  545.   #   "|exec /users/ram/mail/filter >>/users/ram/.bak 2>&1"
  546.   
  547. ! # $Id: magent.SH,v 3.0.1.3 1994/09/22 13:52:34 ram Exp $
  548.   #
  549.   #  Copyright (c) 1990-1993, Raphael Manfredi
  550.   #  
  551. ***************
  552. *** 35,40 ****
  553. --- 35,48 ----
  554.   #  of the source tree for mailagent 3.0.
  555.   #
  556.   # $Log: magent.SH,v $
  557. + # Revision 3.0.1.3  1994/09/22  13:52:34  ram
  558. + # patch12: now performs &init_constants as soon as possible
  559. + # patch12: changed interface for &queue_mail to include first 2 letters
  560. + # patch12: context is loaded earlier to initialize callout queue
  561. + # patch12: added definition for $MAX_LINKS, $S_IWOTH, $S_IWGRP and &abs
  562. + # patch12: changed &email_addr to cache its result and not rely on $cf'user
  563. + # patch12: moved &init_signals to pl/signals.pl as &catch_signals
  564. + #
  565.   # Revision 3.0.1.2  1994/07/01  14:54:29  ram
  566.   # patch8: fixed leading From date format (spacing problem)
  567.   #
  568. ***************
  569. *** 193,198 ****
  570. --- 201,207 ----
  571.   
  572.   $file_name = shift;                # File name to be processed (null if stdin)
  573.   $ENV{'IFS'}='' if $ENV{'IFS'};    # Shell separation field
  574. + &init_constants;                # Constants definitions
  575.   &get_configuration;                # Get a suitable configuration package (cf)
  576.   select(STDOUT);                    # Because the -t option writes on STDOUT,
  577.   $| = 1;                            # make sure it is flushed before we fork()
  578. ***************
  579. *** 237,249 ****
  580.   
  581.   if (!$locked && !$nolock) {
  582.       # Another mailagent is running somewhere
  583. !     &queue_mail($file_name);
  584.       exit 0;
  585.   }
  586.   
  587.   # Initialize mail filtering and compile filter rule if necessary
  588.   &init_all;
  589.   &compile_rules unless $norule;
  590.   
  591.   # If rules are to be dumped, this is the only action
  592.   if ($dump_rule) {
  593. --- 246,259 ----
  594.   
  595.   if (!$locked && !$nolock) {
  596.       # Another mailagent is running somewhere
  597. !     &queue_mail($file_name, 'fm');
  598.       exit 0;
  599.   }
  600.   
  601.   # Initialize mail filtering and compile filter rule if necessary
  602.   &init_all;
  603.   &compile_rules unless $norule;
  604. + &context'init;        # Load context, initialize callout queue
  605.   
  606.   # If rules are to be dumped, this is the only action
  607.   if ($dump_rule) {
  608. ***************
  609. *** 286,292 ****
  610.       if (0 != &analyze_mail($file_name)) {    # Analyze the mail
  611.           &add_log("ERROR while processing main message--queing it")
  612.               if ($loglvl > 0);
  613. !         &queue_mail($file_name);
  614.           unlink $lockfile;
  615.           exit 0;                    # Do not continue
  616.       } else {
  617. --- 296,302 ----
  618.       if (0 != &analyze_mail($file_name)) {    # Analyze the mail
  619.           &add_log("ERROR while processing main message--queing it")
  620.               if ($loglvl > 0);
  621. !         &queue_mail($file_name, 'fm');
  622.           unlink $lockfile;
  623.           exit 0;                    # Do not continue
  624.       } else {
  625. ***************
  626. *** 364,371 ****
  627.   
  628.   # Start-up initializations
  629.   sub init_all {
  630. !     &init_signals;        # Trap common signals
  631. !     &init_constants;    # Constants definitions
  632.       &init_interpreter;    # Initialize tables %Priority, %Function, ...
  633.       &init_env;            # Initialize the %XENV array
  634.       &init_matcher;        # Initialize special matching functions
  635. --- 374,380 ----
  636.   
  637.   # Start-up initializations
  638.   sub init_all {
  639. !     &catch_signals;        # Trap common signals
  640.       &init_interpreter;    # Initialize tables %Priority, %Function, ...
  641.       &init_env;            # Initialize the %XENV array
  642.       &init_matcher;        # Initialize special matching functions
  643. ***************
  644. *** 375,394 ****
  645.       &init_special;        # Initialize special user table %Special
  646.   }
  647.   
  648. - # Protect ourselves (trap common signals)
  649. - sub init_signals {
  650. -     $SIG{'HUP'} = 'emergency';
  651. -     $SIG{'INT'} = 'emergency';
  652. -     $SIG{'QUIT'} = 'emergency';
  653. -     $SIG{'PIPE'} = 'emergency';
  654. -     $SIG{'IO'} = 'emergency';
  655. -     $SIG{'BUS'} = 'emergency';
  656. -     $SIG{'ILL'} = 'emergency';
  657. -     $SIG{'SEGV'} = 'emergency';
  658. -     $SIG{'ALRM'} = 'emergency';
  659. -     $SIG{'TERM'} = 'emergency';
  660. - }
  661.   # Constants definitions
  662.   sub init_constants {
  663.       require 'ctime.pl';
  664. --- 384,389 ----
  665. ***************
  666. *** 398,403 ****
  667. --- 393,402 ----
  668.       $LOCK_NB = 4;                # Make a non-blocking lock request
  669.       $LOCK_UN = 8;                # Unlock the file
  670.   
  671. +     # Stat constants for file rights
  672. +     $S_IWOTH = 02;                # Writable by world (no .ph files here)
  673. +     $S_IWGRP = 020;                # Writable by group
  674.       # Status used by filter
  675.       $FT_RESTART = 0;            # Abort current action, restart from scratch
  676.       $FT_CONT = 1;                # Continue execution
  677. ***************
  678. *** 432,437 ****
  679. --- 431,439 ----
  680.       $now =~ s/\s(\d:\d\d:\d\d)\b/0$1/;    # Add leading 0 if hour < 10
  681.       chop($now);
  682.       $FAKE_FROM = "From mailagent " . $now;
  683. +     # Miscellaneous constants
  684. +     $MAX_LINKS = 100;            # Maximum number of symbolic link levels
  685.   }
  686.   
  687.   # Initializes environment. All the variables are initialized in XENV array
  688. ***************
  689. *** 493,500 ****
  690.   }
  691.   
  692.   # Computes the e-mail address of the user
  693.   sub email_addr {
  694. !     $cf'user . '@' . &domain_addr;        # E-mail address in internet format
  695.   }
  696.   
  697.   # Domain name address for current host
  698. --- 495,510 ----
  699.   }
  700.   
  701.   # Computes the e-mail address of the user
  702. + # Can't rely on the value of $cf'user since config file may not have
  703. + # been parsed when this routine is first called.
  704.   sub email_addr {
  705. !     return $email_addr_cached if defined $email_addr_cached;
  706. !     local($user);
  707. !     ($user) = getpwuid($>);
  708. !     ($user) = getpwuid($<) unless $user;
  709. !     $user = 'nobody' unless $user;
  710. !     $email_addr_cached = $user . '@' . &domain_addr;
  711. !     return $email_addr_cached;    # E-mail address in internet format
  712.   }
  713.   
  714.   # Domain name address for current host
  715. ***************
  716. *** 517,522 ****
  717. --- 527,535 ----
  718.       $path;                                # Return possibly stripped path
  719.   }
  720.   
  721. + # Compute absolute value -- on one line to avoid dataloading
  722. + sub abs { $_[0] > 0 ? $_[0] : -$_[0]; }
  723.   # Compute the system mailbox file name
  724.   sub mailbox_name {
  725.       # If ~/.mailagent provides us with a mail directory, use it and possibly
  726. ***************
  727. *** 638,642 ****
  728. --- 651,657 ----
  729.   $grep -v '^;#' pl/tilde.pl >>magent
  730.   $grep -v '^;#' pl/mh.pl >>magent
  731.   $grep -v '^;#' pl/umask.pl >>magent
  732. + $grep -v '^;#' pl/signals.pl >>magent
  733. + $grep -v '^;#' pl/callout.pl >>magent
  734.   chmod 755 magent
  735.   $eunicefix magent
  736.  
  737. Index: agent/pl/secure.pl
  738. Prereq: 3.0
  739. *** agent/pl/secure.pl.old    Thu Sep 22 16:43:23 1994
  740. --- agent/pl/secure.pl    Thu Sep 22 16:43:23 1994
  741. ***************
  742. *** 1,4 ****
  743. ! ;# $Id: secure.pl,v 3.0 1993/11/29 13:49:16 ram Exp $
  744.   ;#
  745.   ;#  Copyright (c) 1990-1993, Raphael Manfredi
  746.   ;#  
  747. --- 1,4 ----
  748. ! ;# $Id: secure.pl,v 3.0.1.1 1994/09/22 14:38:04 ram Exp $
  749.   ;#
  750.   ;#  Copyright (c) 1990-1993, Raphael Manfredi
  751.   ;#  
  752. ***************
  753. *** 9,14 ****
  754. --- 9,17 ----
  755.   ;#  of the source tree for mailagent 3.0.
  756.   ;#
  757.   ;# $Log: secure.pl,v $
  758. + ;# Revision 3.0.1.1  1994/09/22  14:38:04  ram
  759. + ;# patch12: symbolic directories are now specially handled
  760. + ;#
  761.   ;# Revision 3.0  1993/11/29  13:49:16  ram
  762.   ;# Baseline for mailagent 3.0 netwide release.
  763.   ;#
  764. ***************
  765. *** 28,34 ****
  766.           return 0;        # Unsecure file
  767.       }
  768.       local($ST_MODE) = 2 + $[;    # Field st_mode from inode structure
  769. -     local($S_IWOTH) = 02;        # Writable by world (no .ph files here)
  770.       unless (-O _) {                # Reuse stat info from -e
  771.           &add_log("WARNING you do not own $type file $file") if $loglvl > 5;
  772.           return 0;        # Unsecure file
  773. --- 31,36 ----
  774. ***************
  775. *** 38,49 ****
  776.           &add_log("WARNING $type file is world writable!") if $loglvl > 5;
  777.           return 0;        # Unsecure file
  778.       }
  779.       return 1 unless $cf'secure =~ /on/i || $< == 0;
  780.   
  781.       # Extra checks for secure mode (or if root user). We make sure the
  782.       # file is not writable by group and then we conduct the same secure tests
  783.       # on the directory itself
  784. -     local($S_IWGRP) = 020;        # Writable by group
  785.       if ($st_mode & $S_IWGRP) {
  786.           &add_log("WARNING $type file is group writable!") if $loglvl > 5;
  787.           return 0;        # Unsecure file
  788. --- 40,51 ----
  789.           &add_log("WARNING $type file is world writable!") if $loglvl > 5;
  790.           return 0;        # Unsecure file
  791.       }
  792.       return 1 unless $cf'secure =~ /on/i || $< == 0;
  793.   
  794.       # Extra checks for secure mode (or if root user). We make sure the
  795.       # file is not writable by group and then we conduct the same secure tests
  796.       # on the directory itself
  797.       if ($st_mode & $S_IWGRP) {
  798.           &add_log("WARNING $type file is group writable!") if $loglvl > 5;
  799.           return 0;        # Unsecure file
  800. ***************
  801. *** 56,77 ****
  802.           return 0;        # Unsecure directory, therefore unsecure file
  803.       }
  804.       $st_mode = (stat(_))[$ST_MODE];
  805. !     if ($st_mode & $S_IWOTH) {
  806. !         &add_log("WARNING directory of $type file is world writable!")
  807.               if $loglvl > 5;
  808.           return 0;        # Unsecure directory
  809.       }
  810. !     if ($st_mode & $S_IWGRP) {
  811. !         &add_log("WARNING directory of $type file is group writable!")
  812.               if $loglvl > 5;
  813.           return 0;        # Unsecure directory
  814.       }
  815. !     if (-l $dir) {
  816. !         &add_log("WARNING directory of $type file $file is a symbolic link")
  817.               if $loglvl > 5;
  818.           return 0;        # Unsecure directory
  819.       }
  820. !     1;        # At last! File is secure...
  821.   }
  822.   
  823. --- 58,145 ----
  824.           return 0;        # Unsecure directory, therefore unsecure file
  825.       }
  826.       $st_mode = (stat(_))[$ST_MODE];
  827. !     return 0 unless &check_st_mode($dir, 1);
  828. !     # If linkdirs is OFF, we do not check further when faced with a symbolic
  829. !     # link to a directory.
  830. !     if (-l $dir && $cf'linkdirs !~ /^off/i && !&symdir_secure($dir, $type)) {
  831. !         &add_log("WARNING directory of $type file $file is an unsecure symlink")
  832.               if $loglvl > 5;
  833.           return 0;        # Unsecure directory
  834.       }
  835. !     1;        # At last! File is secure...
  836. ! }
  837. ! # Is a symbolic link to a directory secure?
  838. ! sub symdir_secure {
  839. !     local($dir, $type) = @_;
  840. !     if (&symdir_check($dir, 0)) {
  841. !         &add_log("symbolic directory $dir for $type file is secure")
  842. !             if $loglvl > 11;
  843. !         return 1;
  844. !     }
  845. !     0;    # Not secure
  846. ! }
  847. ! # A symbolic directory (that is a symlink pointing to a directory) is secure
  848. ! # if and only if:
  849. ! #   - its target is a symlink that recursively proves to be secure.
  850. ! #   - the target lies in a non world-writable directory
  851. ! #   - the final directory at the end of the symlink chain is not world-writable
  852. ! #   - less than $MAX_LINKS levels of indirection are needed to reach a real dir
  853. ! # Unfortunately, we cannot check for group writability here for the parent
  854. ! # target directory since the target might lie in a system directory which may
  855. ! # have a legitimate need to be read/write for root and wheel, for instance.
  856. ! # The routine returns 1 if the file is secure, 0 otherwise.
  857. ! sub symdir_check {
  858. !     local($dir, $level) = @_;    # Directory, indirection level
  859. !     return 0 if $level++ > $MAX_LINKS;
  860. !     $dir = readlink($dir);
  861. !     unless (defined $dir) {
  862. !         &add_log("SYSERR readlink: $!") if $loglvl;
  863. !         return 0;
  864. !     }
  865. !     local($still_link) = -l _;
  866. !     unless (-d $dir || $still_link) {
  867. !         &add_log("ERROR inconsistency: $dir is a plain file?") if $loglvl;
  868. !         return 0;        # Reached a plain file while following links to a dir!
  869. !     }
  870. !     unless (-d "$dir/..") {
  871. !         &add_log("ERROR inconsistency: $dir/.. is not a directory?") if $loglvl;
  872. !         return 0;        # Reached a file hooked nowhere in the file system!
  873. !     }
  874. !     # Check parent directory
  875. !     local($ST_MODE) = 2 + $[;    # Field st_mode from inode structure
  876. !     $st_mode = (stat(_))[$ST_MODE];
  877. !     return 0 unless &check_st_mode("$dir/..", 0);
  878. !     # Recurse if still a symbolic link
  879. !     if ($still_link) {
  880. !         return 0 unless &symdir_check($dir, $level);
  881. !     } else {
  882. !         $st_mode = (stat($dir))[$ST_MODE];
  883. !         return 0 unless &check_st_mode($dir, 1);
  884. !     }
  885. !     1;    # Ok, link is secure
  886. ! }
  887. ! # Returns true if mode in $st_mode does not include world or group writable
  888. ! # bits, false otherwise. This helps factorizing code used in both &file_secure
  889. ! # and &symdir_check. Set $both to true if both world/group checks are desirable,
  890. ! # false to get only world checks.
  891. ! sub check_st_mode {
  892. !     local($dir, $both) = @_;
  893. !     if ($st_mode & $S_IWOTH) {
  894. !         &add_log("WARNING directory of $type file $dir is world writable!")
  895.               if $loglvl > 5;
  896.           return 0;        # Unsecure directory
  897.       }
  898. !     return 1 unless $both;
  899. !     if ($st_mode & $S_IWGRP) {
  900. !         &add_log("WARNING directory of $type file $dir is group writable!")
  901.               if $loglvl > 5;
  902.           return 0;        # Unsecure directory
  903.       }
  904. !     1;
  905.   }
  906.   
  907.  
  908. Index: agent/pl/listqueue.pl
  909. Prereq: 3.0.1.1
  910. *** agent/pl/listqueue.pl.old    Thu Sep 22 16:43:14 1994
  911. --- agent/pl/listqueue.pl    Thu Sep 22 16:43:15 1994
  912. ***************
  913. *** 1,4 ****
  914. ! ;# $Id: listqueue.pl,v 3.0.1.1 1994/07/01 15:01:45 ram Exp $
  915.   ;#
  916.   ;#  Copyright (c) 1990-1993, Raphael Manfredi
  917.   ;#  
  918. --- 1,4 ----
  919. ! ;# $Id: listqueue.pl,v 3.0.1.2 1994/09/22 14:26:00 ram Exp $
  920.   ;#
  921.   ;#  Copyright (c) 1990-1993, Raphael Manfredi
  922.   ;#  
  923. ***************
  924. *** 9,14 ****
  925. --- 9,18 ----
  926.   ;#  of the source tree for mailagent 3.0.
  927.   ;#
  928.   ;# $Log: listqueue.pl,v $
  929. + ;# Revision 3.0.1.2  1994/09/22  14:26:00  ram
  930. + ;# patch12: localized variables used by stat() and localtime()
  931. + ;# patch12: now knows about callout queue messages
  932. + ;#
  933.   ;# Revision 3.0.1.1  1994/07/01  15:01:45  ram
  934.   ;# patch8: now honours new queuehold and queuelost config variables
  935.   ;#
  936. ***************
  937. *** 26,32 ****
  938.       }
  939.       local(@dir) = readdir DIR;        # Slurp the whole directory
  940.       closedir DIR;
  941. !     local(@files) = grep(s!^(q|f)m!$cf'queue/${1}m!, @dir);
  942.       undef @dir;
  943.       if (-f "$cf'queue/$agent_wait") {
  944.           if (open(WAITING, "$cf'queue/$agent_wait")) {
  945. --- 30,36 ----
  946.       }
  947.       local(@dir) = readdir DIR;        # Slurp the whole directory
  948.       closedir DIR;
  949. !     local(@files) = grep(s!^(q|f|c)m!$cf'queue/${1}m!, @dir);
  950.       undef @dir;
  951.       if (-f "$cf'queue/$agent_wait") {
  952.           if (open(WAITING, "$cf'queue/$agent_wait")) {
  953. ***************
  954. *** 78,83 ****
  955. --- 82,92 ----
  956.   .
  957.       local($n) = $#files + 1;
  958.       local($s) = $n > 1 ? 's' : '';
  959. +     local($_);
  960. +     local($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
  961. +         $atime,$mtime,$ctime,$blksize,$blocks);
  962. +     local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst);
  963.       print STDOUT "                   Mailagent Queue ($n request$s)\n";
  964.       foreach (@files) {
  965.           ($directory, $file) = m|^(.*)/(.*)|;
  966. ***************
  967. *** 110,121 ****
  968.           ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
  969.               $atime,$mtime,$ctime,$blksize,$blocks) = stat(_);
  970.           $status = '';
  971.           # If file has 'mbox.' as part of its name, then it is an emergency
  972.           # saving done by the mailagent. If it starts with 'logname', then it
  973.           # is an emergency saving done by the filter.
  974.           $file =~ s/^mbox\.// && ($status = 'Backup');
  975.           $file =~ s/^$cf'user\.// && ($status = 'Backup');
  976. !         if ($file =~ /^qm/ && (time - $mtime) < $cf'queuehold) {
  977.               # Queue mails starting with 'qm' have been queued by the filter
  978.               # program. To avoid race conditions, those mails are skipped for
  979.               # some time (cf to pqueue subroutine).
  980. --- 119,144 ----
  981.           ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
  982.               $atime,$mtime,$ctime,$blksize,$blocks) = stat(_);
  983.           $status = '';
  984.           # If file has 'mbox.' as part of its name, then it is an emergency
  985.           # saving done by the mailagent. If it starts with 'logname', then it
  986.           # is an emergency saving done by the filter.
  987.           $file =~ s/^mbox\.// && ($status = 'Backup');
  988.           $file =~ s/^$cf'user\.// && ($status = 'Backup');
  989. !         # Check for callout queue file. If it is a 'cm' file, or it is not in
  990. !         # the queue and is recorded in the callout queue, then it is marked
  991. !         # as a callout file and the queue time printed will be the trigger
  992. !         # time.
  993. !         if (
  994. !             $file =~ /^cm/ ||
  995. !             ($directory ne $cf'queue && &callout'trigger($_))
  996. !         ) {
  997. !             $mtime = &callout'trigger($_);    # May be called twice, that's ok.
  998. !             $status = 'Callout';
  999. !         } elsif ($file =~ /^qm/ && (time - $mtime) < $cf'queuehold) {
  1000.               # Queue mails starting with 'qm' have been queued by the filter
  1001.               # program. To avoid race conditions, those mails are skipped for
  1002.               # some time (cf to pqueue subroutine).
  1003. ***************
  1004. *** 124,136 ****
  1005.               # Processing of mail allowed (mailagent -q would flush it)
  1006.               $status = 'Deferred' unless $status;
  1007.           }
  1008.           ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
  1009.               localtime($mtime);
  1010.           $queued = sprintf("%.2d/%.2d-%.2d:%.2d", ++$mon,$mday,$hour,$min);
  1011. !         $queued = 'Now' if (time - $mtime) < 60;
  1012.           $star = '';
  1013.           $star = '*' if $directory ne $cf'queue;    # Spot out-of-queue mails
  1014. !         if ((time - $mtime) > $cf'queuelost) {    # Also spot old mails
  1015.               $star = '#';
  1016.               $star = '@' if $directory ne $cf'queue;
  1017.           }
  1018. --- 147,165 ----
  1019.               # Processing of mail allowed (mailagent -q would flush it)
  1020.               $status = 'Deferred' unless $status;
  1021.           }
  1022.           ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
  1023.               localtime($mtime);
  1024.           $queued = sprintf("%.2d/%.2d-%.2d:%.2d", ++$mon,$mday,$hour,$min);
  1025. !         $queued = 'Now' if &'abs(time - $mtime) < 60;
  1026.           $star = '';
  1027.           $star = '*' if $directory ne $cf'queue;    # Spot out-of-queue mails
  1028. !         if ($status ne 'Callout') {
  1029. !             if ((time - $mtime) > $cf'queuelost) {    # Also spot old mails
  1030. !                 $star = '#';
  1031. !                 $star = '@' if $directory ne $cf'queue;
  1032. !             }
  1033. !         } elsif (time > $mtime) {    # Spot callouts that should have triggered
  1034.               $star = '#';
  1035.               $star = '@' if $directory ne $cf'queue;
  1036.           }
  1037.  
  1038. Index: agent/pl/context.pl
  1039. Prereq: 3.0
  1040. *** agent/pl/context.pl.old    Thu Sep 22 16:43:07 1994
  1041. --- agent/pl/context.pl    Thu Sep 22 16:43:08 1994
  1042. ***************
  1043. *** 1,4 ****
  1044. ! ;# $Id: context.pl,v 3.0 1993/11/29 13:48:38 ram Exp $
  1045.   ;#
  1046.   ;#  Copyright (c) 1990-1993, Raphael Manfredi
  1047.   ;#  
  1048. --- 1,4 ----
  1049. ! ;# $Id: context.pl,v 3.0.1.1 1994/09/22 14:16:30 ram Exp $
  1050.   ;#
  1051.   ;#  Copyright (c) 1990-1993, Raphael Manfredi
  1052.   ;#  
  1053. ***************
  1054. *** 9,14 ****
  1055. --- 9,19 ----
  1056.   ;#  of the source tree for mailagent 3.0.
  1057.   ;#
  1058.   ;# $Log: context.pl,v $
  1059. + ;# Revision 3.0.1.1  1994/09/22  14:16:30  ram
  1060. + ;# patch12: added access routines to detect context changes
  1061. + ;# patch12: context is now written back to disk only when changed
  1062. + ;# patch12: added callout queue knowledge
  1063. + ;#
  1064.   ;# Revision 3.0  1993/11/29  13:48:38  ram
  1065.   ;# Baseline for mailagent 3.0 netwide release.
  1066.   ;#
  1067. ***************
  1068. *** 25,32 ****
  1069.   # Initialize context from context file
  1070.   sub init {
  1071.       &default;                        # Load a default context
  1072. !     return unless -f $cf'context;    # Finished if no saved context
  1073. !     &load;                            # Load context, overwriting default context
  1074.       &clean;                            # Remove uneeded entries from context
  1075.   }
  1076.   
  1077. --- 30,37 ----
  1078.   # Initialize context from context file
  1079.   sub init {
  1080.       &default;                        # Load a default context
  1081. !     &load if -f $cf'context;        # Load context, overwriting default context
  1082. !     &callout'init;                    # Initialize callout queue
  1083.       &clean;                            # Remove uneeded entries from context
  1084.   }
  1085.   
  1086. ***************
  1087. *** 59,74 ****
  1088.   
  1089.   # Clean context, removing useless entries
  1090.   sub clean {
  1091. !     delete $Context{'last-clean'} unless $cf'autoclean =~ /^on/i;
  1092.   }
  1093.   
  1094. ! # Save a new context file
  1095.   sub save {
  1096.       require 'ctime.pl';
  1097.       local($existed) = -f $cf'context;
  1098.       &'acs_rqst($cf'context) if $existed;    # Lock existing file
  1099.       unless (open(CONTEXT, ">$cf'context")) {
  1100.           &'add_log("ERROR cannot overwrite context file: $!") if $'loglvl > 1;
  1101.           return;
  1102.       }
  1103.       &'add_log("saving context file $cf'context") if $'loglvl > 17;
  1104. --- 64,81 ----
  1105.   
  1106.   # Clean context, removing useless entries
  1107.   sub clean {
  1108. !     &delete('last-clean') if $cf'autoclean !~ /^on/i && &get('last-clean');
  1109.   }
  1110.   
  1111. ! # Save a new context file, if it has changed since we read it.
  1112.   sub save {
  1113. +     return unless $context_changed;         # Do not save if no change
  1114.       require 'ctime.pl';
  1115.       local($existed) = -f $cf'context;
  1116.       &'acs_rqst($cf'context) if $existed;    # Lock existing file
  1117.       unless (open(CONTEXT, ">$cf'context")) {
  1118.           &'add_log("ERROR cannot overwrite context file: $!") if $'loglvl > 1;
  1119. +         &'free_file($cf'context) if $existed;
  1120.           return;
  1121.       }
  1122.       &'add_log("saving context file $cf'context") if $'loglvl > 17;
  1123. ***************
  1124. *** 86,91 ****
  1125. --- 93,127 ----
  1126.   }
  1127.   
  1128.   #
  1129. + # Access features
  1130. + #
  1131. + # Add or set an entry in the context
  1132. + sub set {
  1133. +     local($entry, $value) = @_;
  1134. +     $Context{$entry} = $value;
  1135. +     $context_changed++;
  1136. + }
  1137. + # Get a context entry value
  1138. + sub get {
  1139. +     local($entry) = @_;
  1140. +     defined $Context{$entry} ? $Context{$entry} : undef;
  1141. + }
  1142. + # Delete an entry from context
  1143. + sub delete {
  1144. +     local($entry) = @_;
  1145. +     unless (defined $Context{$entry}) {
  1146. +         &'add_log("WARNING attempting to delete inexistant $entry context")
  1147. +             if $'loglvl > 5;
  1148. +         return;
  1149. +     }
  1150. +     delete $Context{$entry};
  1151. +     $context_changed++;
  1152. + }
  1153. + #
  1154.   # Context-dependant actions
  1155.   #
  1156.   
  1157. ***************
  1158. *** 96,107 ****
  1159.   sub autoclean {
  1160.       return unless $cf'autoclean =~ /^on/i;
  1161.       local($period) = &'seconds_in_period($cf'cleanlaps);
  1162. !     return if ($Context{'last-clean'} + $period) > time;
  1163.       # Retry time reached -- start auto cleaning
  1164.       &'add_log("autocleaning of dbr files") if $'loglvl > 8;
  1165.       $period = &'seconds_in_period($cf'agemax);
  1166.       &dbr'clean($period);
  1167. !     $Context{'last-clean'} = time;            # Update last cleaning time
  1168.   }
  1169.   
  1170.   #
  1171. --- 132,143 ----
  1172.   sub autoclean {
  1173.       return unless $cf'autoclean =~ /^on/i;
  1174.       local($period) = &'seconds_in_period($cf'cleanlaps);
  1175. !     return if (&get('last-clean') + $period) > time;
  1176.       # Retry time reached -- start auto cleaning
  1177.       &'add_log("autocleaning of dbr files") if $'loglvl > 8;
  1178.       $period = &'seconds_in_period($cf'agemax);
  1179.       &dbr'clean($period);
  1180. !     &set('last-clean', time);        # Update last cleaning time
  1181.   }
  1182.   
  1183.   #
  1184. ***************
  1185. *** 112,119 ****
  1186.   # the retry time was not reached. This routine is the main entry point in
  1187.   # the package, and is the only one called from the outside world.
  1188.   sub main'contextual_operations {
  1189. -     &init;                    # Initialize context
  1190.       &autoclean;                # Clean dbr hash files
  1191.       &save;                    # Save new context
  1192.   }
  1193.   
  1194. --- 148,155 ----
  1195.   # the retry time was not reached. This routine is the main entry point in
  1196.   # the package, and is the only one called from the outside world.
  1197.   sub main'contextual_operations {
  1198.       &autoclean;                # Clean dbr hash files
  1199. +     &callout'flush;            # Flush the callout queue
  1200.       &save;                    # Save new context
  1201.   }
  1202.   
  1203.  
  1204. Index: agent/filter/parser.c
  1205. Prereq: 3.0.1.2
  1206. *** agent/filter/parser.c.old    Thu Sep 22 16:42:53 1994
  1207. --- agent/filter/parser.c    Thu Sep 22 16:42:53 1994
  1208. ***************
  1209. *** 11,17 ****
  1210.   */
  1211.   
  1212.   /*
  1213. !  * $Id: parser.c,v 3.0.1.2 1994/07/01 14:53:57 ram Exp $
  1214.    *
  1215.    *  Copyright (c) 1990-1993, Raphael Manfredi
  1216.    *  
  1217. --- 11,17 ----
  1218.   */
  1219.   
  1220.   /*
  1221. !  * $Id: parser.c,v 3.0.1.3 1994/09/22 13:47:21 ram Exp $
  1222.    *
  1223.    *  Copyright (c) 1990-1993, Raphael Manfredi
  1224.    *  
  1225. ***************
  1226. *** 22,27 ****
  1227. --- 22,30 ----
  1228.    *  of the source tree for mailagent 3.0.
  1229.    *
  1230.    * $Log: parser.c,v $
  1231. +  * Revision 3.0.1.3  1994/09/22  13:47:21  ram
  1232. +  * patch12: extended security checks to mimic those done by mailagent
  1233. +  *
  1234.    * Revision 3.0.1.2  1994/07/01  14:53:57  ram
  1235.    * patch8: new routine get_confval to get integer config variables
  1236.    *
  1237. ***************
  1238. *** 52,57 ****
  1239. --- 55,67 ----
  1240.   #include <strings.h>
  1241.   #endif
  1242.   
  1243. + #ifdef I_SYS_PARAM
  1244. + #include <sys/param.h>
  1245. + #endif
  1246. + #ifndef MAX_PATHLEN
  1247. + #define MAX_PATHLEN        2048        /* Maximum path length allowed by kernel */
  1248. + #endif
  1249.   #ifndef HAS_GETHOSTNAME
  1250.   #ifdef HAS_UNAME
  1251.   #include <sys/utsname.h>
  1252. ***************
  1253. *** 180,186 ****
  1254.        * Returning from this routine implies that the security checks succeeded.
  1255.        */
  1256.   
  1257. !     struct stat buf;        /* Statistics buffer */
  1258.   
  1259.       if (-1 == stat(file, &buf)) {
  1260.           add_log(1, "SYSERR stat: %m (%e)");
  1261. --- 190,196 ----
  1262.        * Returning from this routine implies that the security checks succeeded.
  1263.        */
  1264.   
  1265. !     struct stat buf;            /* Statistics buffer */
  1266.   
  1267.       if (-1 == stat(file, &buf)) {
  1268.           add_log(1, "SYSERR stat: %m (%e)");
  1269. ***************
  1270. *** 195,204 ****
  1271.   {
  1272.       /* Check basic permissions on the specified file. It cannot be world
  1273.        * writable and must be owned by the user. If the file specified does not
  1274. !      * exist, no error is reported however.
  1275.        */
  1276.   
  1277. !     struct stat buf;        /* Statistics buffer */
  1278.   
  1279.       if (-1 == stat(file, &buf))
  1280.           return;
  1281. --- 205,220 ----
  1282.   {
  1283.       /* Check basic permissions on the specified file. It cannot be world
  1284.        * writable and must be owned by the user. If the file specified does not
  1285. !      * exist, no error is reported however. If the 'secure' option is set
  1286. !      * to ON, or if we are running with superuser credentials, further checks
  1287. !      * are performed on the directory containing the file.
  1288.        */
  1289.   
  1290. !     struct stat buf;            /* Statistics buffer */
  1291. !     char parent[MAX_PATHLEN+1];    /* For parent directory */
  1292. !     char *cfsecure;                /* Config value for the 'secure' parameter */
  1293. !     char *c;                    /* Last slash position in file name */
  1294. !     int wants_secure = 0;        /* Set to true for extra security checks */
  1295.   
  1296.       if (-1 == stat(file, &buf))
  1297.           return;
  1298. ***************
  1299. *** 212,217 ****
  1300. --- 228,290 ----
  1301.   
  1302.       if (buf.st_uid != geteuid())
  1303.           fatal("file %s not owned by user!", file);
  1304. +     cfsecure = ht_value(&symtab, "secure");    /* Do we need extra security? */
  1305. +     if (
  1306. +         (cfsecure != (char *) 0 &&            /* Ok, secure is defined */
  1307. +         0 == strcasecmp(cfsecure, "ON")) ||    /* And extra checks wanted */
  1308. +         geteuid() == ROOTID                    /* Running as superuser */
  1309. +     )
  1310. +         wants_secure = 1;                    /* Activate checks */
  1311. +             
  1312. +     if (!wants_secure) {
  1313. +         add_log(12, "basic checks ok for file %s", file);
  1314. +         return;
  1315. +     }
  1316. +     /*
  1317. +      * Extra security checks for group writability and parent directory.
  1318. +      */
  1319. +     add_log(17, "performing additional checks on %s", file);
  1320. + #ifndef S_IWGRP
  1321. + #define S_IWGRP 00020        /* Write permissions for group */
  1322. + #endif
  1323. +     if (buf.st_mode & S_IWGRP)
  1324. +         fatal("file %s is group writable!", file);
  1325. +     /*
  1326. +      * Ok, go on and check the parent directory...
  1327. +      */
  1328. +     if (*file != '/') {                /* Path is not abosule, assume from home */
  1329. +         strcpy(parent, home);        /* Prefill with home */
  1330. +         strcat(parent, "/");
  1331. +     } else
  1332. +         *parent = '\0';                /* Null string */
  1333. +     strcat(parent, file);            /* Append file to get an absolute path */
  1334. +     if (c = rindex(parent, '/'))
  1335. +         *c = '\0';                    /* Strip down last path component */
  1336. +     add_log(17, "checking directory %s", parent);
  1337. +     if (-1 == stat(parent, &buf)) {
  1338. +         add_log(1, "SYSERR stat: %m (%e)");
  1339. +         fatal("cannot stat directory %s", parent);
  1340. +     }
  1341. +     if (buf.st_mode & S_IWOTH)
  1342. +         fatal("directory %s is world writable!", parent);
  1343. +     if (buf.st_mode & S_IWGRP)
  1344. +         fatal("directory %s is group writable!", parent);
  1345. +     if (buf.st_uid != geteuid())
  1346. +         fatal("directory %s not owned by user!", parent);
  1347. +     add_log(12, "file %s seems to be secure", file);
  1348.   }
  1349.   
  1350.   public char *homedir()
  1351.  
  1352. Index: agent/pl/builtins.pl
  1353. Prereq: 3.0
  1354. *** agent/pl/builtins.pl.old    Thu Sep 22 16:43:06 1994
  1355. --- agent/pl/builtins.pl    Thu Sep 22 16:43:06 1994
  1356. ***************
  1357. *** 1,4 ****
  1358. ! ;# $Id: builtins.pl,v 3.0 1993/11/29 13:48:35 ram Exp $
  1359.   ;#
  1360.   ;#  Copyright (c) 1990-1993, Raphael Manfredi
  1361.   ;#  
  1362. --- 1,4 ----
  1363. ! ;# $Id: builtins.pl,v 3.0.1.1 1994/09/22 14:10:40 ram Exp $
  1364.   ;#
  1365.   ;#  Copyright (c) 1990-1993, Raphael Manfredi
  1366.   ;#  
  1367. ***************
  1368. *** 9,14 ****
  1369. --- 9,18 ----
  1370.   ;#  of the source tree for mailagent 3.0.
  1371.   ;#
  1372.   ;# $Log: builtins.pl,v $
  1373. + ;# Revision 3.0.1.1  1994/09/22  14:10:40  ram
  1374. + ;# patch12: added escapes in strings for perl5 support
  1375. + ;# patch12: builtins are now looked for in &run_builtins
  1376. + ;#
  1377.   ;# Revision 3.0  1993/11/29  13:48:35  ram
  1378.   ;# Baseline for mailagent 3.0 netwide release.
  1379.   ;#
  1380. ***************
  1381. *** 92,103 ****
  1382.   # The @RR command asks for a receipt
  1383.   sub builtin_rr {
  1384.       local($_) = @_;
  1385. !     &add_log("found an @RR request to $_") if $loglvl > 18;
  1386.       # @RR request honored only if not from special user and directed to us
  1387.       unless (&special_user) {
  1388.           push(@Builtcode, "&send_receipt('$_')");
  1389.       } else {
  1390. !         &add_log("ignoring @RR request to $_") if $loglvl > 4;
  1391.       }
  1392.   }
  1393.   
  1394. --- 96,107 ----
  1395.   # The @RR command asks for a receipt
  1396.   sub builtin_rr {
  1397.       local($_) = @_;
  1398. !     &add_log("found an \@RR request to $_") if $loglvl > 18;
  1399.       # @RR request honored only if not from special user and directed to us
  1400.       unless (&special_user) {
  1401.           push(@Builtcode, "&send_receipt('$_')");
  1402.       } else {
  1403. !         &add_log("ignoring \@RR request to $_") if $loglvl > 4;
  1404.       }
  1405.   }
  1406.   
  1407. ***************
  1408. *** 106,120 ****
  1409.       local($_) = @_;
  1410.       return if /[=\$^&*([{}`\\|;><?]/;        # Invalid character found
  1411.       $Userpath = $_;
  1412. !     &add_log("found an @PATH request to $_") if $loglvl > 18;
  1413.   }
  1414.   
  1415.   # Execute stacked builtins
  1416.   sub run_builtins {
  1417.       return if $#Builtcode < 0;        # No recorded builtins
  1418.       foreach (@Builtcode) {
  1419.           eval($_);                    # Execute stacked builtin
  1420.       }
  1421. !     @Builtcode = ();                # Reset builtcode array
  1422.   }
  1423.   
  1424. --- 110,136 ----
  1425.       local($_) = @_;
  1426.       return if /[=\$^&*([{}`\\|;><?]/;        # Invalid character found
  1427.       $Userpath = $_;
  1428. !     &add_log("found an \@PATH request to $_") if $loglvl > 18;
  1429.   }
  1430.   
  1431.   # Execute stacked builtins
  1432.   sub run_builtins {
  1433. +     undef @Builtcode;
  1434. +     # Lookup for builtins. Code moved out of &parse_mail.
  1435. +     foreach $line (split(/\n/, $Header{'Body'})) {
  1436. +         if ($line =~ s/^@(\w+)\s*//) {            # A builtin command ?
  1437. +             local($subroutine) = $Builtin{$1};
  1438. +             &$subroutine($line) if $subroutine;    # Record it if known
  1439. +         }
  1440. +     }
  1441. +     # End of original &parse_mail exerpt, beginning of original &run_builtins
  1442. +     # NOTE: since builtins are now looked for here and run from there directly,
  1443. +     # going through the burden of @Builtcode is not necessary. Will get fixed
  1444. +     # one day, possibly.
  1445.       return if $#Builtcode < 0;        # No recorded builtins
  1446.       foreach (@Builtcode) {
  1447.           eval($_);                    # Execute stacked builtin
  1448.       }
  1449. !     undef @Builtcode;                # Reset builtcode array
  1450.   }
  1451.   
  1452.  
  1453. *** End of Patch 14 ***
  1454.  
  1455. exit 0 # Just in case...
  1456.