这两天解决了几个开发中遇到的疑难杂症,特此篆文记录。
无论在软件项目的实施,还是系统的开发甚至只是编写一小段代码,经常会遇到一些让人白思不得其解的问题,耗费了大量的时间,用尽了办法却位能解决。感觉就有点得了疑难杂症,便访天下名医却不得根治一样。
但最后发现这些问题的症结,往往都是很小小的问题,却不为人所注意,或者隐藏得非常深入,常人难以发现。
Maildrop 的0x0B故障分析及解决
使用maildrop作为VDA/MDA的用户为数不少,绝大多数用户使用maildrop都是因为其过滤能力强,过滤语言灵活,支持Quota,并可与MySQL/LDAP及小型dbm对接,可外挂各种程序,如SpamAssassin,杀毒软件,甚至SMS等,实现复杂的功能。
但是maildrop常见的一个问题就是经常会遇到0x0B的意外退出问题。除了编译器(使用的Gcc c++版本问题)和编译优化指令太高(如高于O2等)的问题外,还有少数问题是不为人们所注意的。
在自己开发一个全新的webmail系统中,maildrop的投递uid/gid都是250,这样的配置跑了几年都没任何问题,工作得非常可靠。但是由于webmail需要直读Maildir,按常规的方法必须设置成setuid/gid程序,或将apache的User/Group设置成250,这样非常麻烦,尤其在新的SELinux下会造成诸多不便,为此使用了Suexec的配置,但是Suexec的RPM包默认UID_MIN = 500,于是将user/group从250/250改成了1000/1000,结果问题就来了。
投递邮件时,maildrop死活都返回0x0B错误,无论我将user/group改成多少也好,包括mysql里的uidnumber/gidnumber、maildropmysql.config里的default等都改了,完全没有任何效果。
后来再试验su成uid=1000的用户呼叫maildrop发现也是0x0B错误,只有在root权限下没问题,于是又查了maildrop的INSTALL甚至看了source!都是无任何迹象显示与这个错误有关,于是只有google了。但也没什么有效的解决办法。
后来偶然看到一个法文的邮件列表上,看到有人在讨论maildrop的mysql配置,忽然想到,自己的maildrop rpm包自动设置了/etc/maildropmysql.config文件属性是uid=250, gid=250的,于是ls -l /etc/maildropmysql.config一看,原来症结就在这里!
我改了所有该改的地方,就是没有对配置文件的owner/group进行修改,而配置文件原本的属性是600,这样导致了maildrop换成其他uid/gid运行时无法读取配置文件,导致了0x0B错误。执行:
chown -R 1000.1000 /etc/maildropmysql.config
之后一切问题就迎刃而解了。
Webmail解决setuid/gid问题
昨天正在着手解决全新设计的webmail系统setuid/gid的问题,以适应在SELinux下的应用。自己怕麻烦,暂时不想去做相应的policy,所以只有动脑筋了。
幸好RHEL/CentOS/FC3等自带的policy都支持suexec,因此就决定利用suexec来实现与apache不同的运行uid/gid,以达到直接访问Maildir的目的。
在虚拟主机中的配置:
.....SuexecUserGroup vuser vgroupAlias /extmail/ /var/www/cgi-bin/extmail/ SetHandler cgi-script Options +ExecCGI.......
注意: 之所以将cgi程序放到/var/www下是因为Suexec的docroot限制在了这里,详细的suexec编译参数可以通过Suexec -V查看,以下是CentOS 4.1的结果:
-D AP_DOC_ROOT="/var/www" -D AP_GID_MIN=100 -D AP_HTTPD_USER="apache" -D AP_LOG_EXEC="/var/log/httpd/suexec.log" -D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin" -D AP_UID_MIN=500 -D AP_USERDIR_SUFFIX="public_html"
最后,将程序及模板等属性全部改为要运行的uid/gid即可:
chown -R vuser.vgroup /var/www/cgi-bin/extmail
重新启动httpd,通过/var/log/httpd/suexec.log可以看到如下的信息:
[2005-07-26 20:55:51]: uid: (1000/vuser) gid: (1000/1000) cmd: folders.cgi
证明配置成功,这样webmail就不必再设置为setuid了,而且apahce也不必以1000/1000的id来运行了。
chdir()引起的模板问题之解决
开发Webmail时,引入了模板机制,这将大大提高了用户修改的便捷程度,也缩短了开发人员的工作周期。但是这几天遇到了一个问题,在调用了Storage::Maildir模块之后,模板的解析就无论如何都不正常了,总说file not found,但明明文件没有任何错误。
而如果先于呼叫Storage::Maildir之前解析模板则完全没问题,开始怀疑是SELinux的问题,但kernel日志里又无任何不妥。
后来通过一点一点分析,包括对template解析库的修改等都印证了各种代码都没有问题。最后将目光放到了Storage::Maildir,该模块在use的时候会利用chdir()初始化当前工作路径,这样做之后,将使cgi程序的工作路径和之前不同了,对于没使用绝对路径进行模板解析的应用,自然会遇到问题。
代码分析:
my $tpl = Ext::Template-new("../html/");my $mm = Ext::Storage::Maildir;$tpl-assign(TEST = 1);restore_path(); # XXX recover working directory$tpl-process("index.html");$tpl-print;....sub restore_path { my $src=$ENV{SCRIPT_FILENAME}; $src=~s#(.*)/[^\/]+$#$1#; chdir($src);}
上述代码中,在进行模板解析之前,呼叫restore_path(),将工作路径恢复到调用Storage::Maildir之前的原始状态。这样解析就不再有问题了。