星期二, 三月 20, 2007

mailman mailing list

我需要在公司建立一个邮件列表,或者说我需要在自己的企业架构中建立邮件列表,作为团队开发以及用户讨论组等使用。当然至少到目前来看,没有考虑过它会成为基础设施的一部分,我想它应该还是属于上层建筑的。

why not google group?

因为企业的邮箱和邮件列表,特别是内部事务如开发等不能这样做,即使设置了限制,但问题是一方面无法与现有的内部帐号整合在一起,另一方面,如果由于某种原因导致 google group 不能访问(比如年初的地震或者 GFW),则公司的事务将收到影响!所以最终我们需要自己的 mailing list。目前最流行的就是 mailman 了,用 python + C 编写的!

mailman mailing list 有两种接口:web interface && mail interface。及通过 web 页面的表框操作或通过 email 发送诸如 subscribe, unsubscribe 等命令。

安装:
cat .config
pkgname = "mailman";
version = "2.1.9";
user = "mailman";
groups = "web";
group = "mailman";
archive = "mailman-2.1.9.tgz";
command = "tar xfz mailman-2.1.9.tgz";
command = "cd mailman-2.1.9";
command = "./configure --without-permcheck --with-cgi-gid=httpd";
command = "make";
command = "make install";
command = "cd ..";
command = "rm -rf mailman-2.1.9";
time = "20070313 14:01:47 Tue";
使用 rpm 安装则 cgi-gid 比较死,只能使用 apache 用户,只好用源代码编译了。

然后编辑 httpd.conf:
"<"VirtualHost *:80">"
ServerName test.shopex.cn
DocumentRoot "/var/www/html/test"
ScriptAlias /mailman/ /usr/local/mailman/cgi-bin/
Alias /pipermail/ /usr/local/mailman/archives/public
Alias /icons/ /usr/local/mailman/icons/
# AddHandler cgi-script .cgi .py
"<"Directory "/usr/local/mailman/icons/"">"
Options Indexes
Order allow,deny
Allow from all
"<"/Directory">"
"<"Directory "/usr/local/mailman/cgi-bin/"">"
Options Indexes
Order allow,deny
Allow from all
"<"/Directory">"
"<"/VirtualHost">"
然后访问 http://test.shopex.cn/mailman/listinfo(注意修改 hosts 文件),这里 listinfo 实际上是 /usr/local/mailman/cgi-bin/listinfo,是一个二进制的可执行程序!这时可以看到一个页面,并且报告没有创建任何 mailing list。

邮件列表的基本原理就是利用了邮件服务器的 alias 功能。所以使用手工的方法,也可以建立简单的邮件列表,但 Mailman(以前比较流行 Majordomo)可以自动完成大量工作!

将 mailman 和 postfix 集成
sh# vi $prefix/Mailman/mm_cfg.py
MTA = "Postfix"
sh# cd /usr/local/mailman
sh# bin/genaliases
sh# chown mailman:mailman data/aliases*
sh# chmod g+w data/aliases*

sh# vi /etc/postfix/main.cf
myhostname = mail.shopex.cn
mydomain = shopex.cn
myorigin = $mydomain
inet_interfaces = all
mydestination = $myhostname, localhost.$mydomain, localhost,
mail.$mydomain, www.$mydomain, ftp.$mydomain
mynetworks = 192.168.0.0/24, 127.0.0.0/8
alias_maps = hash:/etc/aliases, hash:/usr/local/mailman/data/aliases
alias_database = hash:/etc/aliases, hash:/usr/local/mailman/data/aliases


记得要运行 newaliases,并且是 postfix 的 newaliases,RHEL4 可以用:
sh# alternatives --set mta /usr/sbin/sendmail.postfix
来指定。

然后要创建实际的邮件列表。邮件列表既可以使用 command line 的操作命令,也可以从 web 页面上运行 cgi 脚本来实现。下面分别介绍。
sh# /usr/local/mailman/bin/newlist
输入邮件列表的名字,会自动生成如下的邮件列表别名文件的内容。
sh# cat /usr/local/mailman/data/aliases
# This file is generated by Mailman, and is kept in sync with the
# binary hash file aliases.db. YOU SHOULD NOT MANUALLY EDIT THIS FILE
# unless you know what you're doing, and can keep the two files properly
# in sync. If you screw it up, you're on your own.

# The ultimate loop stopper address
mailman-loop: /usr/local/mailman/data/owner-bounces.mbox

