Questions
and Answers
Amy Rich
Q We use majordomo to manage a large
number of mailing lists. One of the nice features is that it checks
the message body and bounces the message to the moderator if the
message looks like something that should have gone to majordomo
instead of to the list (e.g., unsubscribe, subscribe, remove me,
etc.). Normally, this is great, since it prevents a lot of garbage
traffic on the lists, but in some cases it tends to bounce valid
mail. Is there a way to fine-tune this behavior so that we don't
get valid list mail bounced to the moderator?
A Majordomo uses a set of regular
expression matches for the Subject: header and the first ten lines
of the body. If you take a look at majordomo.cf, you'll see
the following near the end:
# List of perl regular expressions that, if found in the headers
# of a message, will cause the message to be bounced to the list
# approver. Put each regular expression on a separate line before
# the "END" mark, with no trailing ";"
# Administrative checks. These used to be buried in the resend code
$admin_headers = <<'END';
(regular expressions deleted)
END
# Common things that people send to the wrong address.
# These are caught in the first 10 lines of the message body
# if 'administrivia' is turned on and the message isn't marked
# approved.
$admin_body = <<'END';
(regular expressions deleted)
END
# taboo headers to catch
$global_taboo_headers = <<'END';
(regular expressions deleted)
END
# Taboo body contents to catch and forward to the approval address
$global_taboo_body = <<'END';
END
You can modify any of these regular expressions to suit your needs,
but having majordomo magically know that one message should be passed
and another with the same regex match should be bounced to the moderator
isn't possible.
Q We've started using ipfilter
on our Solaris 8 machines and now sshd (OpenSSH) is closing connections
to the machines if they are idle for some short period of time (say
5 minutes or so). According to the sshd_config man page, KeepAlive
should be enabled by default, so I'm not certain why this is
happening. Is there something else I can try?
A I've also seen this happen
with OpenSSH 3.7.1p2 and an ipfiltered Solaris 8 machine with some
pretty restrictive filters. You might want to explicitly enable
KeepAlive in /usr/local/etc/sshd_config or, even better, use the
ClientAliveInterval setting to send encrypted, unspoofable keepalive-style
messages to the clients. From the sshd_config man page:
ClientAliveInterval
Sets a timeout interval in seconds after which if no data has
been received from the client, sshd will send a message through
the encrypted channel to request a response from the client. The
default is 0, indicating that these messages will not be sent
to the client. This option applies to protocol version 2 only.
I generally set ClientAliveInterval to 60 so that it only sends a
message after a minute of inactivity. To tune how fast a dead connection
will time out, also take a look at the ClientAliveCountMax setting:
ClientAliveCountMax
Sets the number of client alive messages (see above) which may
be sent without sshd receiving any messages back from the client.
If this threshold is reached while client alive messages are being
sent, sshd will disconnect the client, terminating the session.
It is important to note that the use of client alive messages
is very different from KeepAlive. The client alive messages are
sent through the encrypted channel and therefore will not be spoofable.
The TCP keepalive option enabled by KeepAlive is spoofable. The
client alive mechanism is valuable when the client or server depend
on knowing when a connection has become inactive.
The default value is 3. If ClientAliveInterval (above) is set
to 15, and ClientAliveCountMax is left at the default, unresponsive
ssh clients will be disconnected after approximately 45 seconds.
Q I was talking to another sys admin
at USENIX who mentioned that sendmail has a variable called greeting_pause
that tells sendmail to wait X number of seconds before sending the
SMTP greeting message to connecting machines. If any traffic is received
before the SMTP greeting is sent, then sendmail throws the entire
connection away. This sounds like a great feature that would catch
a lot of the scripted spam that doesn't bother waiting for the
greeting and just slams the server when it connects. Unfortunately,
I've dug through all my sendmail documentation and I can't
find any reference to this variable. Do you know anything about this
sort of functionality? Is it in some sort of hack or milter add on?
A The feature you describe is actually
called greet_pause, not greeting_pause, and is only available in
sendmail 8.13. Also, the timeout is in milliseconds, not seconds,
so if you do have sendmail 8.13, be sure that you're setting
the timeout high enough. A few caveats, as well... Although this
feature does help block a lot of scripted spam, you might also wind
up rejecting valid mail from impatient servers, like verizon.net
for example, if you set your timeout too high. In your mc file,
make sure to put FEATURE('greet_pause') after FEATURE('access_db').
If you don't want to move to the development version of sendmail
but are willing to modify the sendmail 8.12.11 source code, you
can also backport the greet_pause feature by modifying sendmail-8.12.11/sendmail/srvrsmtp.c.
These directions are taken from Thomas Schulz's post to comp.mail.sendmail:
http://groups.google.com/groups?selm=cbc4tv%24p1r%241%40bluegill.adi.com&rnum=2
Edit the file and swap lines 451 and 452:
451 #if STARTTLS
452 int r;
Insert a new line of code at line 20:
#include <sm/fdset.h>
Next, add the following code from sendmail-8.13.0 at line 800 of the
sendmail-8.12.11 srvrsmtp.c source code:
/*
** Broken proxies and SMTP slammers
** push data without waiting, catch them
*/
if (
#if STARTTLS
!smtps &&
#endif /* STARTTLS */
*greetcode == '2')
{
time_t msecs = 0;
char **pvp;
char pvpbuf[PSBUFSIZE];
/* Ask the rulesets how long to pause */
pvp = NULL;
r = rscap("greet_pause", peerhostname,
anynet_ntoa(&RealHostAddr), e,
&pvp, pvpbuf, sizeof(pvpbuf));
if (r == EX_OK && pvp != NULL && pvp[0] != NULL &&
(pvp[0][0] & 0377) == CANONNET && pvp[1] != NULL)
{
msecs = strtol(pvp[1], NULL, 10);
}
if (msecs > 0)
{
int fd;
fd_set readfds;
struct timeval timeout;
/* pause for a moment */
timeout.tv_sec = msecs / 1000;
timeout.tv_usec = (msecs % 1000) * 1000;
/* Obey RFC 2821: 4.3.5.2: 220 timeout of 5 minutes */
if (timeout.tv_sec >= 300)
{
timeout.tv_sec = 300;
timeout.tv_usec = 0;
}
/* check if data is on the socket during the pause */
fd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL);
FD_ZERO(&readfds);
SM_FD_SET(fd, &readfds);
if (select(fd + 1, FDSET_CAST &readfds,
NULL, NULL, &timeout) > 0 &&
FD_ISSET(fd, &readfds))
{
greetcode = "554";
nullserver = "Command rejected";
sm_syslog(LOG_INFO, e->e_id,
"rejecting commands from %s [%s] due
to pre-greeting traffic",
peerhostname,
anynet_ntoa(&RealHostAddr));
}
}
}
Rebuild and install the sendmail-8.12.11 binary, and you'll have
the greet_pause functionality. You'll also need to add the file
sendmail-8.13.0/cf/feature/greet_pause.m4 to the directory where you
store your sendmail-8.12.11 m4 files so you can generate a new cf
file from your mc file.
Q I'm trying to use find
to gather a list of filenames on my OS X 10.1.3 machine, which I
will then iterate through and perform some action on. These actions
vary from chown/chmod to using sed to replace strings inside
the file. The main problem I'm having is that OS X insists
in creating files and directories with spaces in them. Every syntax
I've used with find splits the filenames up at the space.
As a Unix person, I find this highly irritating, and I know there
must be a way to work around it. Any suggestions?
A This is a common question to
which there are a few answers. Since you don't specify exactly
what you're trying to do with the data, I'll just quote
directly form the comp.unix.shell FAQ, question 16. If you need
to use find, the last example may be the most applicable:
16. How do I loop through files with spaces in their name?
So, you're going to loop through a list of files? How is
this list stored? If it's stored as text, there probably
was already an assumption about the characters allowed in a filename.
Every character except '\0' (NUL) is allowed in a file
path on Unix. So the only way to store a list of file names in
a file is to separate them by a '\0' character (if you
don't use a quoting mechanism as for xargs input).
Unfortunately most shells (except zsh) and most standard Unix
text utilities (except GNU ones) can't cope with "\0"
characters. Moreover, many tools, like "ls", "find",
"grep -l" output a \n separated list of files. So, if
you want to postprocess this output, the simpler way is to assume
that the filenames don't contain newline characters (but
beware that once you make that assumption, you can't pretend
anymore your code is reliable (and thus can't be exploited)).
So, if you've got a newline separated list of files in
a list.txt file, Here are two ways to process it:
1:
while IFS= read -r file <&3; do
something with "$file" # be sure to quote "$file"
done 3< list.txt
(if your read doesn't have the "-r" option, either
make another assumption that filenames don't contain backslashes,
or use:
exec 3<&0
sed 's/\\/&&/g' < list.txt |
while IFS= read file; do
something with "$file" <&3 3<&-
done
)
2:
IFS="
" # set the internal field separator to the newline character
# instead of the default "<space><tab><NL>".
set -f # disable filename generation (or make the assumption
# that filenames don't contain *, [ or ? characters (maybe
# more depending on your shell)).
for file in $(cat < list.txt); do
something with "$file" # it's less a problem if you forget to
# quote $file here.
done
Now, beware that there are things you can do before building this
list.txt. There are other ways to store filenames. For instance,
you have the positional parameters.
With:
set -- ./*.txt
you have the list of txt files in the current directory, and no
problem with weird characters. Looping through them is just a matter
of:
for file
do something with "$file"
done
You can also escape the separator. For instance, with:
find . -exec sh -c 'printf %s\\n "$1" | sed -n '"':1
\$!{N;b1
}
s/|/|p/g;s/\n/|n/g;p'" '{}' '{}' \;
instead of:
find . -print
you have the same list of files except that the \n in filenames
are changed to "|n" and the "|" to "|p".
So that you're sure there's one filename per line and
you have to convert back "|n" to "\n" and "|p"
to "|" before referring to the file.
Amy Rich, president of the Boston-based Oceanwave Consulting, Inc.
(http://www.oceanwave.com), has been a UNIX systems administrator
for more than 10 years. She received a BSCS at Worcester Polytechnic
Institute, and can be reached at: qna@oceanwave.com. |