jaromail

a commandline tool to easily and privately handle your e-mail
git clone git://parazyd.org/jaromail.git
Log | Files | Refs | Submodules | README

commit a4c584412c9dc16732c2201b3b2aeca88225c05f
parent 68834784349efbe0e38388d9415f2765283698e1
Author: Jaromil <jaromil@dyne.org>
Date:   Tue, 18 Sep 2012 21:58:32 +0200

tighter locking

Diffstat:
Msrc/jaro | 63++++++++++++++++++++++++++++++++++++++++++++++++---------------
Msrc/zlibs/email | 5+++--
Msrc/zlibs/filters | 4+++-
Msrc/zlibs/locking | 31+++++++++++++++++++------------
Msrc/zlibs/search | 2+-
5 files changed, 74 insertions(+), 31 deletions(-)

diff --git a/src/jaro b/src/jaro @@ -211,25 +211,54 @@ GNOMEKEY=0 cleanexit() { func "Clean exit procedures" - # while ( ps ax | grep '[s]rm' > /dev/null - # test $? = 0 ); do sleep 1; done - # for f in `ls $TMPDIR/ | grep -v '.lock$'`; do - # { test ! -r $TMPDIR/$f.lock } && { unlink $TMPDIR/$f } - # done + unset name login host protocol port password auth folders accountopt + + # security check + { test "$TMPDIR" = "" } && { + error "Temporary directory not defined" + act "skipping cleanup, this might leave private traces." + return 1 + } + + # first delete dirs + for d in `find -O3 $TMPDIR/ -maxdepth 1 -type d`; do + { test "$d" = "$TMPDIR/" } || { ${=rm} -r ${d} } + done + + # then locks, with a warning + for l in `find -O3 $TMPDIR/ -maxdepth 1 -type f -name '*.lock'`; do + lname=`basename ${(s:.lock:)l}` + + # skip if in course of unlink - parallel operation, see unlink() + { test -r ${TMPDIR}/${lname}.unlink } && { continue } + + pid="$lname.pid" + if [ -r ${pid} ]; then + error "forced removal of lock created by pid $pid: $lname" + rm -f ${TMPDIR}/${pid} + else + error "forced removal of lock created by unknown pid: $lname" + fi + rm -f ${TMPDIR}/${lock} + + # remove the actual file + if [ -r ${TMPDIR}/$lname ]; then ${=rm} ${TMPDIR}/$lname + else error "stale lock: locked file not found"; fi + + done + # { test $TMPRAM = 1 } && { rmdir $TMPDIR } - unset typeset -h name login host protocol port password auth folders accountopt } # make sure tmp is wiped from sensitive data in case of sigINT TRAPINT() { error "Caught signal, aborting operations." - { test $CLEANEXIT = 1 } && { cleanexit } - error "Forced removal of locks" - { test $TMPDIR } && { - for l in `find $TMPDIR/`; do - ${=rm} $l; done - } + + { test $CLEANEXIT = 1 } && { + error "Forced removal of locks" + cleanexit } + if [ "$DEBUG" = "1" ]; then return 1 else exit 1; fi } @@ -294,7 +323,7 @@ option_value() { usage() { - cat <<EOF + cat <<EOF | more Jaro Mail $VERSION - your humble and faithful electronic postman Copyright (C) 2010-2012 by Jaromil @ Dyne.org, License GNU GPL v3+ @@ -317,7 +346,7 @@ Options: -h print this help -v version information for this tool - -q run quietly without printing informations + -q run quietly without printing information -n dry run, show operations without executing them -D print debugging information at runtime @@ -355,7 +384,7 @@ Please report bugs on <http://bugs.dyne.org>. EOF } -# TODO: For more informations on Jaro Mail read the manual: man jaro +# TODO: For more information on Jaro Mail read the manual: man jaro typeset -A subcommands_opts main() @@ -380,6 +409,8 @@ main() subcommands_opts[peek]="R -readonly=R" subcommands_opts[open]="R -readonly=R" + subcommands_opts[help]="" + subcommands_opts[update]="" subcommands_opts[stat]="" @@ -508,6 +539,8 @@ main() update) update ;; + help) CLEANEXIT=0; usage ;; + search) CLEANEXIT=0; search ${PARAM} ;; stat) CLEANEXIT=0; stats ${PARAM} ;; diff --git a/src/zlibs/email b/src/zlibs/email @@ -82,6 +82,7 @@ fetchall() { done return $res } + fetch() { { test "$account" = "" } && { fetchall; return $? } @@ -267,8 +268,8 @@ EOF act "Mail sent succesfully" # whitelist those to whom we send mails cat ${mail} | $WORKDIR/bin/jaro -q learn recipient - ${=rm} ${mail} & - unlink ${smtp} & + ${=rm} ${mail} + unlink ${smtp} fi done unlink $tmp diff --git a/src/zlibs/filters b/src/zlibs/filters @@ -116,8 +116,9 @@ EOF ####### # SIEVE act "generating sieve filters" - id=$RANDOM + id=$datestamp.$RANDOM sieve=$WORKDIR/sieve.filter + lock $sieve rm -f $sieve touch $sieve chmod 600 $sieve @@ -319,6 +320,7 @@ if header :is "X-Spam-Flag" "YES" { EOF +unlock $sieve #### PROCMAIL diff --git a/src/zlibs/locking b/src/zlibs/locking @@ -35,21 +35,31 @@ lock() { return 0 ;; esac } + newlock() { # create locked func "creating locked file: $1" touch $1 chmod 600 $1 lock $1 } -unlock() { - func "unlock: $1" + +pidcheck() { # check if lock belongs to us lockpid="`cat ${1}.pid`" { test -r "${1}.pid" } && { { test "$$" != "$lockpid" } && { - error "Unlock attempt by different PID: $1" - error "Created by $lockpid now $$ is trying to unlock" + error "Unlock attempt by different PID on `basename $1`" + act "created by $lockpid now we ($$) try to unlock" + act "skipped removal: $1" return 1 } } + return 0 +} + +unlock() { + func "unlock: $1" + + pidcheck $1 + { test $? = 0 } || { return 1 } $WORKDIR/bin/dotlock -u ${=@} { test $? != 0 } && { error "Unable to unlock: $1"; return 1 } @@ -59,22 +69,19 @@ unlock() { unlink() { # delete a file that we are locking func "unlink: $1" # use with care! this can permanently erase currently locked files - # only the locking PID should use it on its own locks - { test -r "${1}.pid" } && { - lockpid="`cat ${1}.pid`" - { test "$$" != "$lockpid" } && { - error "Unlock attempt by different PID: $1" - error "Created by $lockpid now $$ is trying to unlock" - return 1 } - } + pidcheck $1 + { test $? = 0 } || { return 1 } + # signal that is unlinking (for parallel operation) + touch ${1}.unlink ( ${=rm} ${1} touch ${1} $WORKDIR/bin/dotlock -d -f ${1} { test $? != 0 } && { error "Unable to unlink: $1"; return 1 } { test -r "${1}.pid" } && { rm -f ${1}.pid } + rm -f ${1}.unlink ) &! return 0 } diff --git a/src/zlibs/search b/src/zlibs/search @@ -123,7 +123,7 @@ EOF } # DRYRUN ${=rm} $TMPDIR/search.db.$id ${=rm} $TMPDIR/search.conf.$id - ${=rm} $TMPDIR/search.result.$id + ${=rm} -r $TMPDIR/search.result.$id return $exitcode }