# STANZA START: dev
# CREATED: Tue Mar 13 18:40:13 2007
dev: "|/usr/local/mailman/mail/mailman post dev"
dev-admin: "|/usr/local/mailman/mail/mailman admin dev"
dev-bounces: "|/usr/local/mailman/mail/mailman bounces dev"
dev-confirm: "|/usr/local/mailman/mail/mailman confirm dev"
dev-join: "|/usr/local/mailman/mail/mailman join dev"
dev-leave: "|/usr/local/mailman/mail/mailman leave dev"
dev-owner: "|/usr/local/mailman/mail/mailman owner dev"
dev-request: "|/usr/local/mailman/mail/mailman request dev"
dev-subscribe: "|/usr/local/mailman/mail/mailman subscribe dev"
dev-unsubscribe: "|/usr/local/mailman/mail/mailman unsubscribe dev"
# STANZA END: dev
实际上首先要创建 site-wild mailing list:
site-wild mailing list:
sh# bin/newlist mailman
sh# bin/config_list -i data/sitelist.cfg mailman
通过如下地址访问邮件列表信息:
http://test.shopex.cn/mailman/listinfo/dev
看看如果不存在的列表的情况:
http://test.shopex.cn/mailman/listinfo/users
"No such list users"

下面设置密码,除了 list owner 之外,有两个特殊用户,即 Administrator 和 list creator,前者相当于 root,后者一般专门用来从 web page 创建 list 的时候使用。这两者分别用如下命令创建密码:
sh# bin/mmsitepass
sh# bin/mmsitepass -c
为了能够从页面访问,必须启动 mailman 服务,实际上会启动一个名为 qrunner 的进程。对 RHEL4,使用:
sh# cp scripts/mailman /etc/init.d/mailman
sh# chkconfig --add mailman
sh# chkconfig mailman on
sh# chkconfig sendmail off
sh# chkconfig postfix on
那么现在可以打开页面 http://test.shopex.cn/mailman/create 来建立邮件列表。在最下面使用 list creator 密码提交。

hostname settings 会产生影响。例如 http://test.shopex.cn/mailman/listinfo,有显示
"If you are having trouble using the lists, please contact mailman@test1.shopex.cn."(这里我更改了主机名),显然,这个值根据主机名而改变了。但是这不是我希望的值。

这里先不考虑虚拟主机的情况,那么需要修改 mm_cfg.py,增加 DEFAULT_EMAIL_HOST 和 DEFAULT_URL_HOST。这两个参数在安装时会写入到 /usr/local/mailman/Mailman/Defaults.py 中,但不要直接编辑这个文件,编辑 /usr/local/mailman/Mailman/mm_cfg.py 就好了。

比如在 Defaults.py 中的默认设定为:
DEFAULT_EMAIL_HOST = 'docs.shopex.cn'
DEFAULT_URL_HOST = 'docs.shopex.cn'
这会有问题,因为我在 apache 上发布的虚拟主机名是 test.shopex.cn,并且我也不希望用户把邮件发送到 users@docs.shopex.cn 或 users@test.shopex.cn 这样的地址,而是希望是 users@shopex.cn 这样的地址(即 mailing list 的地址将是 listname@DEFAULT_EMAIL_HOST)。那么我编辑 mm_cfg.py
DEFAULT_EMAIL_HOST = 'shopex.cn'
DEFAULT_URL_HOST = 'test.shopex.cn'
add_virtualhost(DEFAULT_URL_HOST, DEFAULT_EMAIL_HOST)
这里 DEFAULT_URL_HOST 不能写成"shopex.cn",否则你在页面上访问不行了,因为链接到错误的域名上去了。通常 URL_HOST 和 EMAIL_HOST 会不同,如上。因为 EMAIL_HOST 通常是你的整个域的,而 postfix 可以为整个域接收和发送邮件,但 URL_HOST 则是具体的主机的,如果设置成 shopex.cn,则在 http://test.shopex.cn/mailman/listinfo/dev 进行 subscribe 的时候,会连接到 http://shopex.cn/mailman/subscribe/dev,但这个可能是不存在的,或根本不是统一台主机(除非确实是同一台主机并且对 shopex.cn 域做了同样的 A 记录)。

注意后面必须使用 add_vertualhost function call。

