通过shell脚本中的s_client关闭连接

时间:2013-04-13 08:12:16

标签: bash openssl

我正在尝试在shell脚本中建立与IMAP服务器的连接。虽然我可以连接并发出命令,但是合适地关闭连接似乎是不可能的。

这是我正在使用的测试命令:

openssl s_client -crlf -connect server:993 <<EOF
01 login USERNAME PASSWORD
02 LIST "" "*"
03 logout
EOF

因为一旦输入用完就连接关闭,这会在收到任何输出之前发生,因此我从未收到所需的数据。

如果我添加选项-ign_eof选项,以便忽略输入结束以保持连接打开,则会根据需要返回输出。但是在连接关闭之后......

* BYE Logging out
03 OK Logout completed.

... s_client仍处于活动状态,因此执行永远不会返回脚本。

当服务器关闭连接时,是否存在导致s_client终止的解决方案?

或者是否有使用标准工具的替代方法?该脚本将在Mac OS X,Debian和Redhat衍生产品上运行,并且可能是Android终端仿真器,因此我想使用相当标准的工具来实现可移植性而不是专业软件包。

更新:我提出了一个我并不完全满意的答案,但确实有效。它使用脚本将命令传递给openssl,然后进入无限循环以保持stdin打开,直到它收到一个信号告诉它退出。这是我的测试脚本:

#!/bin/sh

if [ "$1" = "doit" ]; then
   trap "echo \"04 logout\"; exit" SIGUSR1
   echo "00 login USERNAME PASSWORD"
   echo "01 SELECT PID-$$"
   echo "02 SELECT FOLDER"
   echo "03 FETCH 1:* (BODY[HEADER.FIELDS (Subject)])"
   while :; do :; done
fi

MYFLAG=
$0 doit | openssl s_client -crlf -connect server:993 2>/dev/null | while read LINE; do
   LINE=`echo "$LINE" | tr -d '\r'`
   [ "${LINE:0:4}" = "* OK" ] && MYFLAG=Y 
   [ "${LINE:0:33}" = "01 NO Mailbox doesn't exist: PID-" ] && PID="${LINE##*PID-}"
   [ "$MYFLAG" ] && echo "$LINE"
   [ "$PID" -a "$LINE" = "03 OK Fetch completed." ] && kill -USR1 $PID
done
echo "Finished."

该脚本使用参数调用自身以输出通过管道传输给openssl的IMAP命令,其输出通过管道传输到read循环,以便进行处理。 MYFLAG变量仅用于隐藏openssl输出的信息,只是回显服务器连接的输出。

我选择一个虚拟文件夹名称,其中包含脚本第二个实例的PID作为将其传回的方法,显然临时文件会更好但是对于测试我想保持一切自包含且能够看看发生了什么。

一旦显示获取信息并且服务器返回OK响应,它就会向脚本的第二个实例发送一个SIGUSR1信号,然后发送注销消息并退出,关闭stdin,导致s_client断开连接。

最初我在初始的回声集中包含了04 logout命令,但是当我这样做时,读取循环只显示到获取输出然后停止,它甚至没有显示操作的OK状态虽然收到了一切。

此外,我需要使用tr来删除尾随回车符,但是如果我通过openssl传输输出,那么读取循环就不会收到任何内容。

1 个答案:

答案 0 :(得分:6)

您可以通过计算输入到openssl来解决这个问题。 我能提出的最简单的方法是使用一个回显stdout输入的函数:

#!/bin/sh

imapscript () {
echo '01 login USER PASSWD'
echo '02 LIST "" "*"'
echo '03 logout'
while sleep 1; do
  echo "04 logout"
done
}

imapscript | openssl s_client -crlf -connect server:993