Ключевые слова:awk, example, shell, (найти похожие документы)
Date: Fri, 2 Mar 2001 20:17:26 +0000 (UTC)
From: Valentin Davydov <val@sqdp.trc-net.co.jp>
Newsgroups: fido7.ru.unix
Subject: pop3 север на AWK
>Как Bourne shell (не bash) вывести такую строку: $ab'cd
>echo '$ab\'cd' не работает.
Вот, например, как в новой версии поппера сделано:
# Copyright (C) Valentin Davydov, 2000-2001.
# Version 0.2.
#
# Thanks to Solar Designer for security testing.
#
# THIS SOFTWARE IS PROVIDED AS IS, WITHOUT ANY WARRANTY. USE AT YOUR OWN RISK.
#
# This server is written in GNU awk and implements POP3 protocol (RFC1939).
# For the simplicity of the popper itself, some other (than awk) system
# utilities and facilities are of heavy usage. They are (attention porters!):
# inetd, procfs, sh, hostname, md5, ls, tail, xargs, rm. Don't forget to allow
# the server to access them by duly setting paths/permissions/environment.
# Also some features (flaws ;-) of the POP3 protocol itself are abused, so
# the server is likely to work only with strictly RFC1939-compliant clients.
#
# The server is normally started by inetd who should manage the TCP
# connections and, probably, load balancing. Typical line for /etc/inetd.conf:
#
# pop3 stream tcp nowait pop:mail /usr/local/bin/gawk awk -f /path/popper.awk
#
# The user's mailboxes should be organized as follows:
#
# There is a directory, say, /var/mail/maildrop/ (which should be symlinked
# to the /maildrop) with pop/mail ownership and no more than 1770 permissions.
# In this directory there are subdirectories with the same ownership and
# permissions. The name of each such subdirectory is calculated as MD5
# digest from the respective user id which thus become known to the server.
# Note that this userids nothing to do with system users defined in
# system /etc/passwd. In each this subdirectory two datasets should reside.
#
# One dataset is a single file called ".passwd" containing single line of text.
# This line should be either user password in clear form (when APOP
# authorization is used) or MD5 hash of the string composed from the directory
# name (that is, MD5 hash of the user id) followed by a single space
# followed by the user password followed by newline (in the case of USER/PASS
# authorization). It is recommended to restrict read access to this file to
# the popper only.
#
# The second (possible empty) dataset consists of the mail messages themselves.
# Each message should occupy it's own file in the form of some single text line
# (for example, "From " line used in Unix mailboxes) followed by a message in
# RFC822 format, that is a number of header lines followed by an empty line
# followed by a message body. Popper will read and possibly delete this
# files during normal operation.
#
# The name of this file is used in UIDL listing, so only ASCII characters
# from 0x21 to 0x7e are allowed in it by RFC1939. This implementation
# further restrict this range by excluding characters 0x2e in the first
# position (which is specially interpreted by ls) and 0x2f, which is not
# allowed in Unix filenames. The convenient way of naming message files
# is recommended to set filename equal to the MD5 hash of the file contents.
# Besides, this politics provides some protection against duplicate messages.
# If the same message is delivered to the several users, hardlinks to the
# single file from their directories are OK.
#
# This implementation is still quite raw and possess some obvious bugs:
# - The supplied parameters from client (user name, password, message
# number etc.) are not checked for their length. While this is not (?)
# harmful for the server itself, the underlaying structures may work
# improperly, for example, the Unix filesystem will not allow filenames
# longer than 255 characters, commandline for the md5 command is also
# limited in length etc.
# - The server is not robust with respect to misconfiguration, say, the
# absence of some required files or presence of some redundant ones
# leads to abnormal functioning.
# - The user credentials (password) are seen in clear form as arguments
# to the md5 subprocess. I don't know any workaround which will not
# affect the multiprocess operation on the same maildrop :-(
# - The unnecessarily detailed parsing of the message texts degrades the
# performance on the long messages.
# - The Unix filesystem implementation degrades the performance on the
# maildrops with lots of messages.
# - Usage of procfs, ls and so on is not highly portable.
#
BEGIN{IGNORECASE=1;FS="[[:space:]]+";ORS="\r\n";state="A"
getline < "/proc/curproc/status";
close("/proc/curproc/status");
gsub (",","."); x="<" $2 "." $8 "@";
"hostname" | getline; close("hostname");
x=x $1 ">"
print "+OK POP3", x;fflush()};
function md5(s, r){gsub("'","'\\''",s);
"md5 -q -s '" s "'" | getline r;
close ("md5 -q -s '" s "'");
return r}
/^QUIT/{if(state=="T")state="U";exit};
/^APOP /&&state=="A"{us=md5($2); user="/maildrop/" us;
if(system("cd " user))
{print "-ERR Unknown user"}
else
{getline i < (user "/.passwd"); close(user "/.passwd");
hash=md5(x i);
if(hash==substr($3,1,32)){v=0;n=0;
while(x="ls -ltr " user|getline)
{if(NF-2){v+=$5;n+=1;mbox[n]=$9;sz[n]=$5;st[n]="N"}}
close("ls -ltr " user)
print "+OK " user " locked";
state="T"}
else{print "-ERR Invalid password"; state="A"}}
fflush();next}
/^USER /&&state=="A"{us=md5($2); user="/maildrop/" us;
if(system("cd " user))
{print "-ERR Unknown user"}
else
{print "+OK Please supply PASS for " user;
state="AU"};
fflush();next};
/^PASS /&&state=="AU"{hash=md5(us " " substr($0,6,length-6) "\n")
getline < (user "/.passwd")
close(user "/.passwd")
if(hash==$0){v=0;n=0;
while(x="ls -ltr " user|getline)
{if(NF-2){v+=$5;n+=1;mbox[n]=$9;sz[n]=$5;st[n]="N"}}
close("ls -ltr " user)
print "+OK " user " locked";
state="T"}
else{print "-ERR Invalid PASS"; state="A"}
fflush();next}
/^STAT/&&state=="T"{print "+OK",n,v;
fflush();next}
/^LIST/&&state=="T"{if(length($2)==0)
{print "+OK Listing follows";
for(i in mbox)
{if(st[i]~/N|R/)print i,sz[i]};
print "."}
else
{if(st[$2]~/N|R/){print "+OK",$2,sz[$2]}
else{print "-ERR No message",$2}}
fflush();next}
/^RETR /&&state=="T"{if(st[f=$2]~/N|R/){print "+OK Message",f,"follows"
while(x="tail +2 " user "/" mbox[f]|getline){
if(/^\./){$0="." $0};print}
print ".";fflush()
close("tail +2 " user "/" mbox[f])
st[f]="R"}
else{print "-ERR No message",f;fflush()}
next}
/^DELE /&&state=="T"{if(st[f=$2]~/N|R/){print "+OK Message",$2,"deleted"
fflush();st[$2]="D";n-=1;v-=sz[$2]}
else{print "-ERR No message", $2;fflush()}
next}
/^NOOP/&&state=="T"{print "+OK";fflush();next}
/^RSET/&&state=="T"{x=0;for(i in mbox){if(st[i]~/D/)
{st[i]="R";v+=sz[i];n+=1;x+=1}}
print "+OK", x, x-1?"messages":"message", "restored"
fflush();next}
/^TOP /&&state=="T"{if(st[f=$2]~/N|R/){if((i=$3+1)>1){}else i=0
print "+OK Header and possible", e=i-(i>0), e-1?"lines":"line", "of body follows"
e=0
while(x="tail +2 " user "/" mbox[f]|getline){
if(/^\./){$0="." $0}
if(/^[[:space:]]*$/){e=1}
i-=e
if(i>=0) print; else break}
close("tail +2 " user "/" mbox[f])
print "."}
else{print "-ERR No message",f};fflush();next}
/^UIDL/&&state=="T"{if(length($2)==0)
{print "+OK Unique-id listing follows";
for(i in mbox)
{if(st[i]~/N|R/)print i,mbox[i]};
print "."}
else
{if(st[$2]~/N|R/){print "+OK",$2,mbox[$2]}
else{print "-ERR No message", $2}}
fflush();next}
{print "-ERR Command `" $1 "' not implemented or invalid";fflush()}
END{if(state=="U"){print "+OK Updating " user; fflush(); ORS="\n"
for(i in mbox){if(st[i]~/D/){print (user "/" mbox[i]) | "xargs rm"}}}}