对于已经存在的域,比如前面创建了 dev,但并没有设定其 mailing list 为 dev@shopex.cn,而仍然是 dev@docs.shopex.cn 或 dev@test.shopex.cn,那么
You will want to run the bin/fix_url.py to change the domain of any existing lists.
实际上是这样做的
sh# cd /usr/local/mailman
sh# bin/withlist -l -r fix_url dev -u shopex.cn
进入一个列表来管理:
http://test.shopex.cn/mailman/amdin/users
进入可以用 site-password,也可以用 create 时发送的那个由 mailman 生成的密码,取决于你的管理策略。每个列表成员也有自己的密码,也是在订阅的时候发送的那个,可以用它登入管理自己的设置。

subscribe 可以访问 http://test1.shopex.cn/mailman/listinfo/dev 这个 URL。收到邮件后从页面 confirm 即可。

其他一些命令:
bin/list_lists
bin/rm_lists
bin/list_owners -w
bin/list_members dev

mailing list/newsgroup && google group

以前都是在论坛上发帖来讨论问题,比如在 LinuxSir 或 LinuxQuestions。现在越来越发现这种方法不太好,因为你必须维护多个帐号,每个论坛都有一个,像我这种懒人,久而久之,信息的交流就会受到影响。

因此应该考虑使用 mailing list 和 newsgroup 这样的方式来实现信息的集中管理,提高效率,便于交流。而且,如果一个问题既涉及 samba,又涉及 openldap 和 Kerberos,那么我可以同时向三个 mailing list 发帖。

比较流行的 newsgroup 是 USENET,但必须使用相应的新闻阅读器。不过目前已经有了 google group,可以不再使用新闻阅读器了。

google group 实际上包括了 newsgroup 和 mailing list 两种形式的整合。而且很多传统的 USENET newsgroup/mailing list 的内容都可以在 google group 中找到。比如我订阅了 samba@lists.samba.org 这个邮件列表,并发送了文章,那么不久就可以在"linux.samba"这个 google group 中找到,但是这个 group 却是一个 USENET newsgroup,却不包含 mailing list 功能。

因为 USENET newsgroup 存在 spam 的风险,所以我本来希望能够使用邮箱来向这样的 groups 发送内容,并使用 gmail 的 plus address 功能,这样能够更好的设置过滤规则,但结果发现对于这种 USENET newsgroup 功能不能以发送邮件的方式来操作。而新建的 google group 就都包含 mailing list 的功能,比如 sfworld, openldap 等,这些 group 可以发送邮件。通过在 group 中查看"About this group"可以发现两者的区别。

所以,如果我在其他地方订阅 mailing list(当然是比较正规的,否则就要收到大量垃圾邮件了),那么我会使用 $username+l@gmail.com 这样的用户名,而不是 $username@gmail.com。但 google group,即便有接收邮件的 list 地址,也不能使用这种 plus address 的方法!

对于 USENET 的 google group,目前我只好使用另外一个帐号,并将所有到那个帐号并与订阅的新闻组有关的邮件都转发到我现在实际使用的帐号,其他邮件一律删除,然后实际使用帐号配置可以使用这个临时帐号来发送邮件。

vsftpd xferlog LOGIN record

默认的 vsftpd 中的有如下配置:
xferlog_enable=YES
# xferlog_file=/var/log/vsftpd.log
xferlog_std_format=YES
使用 wuftpd 类型的日志记录。但却发现好像没有 LOGIN 记录!于是改成如下配置:
xferlog_enable=YES
xferlog_file=/var/log/vsftpd.log
# xferlog_std_format=YES

Mon Mar 12 17:15:22 2007 [pid 13772] [mb.shopex.cn] OK LOGIN: Client "218.80.208.72"
Mon Mar 12 17:15:33 2007 [pid 13774] [mb.shopex.cn] OK UPLOAD: Client "218.80.208.72", "/syssite/home/shop/1/template/Template
/TPL_NEWGOODS.htm", 896 bytes, 71.47Kbyte/sec

PAM stack && sufficient

关于 PAM 的 stack 有一个概念突然觉得有点模糊,比如 sufficient 控制标志,资料上的解释都是:如果 sufficient 回报认证通过,则不再调用其他模块。那么如果在 auth 中的 sufficient 模块通过,是否意味着就不用再做其他检查,比如 accout/session/password 的检查了。为了验证这一点,修改 /etc/pam.d/system-auth:
sh# vi /etc/shadow
root:**********:13524:0:99999:7::7:

sh# cat system-auth
#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth required /lib/security/$ISA/pam_env.so
auth sufficient /lib/security/$ISA/pam_unix.so likeauth nullok
auth required /lib/security/$ISA/pam_deny.so

account required /lib/security/$ISA/pam_unix.so
account sufficient /lib/security/$ISA/pam_succeed_if.so uid < 100 quiet
account required /lib/security/$ISA/pam_permit.so

password requisite /lib/security/$ISA/pam_cracklib.so retry=3
password sufficient /lib/security/$ISA/pam_unix.so nullok use_authtok md5 shadow
password required /lib/security/$ISA/pam_deny.so

session required /lib/security/$ISA/pam_limits.so
session required /lib/security/$ISA/pam_unix.so
那么现在是不能登录的,这说明 auth pam_unix.so 的 sufficient 只影响了 auth 部分,而 account 部分还是要再检查一遍的。如果注销上面的 account pam_unix.so 一行,则可以进行登录了。

vsftpd website && sharing by users

vsftpd 为不同用户进行不同设置中,其主要目的为了可以将 apache 的不同虚拟主机赋予不同的人员进行管理,或者至少管理人员不需要使用 httpd 这个帐户来登录 ftp。那么有一个问题,就是 $htdocs_prefix/$site 的属主和权限应该如何设置(设对 $user 的 vsftpd local_root=$htdocs_prefix/$site, 即 DocumentRoot)。

我开始考虑能不能对不同的 VirtualHost/DocumentRoot 使用不同的 User/Group,于是在 httpd.conf 中进行了调整。但最终报错:
Syntax error on line 433 of /usr/local/apache2/conf/httpd.conf:
User cannot occur within "<"VirtualHost">" section
那么还是回到文件和目录权限这个思路上来。

$htdocs_prefix/$site 应该属于 httpd 用户(设 Apache 以该用户身份运行),还是应该属于 $user 这个用户?

我开始设想,如果设置属于 httpd 用户和组,因为 $user 是通过 ftp 上传文件的,而 vsftpd 这个进程是以 root 身份运行的,所以不需要另外再设置对它的系统权限,不论是否已经存在某个文件,都可以成功的进行上传(已存在则可选择是否覆盖)。而为了使 httpd 进程能够读写页面,就必须使其属主为 httpd。

这时唯一的问题是,上传后的文件的属主是 $user,而不是 httpd,所以为了使新上传的文件也能够被 httpd 正确读写,需要设置 vsftpd 的 chown_upload:
sh# vi /etc/vsftpd/vsftpd.conf
chown_uploads=YES
chown_username=httpd
但实际上这样也是不行的,因为 chown_* 只对 anonymous 用户有效,对其他用户是不行的。

所以我只能令其属于 $user 用户,并属于 httpd 组,并令 $user 也成为 httpd 的组成员,对目录增加权限:g+ws,因为如果目录拥有 g+s,则其创建的子目录也将拥有 g+s,对普通文件增加权限:g+w。这样 httpd 进程对目录和文件都具有操作能力,上传的文件也会自动属于 httpd 组。
sh# find . | xargs chmod g+w
sh# find . -type d | xargs chmod g+s

sh# vi /etc/vsftpd.conf
local_umask=002
umask 002 对普通文件及为 775,对目录即为 664。

除非在脚本中使用了 chown 这样的调用,否则这样就可以了。

对于更负责的需要,可能需要利用 cgiwrap 这样的 CGI 脚本了。在 sourceforge 上可以找到这个项目。

XML encoding UTF-8

我在 xml 文件中使用
?xml version="1.0" encoding="zh_CN.GBK"?
设定,但使用 4xml 时不行,提示不支持的字符集。于是只能使用 UTF-8
?xml version="1.0" encoding="UTF-8"?
而之前的 xml 文件使用的编码格式必须更改过来,否则仍然不能正确处理。使用 iconv 命令:
sh# iconv -f gb2312 -t utf-8 index.xml -o index2.xml
sh# export LANG=zh_CN.UTF-8
sh# vi ~/.vimrc
set encoding=utf-8
但这样做,其他不是 UTF-8 的文件又会显示乱码了。所以目前只能说在编辑时使用 set encoding=utf-8 命令来设定。

而现在在 Windows 下使用 gvim 使用上面的方法编辑是没有问题了,但我自己的 LFS 却没有对 UTF-8 的很好的支持,文件显示为乱码。不知道应该如何设定 glibc 的 locale?

星期日, 三月 18, 2007

google interview: 2nd by phone

问:TCP 三次握手协议是怎样的一个过程?
答:SYN, SYN+ACK, ACK

问:中断连接是发送什么类型的报文?
答:RST

问:traceroute 原理
...(上次问过的)

问:当不能到达目标的时候的情况?

问:有 Server1 和 Server2,之间有一个 firewall,firewall 只运行两主机的 22 端口互相连接到对方,同时只允许从 Server1 的 80 端口的访问,那么如何从 Server2 连接到 firewall 的 80 端口?
答:可以利用 ssh forwarding,使用本地转发从 Server1 的 22 端口转到 firewall 的 80 端口。

问:那么具体是什么命令来实现?
答:
sh# ssh -L 2080:firewall:80 server1
sh# ssh localhost 80


问:请问没有浏览器的时候,如何浏览页面?
答:可以通过 telnet host 80 来访问
(wget -m)

问:常用端口及 /etc/service(上次问过)

问:软、硬链接的区别?
答:符号链接即文件的内容是到目标的路径的字符串,而硬链接是在文件系统底层利用 inode 的指向来实现的。

问:kill 中止进程是使用的什么信号?
答:SIGTERM

问:这和 -9 强制中止有什么区别?
答:强制中止不会做清理工作并返回推出状态。

问:如何查看一个 pid 是属于什么进程的?
答:可以利用 pidof 命令,这个命令是 killall 的一个符号链接。

问:如何利用 kill 来中止所有的名为 javascript 的进程?
答:如果不使用 killall,则可以例如脚本:
for pid in `pidof javascript`; do
kill pid
done

问:mv * 这个命令会产生什么结果

问:/var/www/htdocs 下所有的 html 改诚 htm

find /var/www/htdocs | grep '\.html$' | xargs -i mv {} {}.l

for f in `find /var/www/htdocs | grep '\.html$'`; do
basename
awk
foo1.foo2.html
$1~$(NF-1) => name
mv /var/www/htdocs/$name ...
done

rewrite......

O(n^2)

改进算法

星期四, 三月 15, 2007

gvim setting [on windows]

"编辑"->"启动设定"
colorscheme darkblue
set tabstop=4
set number
set gfn=新宋体:h12:cGB231

"编辑"->"设定窗口"
可以查找所有的设定,例如设置字体的"set gfn=新宋体:h12:GB2312"在"10 GUI"中。

星期二, 三月 06, 2007

慎用 ifup 和 ifconfig up

因为在 RHEL4 中,默认路由总是由后面启动的那块网卡来设定的。而一般设定使用 eth0 作为内网接口,eth1 作为外网接口,如果使用 /etc/init.d/nework restart 这就没有问题,因为 eth1 总是后启动。但如果使用 ifup eth0 和 ifconfig eth0 up 这样的命令,就很可能会抹掉默认路由设置。如果 eth0 没有配置路由,还有希望登录,否则只能重启主机。

星期一, 三月 05, 2007

smbfs/cifs for fs_backup

备份的目标比较大,压缩后的档案超过两个G,使用了 smbfs 文件系统:
sh# mount
//store/homes on /mnt/host type smbfs (rw,mand)
但是执行完全备份时出现如下报错:
sh# fs_backup at_pages

gzip: stdout: File too large
tar: /mnt/host/fs_backup/at_pages/at_pages.full.20070301-010003.tgz: Wrote only 2048 of 10240 bytes
tar: Error is not recoverable: exiting now

bzip2: I/O or other error, bailing out. Possible reason follows.
bzip2: File too large
Input file = (stdin), output file = (stdout)
tar: /mnt/host/fs_backup/at_pages/at_pages.full.20070301-145957.tgz: Wrote only 8192 of 10240 bytes
tar: Error is not recoverable: exiting now
首先看看本地备份是否会有问题,改变 datadir = /var/fs_backup,重新运行完全备份,没有问题。说明限制不再 gzip/bzip2 上面,只可能是 samba 的问题。

从查找资料的情况来看,时间上就是由于 smbfs 有 2GB 的限制,使用 cifs 来代替 smbfs 即可:
sh# mount
//store/homes on /mnt/host type cifs (rw,mand)
在 /etc/fstab 做相应更改就可以了。

星期四, 三月 01, 2007

xml ts

sh$ 4xml -v index.xml
Ft.Xml.ReaderException: In file:///root/docs/shoex-sysadm/eq_room_man.xml, line 9, column 19: not well-formed (invalid token)

"<"itemizedlist mark=opencircle">"
应该写成:
"<"itemizedlist mark="opencircle"">"
因为 xml 文档的标签属性都必须使用引号!