﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-每日一得-随笔分类-linux</title><link>http://www.blogjava.net/alex/category/5489.html</link><description>不求多得,只求一得
about java,hibernate,spring,design,database,Ror,ruby,快速开发&lt;br/&gt;&lt;br/&gt;
最近关心的内容关键字:RoR
</description><language>zh-cn</language><lastBuildDate>Mon, 18 Jun 2007 09:14:53 GMT</lastBuildDate><pubDate>Mon, 18 Jun 2007 09:14:53 GMT</pubDate><ttl>60</ttl><item><title>[zt]如何在Linux下增加Swap </title><link>http://www.blogjava.net/alex/archive/2007/06/18/124940.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Mon, 18 Jun 2007 06:27:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2007/06/18/124940.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/124940.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2007/06/18/124940.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/124940.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/124940.html</trackback:ping><description><![CDATA[<p>1.查看系统Swap空间使用</p>
<p>[root@jumper usr]# free<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; total&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; used&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; free&nbsp;&nbsp;&nbsp;&nbsp; shared&nbsp;&nbsp;&nbsp; buffers&nbsp;&nbsp;&nbsp;&nbsp; cached<br>Mem:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 513980&nbsp;&nbsp;&nbsp;&nbsp; 493640&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20340&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 143808&nbsp;&nbsp;&nbsp;&nbsp; 271780<br>-/+ buffers/cache:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 78052&nbsp;&nbsp;&nbsp;&nbsp; 435928<br>Swap:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1052248&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 21256&nbsp;&nbsp;&nbsp; 1030992</p>
<p>2.在空间合适处创建swap文件</p>
<p>[root@jumper usr]# mkdir swap<br>[root@jumper usr]# cd swap<br>[root@jumper swap]# dd if=/dev/zero of=swapfile bs=1024 count=10000<br>10000+0 records in<br>10000+0 records out<br>[root@jumper swap]# ls -al<br>total 10024<br>drwxr-xr-x&nbsp;&nbsp;&nbsp; 2 root&nbsp;&nbsp;&nbsp;&nbsp; root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4096&nbsp; 7月 28 14:58 .<br>drwxr-xr-x&nbsp;&nbsp; 19 root&nbsp;&nbsp;&nbsp;&nbsp; root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4096&nbsp; 7月 28 14:57 ..<br>-rw-r--r--&nbsp;&nbsp;&nbsp; 1 root&nbsp;&nbsp;&nbsp;&nbsp; root&nbsp;&nbsp;&nbsp;&nbsp; 10240000&nbsp; 7月 28 14:58 swapfile</p>
<p><br>[root@jumper swap]# mkswap swapfile<br>Setting up swapspace version 1, size = 9996 KiB</p>
<p><br>3.激活swap文件<br>[root@jumper swap]# swapon swapfile<br>[root@jumper swap]# ls -l<br>total 10016<br>-rw-r--r--&nbsp;&nbsp;&nbsp; 1 root&nbsp;&nbsp;&nbsp;&nbsp; root&nbsp;&nbsp;&nbsp;&nbsp; 10240000&nbsp; 7月 28 14:58 swapfile<br>[root@jumper swap]# free<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; total&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; used&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; free&nbsp;&nbsp;&nbsp;&nbsp; shared&nbsp;&nbsp;&nbsp; buffers&nbsp;&nbsp;&nbsp;&nbsp; cached<br>Mem:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 513980&nbsp;&nbsp;&nbsp;&nbsp; 505052&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8928&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 143900&nbsp;&nbsp;&nbsp;&nbsp; 282288<br>-/+ buffers/cache:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 78864&nbsp;&nbsp;&nbsp;&nbsp; 435116<br>Swap:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1062240&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 21256&nbsp;&nbsp;&nbsp; 1040984<br>[root@jumper swap]# &nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Swap，即交换区，除了安装Linux的时候，有多少人关心过它呢？其实，Swap的调整对Linux服务器，特别是Web服务器的性能至关重要。通过调整Swap，有时可以越过系统性能瓶颈，节省系统升级费用。&nbsp; <br><br>本文内容包括：&nbsp; <br><br><br>Swap基本原理&nbsp; <br><br>突破128M&nbsp;Swap限制&nbsp; <br><br>Swap配置对性能的影响&nbsp; <br><br>Swap性能监视&nbsp; <br><br>有关Swap操作的系统命令&nbsp; <br>Swap基本原理&nbsp; <br><br>Swap的原理是一个较复杂的问题，需要大量的篇幅来说明。在这里只作简单的介绍，在以后的文章中将和大家详细讨论Swap实现的细节。&nbsp; <br><br>众所周知，现代操作系统都实现了"虚拟内存"这一技术，不但在功能上突破了物理内存的限制，使程序可以操纵大于实际物理内存的空间，更重要的是，"虚拟内存"是隔离每个进程的安全保护网，使每个进程都不受其它程序的干扰。&nbsp; <br><br>Swap 空间的作用可简单描述为：当系统的物理内存不够用的时候，就需要将物理内存中的一部分空间释放出来，以供当前运行的程序使用。那些被释放的空间可能来自一些很长时间没有什么操作的程序，这些被释放的空间被临时保存到Swap空间中，等到那些程序要运行时，再从Swap中恢复保存的数据到内存中。这样，系统总是在物理内存不够时，才进行Swap交换。&nbsp; <br><br>计算机用户会经常遇这种现象。例如，在使用Windows系统时，可以同时运行多个程序，当你切换到一个很长时间没有理会的程序时，会听到硬盘"哗哗"直响。这是因为这个程序的内存被那些频繁运行的程序给"偷走"了，放到了Swap区中。因此，一旦此程序被放置到前端，它就会从Swap区取回自己的数据，将其放进内存，然后接着运行。&nbsp; <br><br>需要说明一点，并不是所有从物理内存中交换出来的数据都会被放到Swap中（如果这样的话，Swap就会不堪重负），有相当一部分数据被直接交换到文件系统。例如，有的程序会打开一些文件，对文件进行读写（其实每个程序都至少要打开一个文件，那就是运行程序本身），当需要将这些程序的内存空间交换出去时，就没有必要将文件部分的数据放到 Swap空间中了，而可以直接将其放到文件里去。如果是读文件操作，那么内存数据被直接释放，不需要交换出来，因为下次需要时，可直接从文件系统恢复；如果是写文件，只需要将变化的数据保存到文件中，以便恢复。但是那些用malloc和new函数生成的对象的数据则不同，它们需要Swap空间，因为它们在文件系统中没有相应的"储备"文件，因此被称作"匿名"(Anonymous)内存数据。这类数据还包括堆栈中的一些状态和变量数据等。所以说，Swap 空间是"匿名"数据的交换空间。&nbsp; <br><br>突破128M&nbsp;Swap限制&nbsp; <br><br>经常看到有些Linux（国内汉化版）安装手册上有这样的说明：Swap空间不能超过128M。为什么会有这种说法？在说明"128M"这个数字的来历之前，先给问题一个回答：现在根本不存在128M的限制！现在的限制是2G！&nbsp; <br><br>Swap 空间是分页的，每一页的大小和内存页的大小一样，方便Swap空间和内存之间的数据交换。旧版本的Linux实现Swap空间时，用Swap空间的第一页作为所有Swap空间页的一个"位映射"（Bit&nbsp;map）。这就是说第一页的每一位，都对应着一页Swap空间。如果这一位是1，表示此页Swap可用；如果是0，表示此页是坏块，不能使用。这么说来，第一个Swap映射位应该是0，因为，第一页Swap是映射页。另外，最后10个映射位也被占用，用来表示Swap的版本（原来的版本是Swap_space&nbsp;，现在的版本是swapspace2）。那么，如果说一页的大小为s，这种Swap的实现方法共能管理"8&nbsp;*&nbsp;(&nbsp;s&nbsp;-&nbsp;10&nbsp;)&nbsp;-&nbsp;1"个Swap页。对于i386系统来说s=4096，则空间大小共为133890048，如果认为 1&nbsp;MB=2^20&nbsp;Byte的话，大小正好为128M。&nbsp; <br><br>之所以这样来实现Swap空间的管理，是要防止Swap空间中有坏块。如果系统检查到Swap中有坏块，则在相应的位映射上标记上0，表示此页不可用。这样在使用Swap时，不至于用到坏块，而使系统产生错误。&nbsp; <br><br>现在的系统设计者认为：&nbsp; <br><br>1.现在硬盘质量很好，坏块很少。&nbsp; <br><br>2.就算有，也不多，只需要将坏块罗列出来，而不需要为每一页建立映射。&nbsp; <br><br>3.如果有很多坏块，就不应该将此硬盘作为Swap空间使用。&nbsp; <br><br>于是，现在的Linux取消了位映射的方法，也就取消了128M的限制。直接用地址访问，限制为2G。&nbsp; <br><br>Swap配置对性能的影响&nbsp; <br><br>分配太多的Swap空间会浪费磁盘空间，而Swap空间太少，则系统会发生错误。&nbsp; <br><br>如果系统的物理内存用光了，系统就会跑得很慢，但仍能运行；如果Swap空间用光了，那么系统就会发生错误。例如，Web服务器能根据不同的请求数量衍生出多个服务进程（或线程），如果Swap空间用完，则服务进程无法启动，通常会出现"application&nbsp;is&nbsp;out&nbsp;of&nbsp;memory"的错误，严重时会造成服务进程的死锁。因此Swap空间的分配是很重要的。&nbsp; <br><br>通常情况下，Swap空间应大于或等于物理内存的大小，最小不应小于64M，通常Swap空间的大小应是物理内存的2-2.5倍。但根据不同的应用，应有不同的配置：如果是小的桌面系统，则只需要较小的Swap空间，而大的服务器系统则视情况不同需要不同大小的Swap空间。特别是数据库服务器和Web服务器，随着访问量的增加，对Swap空间的要求也会增加，具体配置参见各服务器产品的说明。&nbsp; <br><br>另外，Swap分区的数量对性能也有很大的影响。因为Swap交换的操作是磁盘IO的操作，如果有多个 Swap交换区，Swap空间的分配会以轮流的方式操作于所有的Swap，这样会大大均衡IO的负载，加快Swap交换的速度。如果只有一个交换区，所有的交换操作会使交换区变得很忙，使系统大多数时间处于等待状态，效率很低。用性能监视工具就会发现，此时的CPU并不很忙，而系统却慢。这说明，瓶颈在 IO上，依靠提高CPU的速度是解决不了问题的。&nbsp; <br>系统性能监视&nbsp; <br><br>Swap空间的分配固然很重要，而系统运行时的性能监控却更加有价值。通过性能监视工具，可以检查系统的各项性能指标，找到系统性能的瓶颈。本文只介绍一下在Solaris下和Swap相关的一些命令和用途。&nbsp; <br><br>最常用的是Vmstat命令（在大多数Unix平台下都有这样一些命令），此命令可以查看大多数性能指标。&nbsp; <br><br>例如：&nbsp; <br>#&nbsp;vmstat&nbsp;3&nbsp; <br>procs&nbsp;memory&nbsp;swap&nbsp;io&nbsp;system&nbsp;cpu&nbsp; <br>r&nbsp;b&nbsp;w&nbsp;swpd&nbsp;free&nbsp;buff&nbsp;cache&nbsp;si&nbsp;so&nbsp;bi&nbsp;bo&nbsp;in&nbsp;cs&nbsp;us&nbsp;sy&nbsp;id&nbsp; <br>0&nbsp;0&nbsp;0&nbsp;0&nbsp;93880&nbsp;3304&nbsp;19372&nbsp;0&nbsp;0&nbsp;10&nbsp;2&nbsp;131&nbsp;10&nbsp;0&nbsp;0&nbsp;99&nbsp; <br>0&nbsp;0&nbsp;0&nbsp;0&nbsp;93880&nbsp;3304&nbsp;19372&nbsp;0&nbsp;0&nbsp;0&nbsp;0&nbsp;109&nbsp;8&nbsp;0&nbsp;0&nbsp;100&nbsp; <br>0&nbsp;0&nbsp;0&nbsp;0&nbsp;93880&nbsp;3304&nbsp;19372&nbsp;0&nbsp;0&nbsp;0&nbsp;0&nbsp;112&nbsp;6&nbsp;0&nbsp;0&nbsp;100&nbsp; <br>............&nbsp; <br><br>命令说明：&nbsp; <br>vmstat&nbsp;后面的参数指定了性能指标捕获的时间间隔。3表示每三秒钟捕获一次。第一行数据不用看，没有价值，它仅反映开机以来的平均性能。从第二行开始，反映每三秒钟之内的系统性能指标。这些性能指标中和Swap有关的包括以下几项：&nbsp; <br><br><br>procs下的w&nbsp; <br>它表示当前（三秒钟之内）需要释放内存、交换出去的进程数量。&nbsp; <br><br>memory下的swpd&nbsp; <br>它表示使用的Swap空间的大小。&nbsp; <br><br>Swap下的si，so&nbsp; <br>si表示当前（三秒钟之内）每秒交换回内存（Swap&nbsp;in）的总量，单位为kbytes；so表示当前（三秒钟之内）每秒交换出内存（Swap&nbsp;out）的总量，单位为kbytes。&nbsp; <br>以上的指标数量越大，表示系统越忙。这些指标所表现的系统繁忙程度，与系统具体的配置有关。系统管理员应该在平时系统正常运行时，记下这些指标的数值，在系统发生问题的时候，再进行比较，就会很快发现问题，并制定本系统正常运行的标准指标值，以供性能监控使用。&nbsp; <br><br>另外，使用Swapon-s也能简单地查看当前Swap资源的使用情况。例如：&nbsp; <br>#&nbsp;swapon&nbsp;-s&nbsp; <br>Filename&nbsp;Type&nbsp;Size&nbsp;Used&nbsp;Priority&nbsp; <br>/dev/hda9&nbsp;partition&nbsp;361420&nbsp;0&nbsp;3&nbsp; <br><br>能够方便地看出Swap空间的已用和未用资源的大小。&nbsp; <br><br>应该使Swap负载保持在30%以下，这样才能保证系统的良好性能。&nbsp; <br><br>有关Swap操作的系统命令&nbsp; <br><br><br>增加Swap空间，分以下几步：&nbsp; <br>1)成为超级用户&nbsp; <br>$su&nbsp;-&nbsp;root&nbsp; <br><br>2)创建Swap文件&nbsp; <br>#&nbsp;dd&nbsp;if=/dev/zero&nbsp;of=swapfile&nbsp;bs=1024&nbsp;count=65536&nbsp; <br><br>创建一个有连续空间的交换文件。&nbsp; <br><br>3)激活Swap文件&nbsp; <br>#/usr/sbin/swapon&nbsp;swapfile&nbsp; <br><br>swapfile指的是上一步创建的交换文件。&nbsp;4)现在新加的Swap文件已经起作用了，但系统重新启动以后，并不会记住前几步的操作。因此要在/etc/fstab文件中记录文件的名字，和Swap类型，如：&nbsp; <br>/path/swapfile&nbsp;none&nbsp;Swap&nbsp;sw,pri=3&nbsp;0&nbsp;0&nbsp; <br><br>5)检验Swap文件是否加上&nbsp; <br>/usr/sbin/swapon&nbsp;-s&nbsp; <br><br><br>删除多余的Swap空间。&nbsp; <br>1)成为超级用户&nbsp; <br><br>2)使用Swapoff命令收回Swap空间。&nbsp; <br>#/usr/sbin/swapoff&nbsp;swapfile&nbsp; <br><br>3)编辑/etc/fstab文件，去掉此Swap文件的实体。&nbsp; <br><br>4)从文件系统中回收此文件。&nbsp; <br>#rm&nbsp;swapfile&nbsp; <br><br>5)当然，如果此Swap空间不是一个文件，而是一个分区，则需创建一个新的文件系统，再挂接到原来的文件系统上。</p>
<img src ="http://www.blogjava.net/alex/aggbug/124940.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2007-06-18 14:27 <a href="http://www.blogjava.net/alex/archive/2007/06/18/124940.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ssh timeout</title><link>http://www.blogjava.net/alex/archive/2006/09/06/68048.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Wed, 06 Sep 2006 08:07:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/06/68048.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/68048.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/06/68048.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/68048.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/68048.html</trackback:ping><description><![CDATA[how to set the SSH timeout?<br />a: set 'TMOUT=3600' in /etc/profile <br /><br />fine.<br /><img src ="http://www.blogjava.net/alex/aggbug/68048.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-06 16:07 <a href="http://www.blogjava.net/alex/archive/2006/09/06/68048.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]OpenLDAP学习笔记</title><link>http://www.blogjava.net/alex/archive/2006/08/10/62716.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 10 Aug 2006 01:33:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/10/62716.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/62716.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/10/62716.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/62716.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/62716.html</trackback:ping><description><![CDATA[key words : openldap ldap<br /><br /><div class="book" lang="en"><div class="titlepage"><div><div><h1 class="title"><a name="id2875167"></a></h1></div><div><div class="author"><h3 class="author"><span class="firstname">整理：Jims of <a href="http://www.ringkee.com/" target="_top">肥肥世家</a></span></h3><div class="affiliation"><div class="address"><p><tt class="email">&lt;<a href="mailto:jims.yang@gmail.com">jims.yang@gmail.com</a>&gt;</tt></p></div></div></div></div><div><p class="copyright">Copyright © 2004，2005， 本文遵从GNU 的自由文档许可证(Free Document License)的条款，欢迎转载、修改、散布。</p></div><div><p class="pubdate">发布时间:2004年04月07日</p></div><div><p class="pubdate">最近更新:2005年08月08日</p></div><div><div class="abstract"><p class="title"><b>Abstract</b></p><p>LDAP
(轻量级目录服务访问协议，Lightweight Directory Access
Protocol)基于X.500标准，支持TCP/IP，使用简单方便。现在越来越多的网络应用系统都支持LDAP。OpenLDAP是LDAP的一种
开源实现，本笔记基于OpenLDAP2.1.29。</p></div></div></div><hr /></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="chapter"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2809654">1. 目录服务简介</a></span></dt><dd><dl><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2809734">1.1. X.500和LDAP</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2810057">1.2. LDAP产品</a></span></dt></dl></dd><dt><span class="chapter"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2810083">2. OpenLDAP安装笔记</a></span></dt><dd><dl><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2810091">2.1. 源码安装</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2810479">2.2. 数据录入</a></span></dt><dd><dl><dt><span class="sect2"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2810506">2.2.1. 手动录入方法</a></span></dt><dt><span class="sect2"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2810743">2.2.2. 文件方式</a></span></dt><dt><span class="sect2"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2810843">2.2.3. 脚本方式</a></span></dt></dl></dd><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2810869">2.3. 常用命令介绍</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808359">2.4. 启用sasl验证</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808424">2.5. 配置服务器复制</a></span></dt></dl></dd><dt><span class="chapter"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808612">3. 管理工具</a></span></dt><dd><dl><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808628">3.1. phpldapadmin</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808639">3.2. gq</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808650">3.3. CPU</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808661">3.4. JXplore</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808672">3.5. LAM</a></span></dt></dl></dd><dt><span class="chapter"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808693">4. HowTo</a></span></dt><dd><dl><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808700">4.1. 禁止整个服务器的匿名访问</a></span></dt></dl></dd></dl></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="id2809654"></a>Chapter 1. 目录服务简介</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2809734">1.1. X.500和LDAP</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2810057">1.2. LDAP产品</a></span></dt></dl></div><p>目
录是一个为查询、浏览和搜索而优化的专业分布式数据库，它成树状结构组织数据，就好象Linux/Unix系统中的文件目录一样。目录数据库和关系数据库
不同，它有优异的读性能，但写性能差，并且没有事务处理、回滚等复杂功能，不适于存储修改频繁的数据。所以目录天生是用来查询的，就好象它的名字一样。目
录服务是由目录数据库和一套访问协议组成的系统。类似以下的信息适合储存在目录中：</p><div class="itemizedlist"><ul type="disc"><li><p>企业员工和企业客户之类人员信息；</p></li><li><p>公用证书和安全密钥；</p></li><li><p>邮件地址、网址、IP等电脑信息；</p></li><li><p>电脑配置信息。</p></li><li><p>...</p></li></ul></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both;"><a name="id2809734"></a>1.1. X.500和LDAP</h2></div></div></div><p>现在国际上的目录服务标准有两个，一个是较早的X.500标准，一个是较新的LDAP标准。</p><div class="itemizedlist"><ul type="disc"><li><p>X.500是一个协议族，由一系列的概念和协议组成，包括：</p><div class="itemizedlist"><ul type="circle"><li><p>X.501是模型定义，定义目录服务的基本模型和概念；</p></li><li><p>X.509是认证框架，定义如何处理目录服务中客户和服务器认证；</p></li><li><p>X.511是抽象服务定义，定义X.500提供的功能性服务；</p></li><li><p>X.518是分布式操作过程定义，定义如何跨平台处理目录服务；</p></li><li><p>X.519
是协议规范，定义了X.500协议，包括DAP(Directory Access Protocol，目录访问协议)、DSP(Directory
System Protocol，目录系统协议)、DOP(Directory Operator
Protocol，目录操作绑定协议)、DISP(Directory Information Shadowing
Protocol，目录信息阴影协议 )；</p></li><li><p>X.520定义属性类型要求；</p></li><li><p>X.521定义对象类型；</p></li><li><p>X.525定义如果在目录服务器间复制内容。</p></li></ul></div><p>X.500标准中定义了很多内容，包括：</p><div class="itemizedlist"><ul type="circle"><li><p>定义了信息模型，确定目录中信息的格式和字符集，如何在项中表示目录信息(定义对象类、属性等模式)；</p></li><li><p>定义命名空间，确定对信息进行的组织和引用，如何组织和命名项-目录信息树DIT和层次命名模型；</p></li><li><p>定义功能模型，确定可以在信息上执行的操作；</p></li><li><p>定义认证框架，保证目录中信息的安全，如何实现目录中信息的授权保护-访问控制模型；</p></li><li><p>定义分布操作模型，确定数据如何分布和如何对分布数据执行操作，如何将全局目录树划分为管理域，以便管理。</p></li><li><p>定义客户端与服务器之间的通信的各种协议。</p></li></ul></div><p>由于X.500较复杂，且需严格遵照OSI七层协议模型。造成应用开发较困难。所以开发了LDAP，以便在INTERNET上使用。</p></li><li><p>LDAP协议于1993年获批准，产生LDAPv1版，1997年发布最新的LDAPv3版，该版本是LDAP协议发展的一个里程碑，它作为X.500的简化版提供了很多自有的特性，使LDAP功能更为完备，具有更强大的生命力。</p><p>LDAP也是一个协议族，包含以下内容：</p><div class="itemizedlist"><ul type="circle"><li><p>RFC 2251--LDAPv3核心协议，定义了LDAPv3协议的基本模型和基本操作；</p></li><li><p>RFC 2252--定义LDAPv3基本数据模式(Schema)(包括语法、匹配规则、属性类型和对象类)以及标准的系统数据模式；</p></li><li><p>RFC 2253--定义LDAPv3中的分辩名(DN)表达式；</p></li><li><p>RFC 2254--定义了LDAPv3中的过滤表达式；</p></li><li><p>RFC 2255--定义LDAPv3统一资源地址的格式；</p></li><li><p>RFC 2256--定义LDAPv3中使用X.500的Schema列表；</p></li><li><p>RFC 2829--定义了LDAPv3中的认证方式；</p></li><li><p>RFC 2830--定义了如何通过扩展使用TLS服务；</p></li><li><p>RFC 1823--定义了C的LDAP客户端API开发接口；</p></li><li><p>RFC 2847--定义了LDAP数据导入、导出文件接口LDIF。</p></li></ul></div><p>这些协议定义了LDAP的内容，包括：</p><div class="itemizedlist"><ul type="circle"><li><p>定义了一个信息模型，确定了LDAP目录中信息的格式和字符集，如何表示目录信息(定义对象类、属性、匹配规则和语法等模式)；</p></li><li><p>定义了命名空间，确定信息的组织方式--目录树DIT，以DN和RDN为基础的命名方式，以及LDAP信息的Internet表示方式；</p></li><li><p>定义了功能模型，确定在可以在信息上执行的操作及API。</p></li><li><p>定义了安全框架，保证目录中信息的安全，定义匿名、用户名/密码、SASL等多种认证方式，以及与TLS结合的通讯保护框架；</p></li><li><p>定义分布式操作模型，基于指引方式的分布式操作框架；</p></li><li><p>定义了LDAP扩展框架。</p></li></ul></div></li></ul></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both;"><a name="id2810057"></a>1.2. LDAP产品</h2></div></div></div><p>现
在市场上有关LDAP的产品已有很多，各大软件公司都在他们的产品中集成了LDAP服务，如Microsoft的ActiveDirectory、
Lotus的Domino
Directory、IBM的WebSphere中也集成了LDAP服务。LDAP的开源实现是OpenLDAP，它比商业产品一点也不差，而且源码开
放。</p></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="id2810083"></a>Chapter 2. OpenLDAP安装笔记</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2810091">2.1. 源码安装</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2810479">2.2. 数据录入</a></span></dt><dd><dl><dt><span class="sect2"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2810506">2.2.1. 手动录入方法</a></span></dt><dt><span class="sect2"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2810743">2.2.2. 文件方式</a></span></dt><dt><span class="sect2"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2810843">2.2.3. 脚本方式</a></span></dt></dl></dd><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2810869">2.3. 常用命令介绍</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808359">2.4. 启用sasl验证</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808424">2.5. 配置服务器复制</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both;"><a name="id2810091"></a>2.1. 源码安装</h2></div></div></div><p>我的安装方法是以源码编译的方式进行的，以root用户进行安装。安装所需软件如下：</p><div class="itemizedlist"><ul type="disc"><li><p><a href="http://www.openldap.org/" target="_top">openldap-2.1.29</a></p></li><li><p><a href="http://www.sleepycat.com/" target="_top">Berkeley DB 4.2.52</a></p></li></ul></div><p>具体的安装步骤如下：</p><div class="orderedlist"><ol type="1"><li><p>由于openldap需要Berkeley DB来存放数据，所以需先安装Berkeley DB 4.2.52，可到它的网站下载，网址见上面。运行下面的命令解压：</p><pre class="screen"># tar -zxvf db-4.2.52.tar.gz<br /></pre><p>解完压后，会生成一个db-4.2.52目录,进行该目录下的build_unix目录。执行以下命令进行配置安装。</p><pre class="screen"># ../dist/configure<br /># make<br /># make install<br /></pre><p>也是按linux源码安装的三步曲完成，没有什么好说的了。该软件默认是安装在/usr/local/BerkeleyDB.4.2目
录下。安装完成后，要把/usr/local/BerkeleyDB.4.2/lib的库路径加到/etc/ld.so.conf文件内，添加完成后执行
一次ldconfig，使配置文件生效。这样编译openldap时才能找到相应的库文件。这样资料库就安装完成了，接下来可以安装openldap了。
ld.so.conf是什么东西？它就是系统动态链接库的配置文件。此文件内,存放着可被LINUX共享的动态链接库所在目录的名字(系统目录/lib,
/usr/lib除外)，各个目录名间以空白字符(空格，换行等)或冒号或逗号分隔。一般的LINUX发行版中，此文件均含一个共享目录
/usr/X11R6/lib，为X window窗口系统的动态链接库所在的目录。
ldconfig是它的管理命令，具体操作方法可查询man手册，这里就不细讲了。</p></li><li><p>到openldap官方网站下载最新
的稳定版源码，并解压。查看INSTALLT
和README文档，这个很重要，因为安装方法和一些注意事项都在里面有介绍。认真弄明白文档内容能节省你不少的安装调试时间。这也是开源软件的一个特
点，给用户提供了最大的灵活性和可配置性。但也增加了系统安装配置的难度，需要有相关的文档配置说明和指导。在官方网站上还有详细的帮助文件，在整个系统
配置中需要经常查询。</p><pre class="screen"># tar -zxvf openldap-stable-20040329.tgz<br /></pre><p>解压完成后，会生成一个openldap-2.1.29目录。进行该目录，执行以下命令进行配置安装。</p><pre class="screen"># env CPPFLAGS="-I/usr/local/BerkeleyDB.4.2/include" <br />LDFLAGS="-L/usr/local/BerkeleyDB.4.2/lib" ./configure --prefix=/usr/local/openldap <br />--enable-ldbm <br /></pre><p>注意以上配置语句，要设置资料库的include和lib路径，否则在配置到资料库相关内容时会提示Berkeley DB版本不兼容，并中断配置。如果没有--enable-ldbm选项，在make test时会提示ldbm找不到。为了减少出错，还是加上为好。</p><pre class="screen">#make depens<br />#make<br />#make test<br /></pre><p>在make test阶段要花费较长时间进行测试，好像有16项吧。你可以放松一下，上上网，聊聊天，听听歌，呵呵，开玩笑了，这个时间应该是最紧张的了。成与不成就看这下的了，如果没问题就可安装了。</p><pre class="screen">#make install<br /></pre><p>通过配置命令可以看出，我们把openldap安装到/usr/local/openldap目录下。建议以源码安装的软件都放到独立的目录下，不要放到软件默认的目录。好处是方便管理和控制，所有文件在统一的目录下，卸载软件只要删除整个目录就可以了。</p></li><li><p>安
装完相关软件后就可以着手配置了。Berkeley DB资料库没什么好配置的。主要是配置openldap
服务。配置文件在软件的安装目录的etc/openldap下，有四个文件，主要的是slapd.conf and
ldap.conf，其它两个是backup文件。首先，我们先来配置slapd.conf文档。系统默认的slapd.conf文件如下：</p><pre class="screen"># $OpenLDAP: pkg/ldap/servers/slapd/slapd.conf,v 1.23.2.8 2003/05/24 23:19:14 kurt Exp $<br /># <br /># See slapd.conf(5) for details on configuration options.<br /># This file should NOT be world readable. <br /># <br />include      /usr/local/openldap/etc/openldap/schema/core.schema  <br />#设置schema配置文档包含<br /><br /># Define global ACLs to disable default read access.<br /><br /># Do not enable referrals until AFTER you have a working directory<br /># service AND an understanding of referrals.<br />#referral       ldap://root.openldap.org<br /><br />pidfile         /usr/local/openldap/var/slapd.pid <br />#设置pid和args文档位置<br />argsfile        /usr/local/openldap/var/slapd.args<br /><br /># Load dynamic backend modules:<br /># modulepath    /usr/local/openldap/libexec/openldap<br /># moduleload    back_bdb.la <br /># moduleload    back_ldap.la<br /># moduleload    back_ldbm.la <br /># moduleload    back_passwd.la<br /># moduleload    back_shell.la<br /><br /># Sample security restrictions <br />#       Require integrity protection (prevent hijacking)<br />#       Require 112-bit (3DES or better) encryption for updates<br />#       Require 63-bit encryption for simple bind<br /># security ssf=1 update_ssf=112 simple_bind=64<br /><br /># Sample access control policy: <br />#       Root DSE: allow anyone to read it<br />#       Subschema (sub)entry DSE: allow anyone to read it<br />#       Other DSEs: <br />#       Subschema (sub)entry DSE: allow anyone to read it<br />#       Other DSEs:<br />#               Allow self write access<br />#               Allow authenticated users read access<br />#               Allow anonymous users to authenticate<br />#       Directives needed to implement policy:<br /># access to dn.base="" by * read<br /># access to dn.base="cn=Subschema" by * read<br /># access to *<br />#       by self write<br />#       by users read<br />#       by anonymous auth<br />#<br /># if no access controls are present, the default policy is:<br />#       Allow read by all<br />#<br /># rootdn can always write!<br /><br />#######################################################################<br /># ldbm database definitions<br />#######################################################################<br /><br />database        bdb                                <br />#设置使用的资料库，也可用lbdm。<br />suffix          "dc=my-domain,dc=com"              <br />#设置目录后缀<br />rootdn          "cn=Manager,dc=my-domain,dc=com"   <br />#设置目录管理员<br /># Cleartext passwords, especially for the rootdn, should<br /># be avoid.  See slappasswd(8) and slapd.conf(5) for details.<br /># Use of strong authentication encouraged.<br />rootpw          secret                             <br />#设置管理密码，这里用了明文的“secret”密码。这样设置不安全，需使用加密的密码，下面会讲到如何设置加密密码。<br /># The database directory MUST exist prior to running slapd AND <br /># should only be accessible by the slapd and slap tools.<br /># Mode 700 recommended.<br />directory       /usr/local/openldap/var/openldap-data  <br />#设置资料库路径<br /># Indices to maintain<br />index   objectClass     eq                        <br />#设置目录项索引<br /></pre><p>要服务器正常动作，要修改一些始初参数和设置，修改后的配置文档如下：</p><pre class="screen"># $OpenLDAP: pkg/ldap/servers/slapd/slapd.conf,v 1.23.2.8 2003/05/24 23:19:14 kurt Exp $<br />#<br /># See slapd.conf(5) for details on configuration options.<br /># This file should NOT be world readable.<br />#<br />#为了有效使用目录服务，包含相关的文件。注意，在包含文件时是要按一定顺序的，因为<br />#文件里的属性存在依赖关系。如果顺序不对，服务器启动不了，文档间的依赖关系在文档<br />#中都有说明，请仔细查看一下。如果懒得看也可以按我的顺序。<br />include         /usr/local/openldap/etc/openldap/schema/core.schema<br />include         /usr/local/openldap/etc/openldap/schema/corba.schema<br />include         /usr/local/openldap/etc/openldap/schema/cosine.schema<br />include         /usr/local/openldap/etc/openldap/schema/inetorgperson.schema    <br />include         /usr/local/openldap/etc/openldap/schema/misc.schema             <br />include         /usr/local/openldap/etc/openldap/schema/openldap.schema<br />include         /usr/local/openldap/etc/openldap/schema/nis.schema<br />include         /usr/local/openldap/etc/openldap/schema/samba.schema<br /># Define global ACLs to disable default read access.<br /><br /># Do not enable referrals until AFTER you have a working directory<br /># service AND an understanding of referrals.<br />#referral       ldap://root.openldap.org<br /><br />pidfile         /usr/local/openldap/var/slapd.pid<br />argsfile        /usr/local/openldap/var/slapd.args<br /><br />loglevel 1                       <br />#增加了日志功能，需修改syslog配置文件，在文件中增加一项：local4.* /var/log/ldap.log日志级别定义可查相官方网站的文档。<br />#1级记录的信息很多，可用于调试。<br /># Load dynamic backend modules:<br /># modulepath    /usr/local/openldap/libexec/openldap<br /># moduleload    back_bdb.la<br /># moduleload    back_ldap.la<br /># moduleload    back_ldbm.la<br /># moduleload    back_passwd.la<br /># moduleload    back_shell.la<br /><br /># Sample security restrictions<br />#       Require integrity protection (prevent hijacking)<br />#       Require 112-bit (3DES or better) encryption for updates<br />#       Require 63-bit encryption for simple bind<br /># security ssf=1 update_ssf=112 simple_bind=64<br /><br /># Sample access control policy:<br />#       Root DSE: allow anyone to read it<br />#       Subschema (sub)entry DSE: allow anyone to read it<br />#       Other DSEs:<br />#               Allow self write access<br />#               Allow authenticated users read access<br />#               Allow anonymous users to authenticate<br />#       Directives needed to implement policy:<br /># access to dn.base="" by * read<br /># access to dn.base="cn=Subschema" by * read<br /># access to *<br />#       by self write<br />#       by users read<br />#       by anonymous auth<br />#<br /># if no access controls are present, the default policy is:<br />#       Allow read by all<br />#<br /># rootdn can always write!<br /><br />#######################################################################<br /># ldbm database definitions<br />#######################################################################<br /><br />database        bdb<br />suffix          "dc=it,dc=com"<br />#改成你自已的目录后缀，<br />rootdn          "cn=root,dc=it,dc=com"<br />#设置root为管理员，与linux的root没有什么关系。<br /># Cleartext passwords, especially for the rootdn, should<br /># be avoid.  See slappasswd(8) and slapd.conf(5) for details.<br /># Use of strong authentication encouraged.<br />rootpw          {MD5}mjkiuPt0wXhpxxkdiOOO+0000000AKq0by<br />#设置root密码，用MD5加密。密码串用slappasswd -h {MD5}指令生成<br /># The database directory MUST exist prior to running slapd AND <br /># should only be accessible by the slapd and slap tools.<br /># Mode 700 recommended.<br />directory       /usr/local/openldap/var/openldap-data    <br /># Indices to maintain<br />index   objectClass     eq<br />#这里可根据你的需要设置相关索引，以加快查询速度。具体内容可查询官方网站管理手册。<br /><br />#ACL configure以下内容定义访问控制<br />access to  attr=userPassworduserPassword<br />#只能由自已修改，有效验证用户查询。<br />        by self write<br />        by anonymous auth<br />access to attr=mail<br />        by dn="cn=root,dc=it,dc=tigerhead" writemail<br />#只能由自已修改，有效验证用户查询。<br />        by self write<br />        by anonymous auth<br />access to dn=".*,dc=it,dc=tigerhead"<br />#允许所有人查询没受控制访问限制的信息。<br />        by self write<br />        by * read<br /></pre><p>到现在为止，服务器基本就配置完成了，可以启动了，服务器程序是位于安装目录的libexec下的slapd程序。注意，不是
sldap哦。ok，到现在为止，服务器基本就配置完成了，可以启动了，服务器程序是位于安装目录的libexec下的slapd程序。注意，不是
sldap哦。启动服务器执行以下命令：</p><pre class="screen"># ./slapd<br /></pre><p>如果没有提示什么出错信息，直接返回shell状态，就说明服务器正常启动了，你可以查询日志或用ps -aux查看。或用以下命令查询服务器:</p><pre class="screen">ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts<br /></pre><p>如果命令执行成功，返回一些信息，则说明服务器正常运行了。如果启动不成功，它会提示一些出错信息，多数是slapd.conf配置出错。回头仔细核查一下配置文档。</p></li><li><p>客户端配置文档是ldap.conf。该文档相当简单，其实不用配置也能正常操作。</p><pre class="screen"># $OpenLDAP: pkg/ldap/libraries/libldap/ldap.conf,v 1.9 2000/09/04 19:57:01 kurt Exp $<br />#<br /># LDAP Defaults<br />#<br /><br /># See ldap.conf(5) for details<br /># This file should be world readable but not world writable.<br /><br />BASE    dc=it, dc=com设置目录起点<br />#URI    ldap://ldap.example.com ldap://ldap-master.example.com:666<br /><br />#SIZELIMIT      12<br />#TIMELIMIT      15<br />#DEREF          never<br /></pre></li></ol></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both;"><a name="id2810479"></a>2.2. 数据录入</h2></div></div></div><p>服
务器正常运作后，就可以录入信息了。信息的录入有三种方法，一种是手工录入，一种是.ldif文件格式录入，一种是脚本自动录入。我们先从最基础的手工录
入方式开始介绍，了解录入信息的格式。明白了手工录入的格式，其它两种方式都很容易明白。信息录入用到ldapadd这个程序。可在安装目录的bin目录
下找到。</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2810506"></a>2.2.1. 手动录入方法</h3></div></div></div><div class="itemizedlist"><ul type="disc"><li><p>第一步是要建立DN：</p><pre class="screen"># ldapadd -x -D 'cn=root,dc=it,dc=com' -W<br />dn: dc=it,dc=com<br />objectClass: dcObject<br />objectClass: organization<br />dc: it<br />o: Corporation<br />description: d Corporation<br />注意：如果你用复制/粘贴功能把以上内容拷贝过去，一定要注意每行后面不要有空格，建议还是手工输入，按Ctrl+d存盘。<br /></pre></li><li><p>第二步是建立RDN:</p><pre class="screen"># ldapadd -x -D 'cn=root,dc=it,dc=com' -W        <br />#-x表示用简单验证，-D表示指定目录，-W表示弹出密码输入提示<br /></pre><p>输入密码，这里的密码是在配置文件中rootpw项设置的密码，不是操作系统中root用户的密码。验证通过后就可输入以下内容：</p><pre class="screen">dn: uid=qq,dc=it,dc=com<br />objectClass: person<br />objectClass: organizationalPerson<br />objectClass: inetOrgPerson<br />uid: qq<br />cn: qq<br />sn: qq<br />telephoneNumber: 138888888<br />description: openldap test<br />telexNumber: tex-8888888<br />street: my street<br />postOfficeBox: postofficebox<br />displayName: qqdisplay<br />homePhone: home1111111<br />mobile: mobile99999<br />mail:qq@qq.com<br /></pre><p>输入完所有信息后，按Ctrl+d结束存盘。如果出现出错信息，请查一下对象类和属性的对应关系有没有错或输入失误。初学者就容易出错
的地方是对象类和属性的对应关系没有处理好。对象类和属性是在schema文档中定义的。它们之间的关系是这样的，对象类中有些属性是必选的，有些属性是
可选的。录入信息的属性必须在对象类中有定义才能用。</p></li></ul></div><p>输入以下命令可查询到刚才输入的信息。</p><pre class="screen"># ldapsearch -x -b 'dc=it,dc=com'            <br />-b选项是设置目录起点，如果设置了客户端的BASE配置参数，该项可不用。<br /></pre><p>如果按以上配置文件设置了acl，用上面的查询命令是查询不到受保护的内容的。如上面的userPassword and mail。要查询到这些受限内容，需要通过验证才可以：</p><pre class="screen"># ldapsearch -x -LLL -h it.com -b 'dc=it,dc=com' -D 'uid=qq,dc=it,dc=com' -W 'uid=qq'<br />接着提示输入密码。输入userPassword的密码回车，所有信息就都出来了。<br /></pre></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2810743"></a>2.2.2. 文件方式</h3></div></div></div><p>.ldif文件方式也就是把以上手工输入的内容先写入一个.ldif文件中，然后，用ldapadd命令的-f参数导入。</p><pre class="screen"># ldapadd -x -D "cn=root,dc=it,dc=com" -W -f test.ldif<br /></pre><p>一个完整的global.ldif文件例子：</p><pre class="screen">dn: dc=info, dc=net<br />objectClass: top<br />objectClass: organization<br />o: info.net<br /><br />dn: ou=People, dc=info, dc=net<br />objectClass: top<br />objectClass: organizationalUnit<br />ou: People<br />description: User Info<br /><br />dn: cn=Admin, dc=info, dc=net<br />objectClass: top<br />objectClass: person<br />objectClass: organizationalPerson<br />cn: Admin<br />sn: Admin<br />userPassword: Admin<br />description: Administrator for info.net<br /><br />dn: id=1, ou=People, dc=info, dc=net<br />objectclass: top<br />objectclass: InfoPerson<br />id: 1<br />username: 张三<br />tel:021-63138990<br />card_id:ABC001<br /></pre><p>我们也可用slapadd命令来导入数据。该命令可以导入包含一些系统信息的ldif文件，如：</p><pre class="screen">dn: dc=it,dc=com<br />objectClass: top<br />objectClass: dcObject<br />objectClass: organization<br />dc: it<br />structuralObjectClass: organization<br />entryUUID: d97b06da-d77e-1028-9866-d4ec7ac00d12<br />creatorsName: cn=anonymous            #系统信息<br />createTimestamp: 20041201005115Z      #系统信息<br />o:: 5bm/5bee5biC6JmO5aS055S15rGg6ZuG5Zui5pyJ6ZmQ5YWs5Y+4<br />userPassword:: e01ENX14TXBDT0tDNUk0SU56RkNhYjNXRW13PT0=<br />entryCSN: 2004120603:50:08Z#0x0001#0#0000     #系统信息<br />modifiersName: cn=admin,dc=it,dc=com          #系统信息<br />modifyTimestamp: 20041206035008Z              #系统信息<br /></pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table summary="Note" border="0"><tbody><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="http://www.ringkee.com/note/opensource/images/note.png" /></td><th align="left"><br /></th></tr><tr><td colspan="2" align="left" valign="top">再次提醒，注意每行后面不要留有空格。</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2810843"></a>2.2.3. 脚本方式</h3></div></div></div><p>脚本录入方式需要自已编写脚本，或到网上下载。有一个用PHP写的LDAP管理工具不错，叫phpLDAPadmin。可以到以下网址下载：<a href="http://phpldapadmin.sourceforge.net/" target="_top">http://phpldapadmin.sourceforge.net</a>。安装方法也很简单，只要解压出来，拷贝到apache的web目录下，按说明配置一下设定文档,就ok了。</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both;"><a name="id2810869"></a>2.3. 常用命令介绍</h2></div></div></div><p>接着为大家介绍一下几个常用的ldap命令，如果你用了phpLDAPadmin程序，其实它已经有一个很好的图形介面帮你完成这些命令了。但了解一下还是对你还是很有益的，因为命令方法才是最根本的。</p><div class="itemizedlist"><ul type="disc"><li><p>删除命令ldapdelete</p><pre class="screen"># ldapdelete -x -D 'cn=root,dc=it,dc=com' -W 'uid=qq1,dc=it,dc=com'<br /></pre></li><li><p>重新索引ldap数据库命令slapindex</p><pre class="screen"># slapindex -f slapd.conf<br /></pre></li><li><p>设置使用者密码，当然了，你的用户需要有userPassword项了。</p><pre class="screen">#ldappasswd -x -D "cn=root,dc=it,dc=com" -W "uid=qq1,dc=it,dc=com" -S <br />New password: <br />Re-enter new password: <br />Enter bind password: <br />Result: Success (0)<br /></pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table summary="Note" border="0"><tbody><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="http://www.ringkee.com/note/opensource/images/note.png" /></td><th align="left"><br /></th></tr><tr><td colspan="2" align="left" valign="top">"Enter bind password" 是 "cn=root,dc=it,dc=com"管理员的密码。</td></tr></tbody></table></div></li><li><p>管理员密码更改 </p><pre class="screen">#slappasswd <br />New password <br />Re-enter new password <br />{SSHA}83DJ4KVwqlk1uh9k2uDb8+NT1U4RgkEs <br /></pre><p>接下再拷贝到 path/to/sldap.conf 的 rootpw 即可,重启使用配置文件生效</p></li><li><p>通过ldapmodify修改目录内容</p><pre class="screen"># ldapmodify -x -D "cn=root,dc=it,dc=com" -W -f modify.ldif<br /></pre><p>通过ldif文件修改ldap数据，ldif文件格式如下：</p><pre class="screen">dn: cn=qq,dc=it,dc=com<br />changetype: modify<br />replace: mail<br />mail: modme@example.com<br />-<br />add: title<br />title: Grand Poobah<br />-<br />add: jpegPhoto<br />jpegPhoto:&lt; file:///tmp/modme.jpeg<br />-<br />delete: description<br />-<br /></pre></li></ul></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both;"><a name="id2808359"></a>2.4. 启用sasl验证</h2></div></div></div><p>前提是你在系统中安装了sasl认证库，并在编译openldap时支持它，默认就支持了。到<a href="http://asg.web.cmu.edu/cyrus" target="_top">http://asg.web.cmu.edu/cyrus</a>下载。安装方法见我写的sendmail安装笔记。安装好之后，需要在sasl中建立相应的帐号，用以下命令可完成。</p><pre class="screen"># saslpasswd2 -c test<br /></pre><p>接着配置slapd.conf文件，加入以下内容。</p><pre class="screen">sasl-regexp<br />        uid=(.*),cn=.*,cn=auth<br />        uid=$1,dc=it,dc=com<br /></pre><p>重启服务器使配置文件生效。这个配置是最大权限的配置，如果要细化请查阅相关文档。用以下命令测试。</p><pre class="screen"># ldapsearch -U qq  -b 'uid=qq,dc=it,dc=com' -D 'dc=it,dc=com' -Y DIGEST-MD5<br /></pre><p>采用digest-md5验证,提示密码，输入saslpasswd2的密码。</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both;"><a name="id2808424"></a>2.5. 配置服务器复制</h2></div></div></div><p>在
一些关键的应用场合，我们需设置多个ldap服务器实例，且数据要保持同步。当一台服务器出现故障或被黑客攻击时，我们就能继续保持应用的正常运行。通过
DNS的轮流查询功能，还能实现服务器的负载均衡，提高响应速度。在openldap中有一个slurpd进程，利用slurpd进程可帮助我们实现多台
ldap服务器数据的同步功能。下面简单介绍一下主、从ldap服务器的配置。</p><p>slurpd运行在主服务器上，它能把主服务器上的变化通过
LDAP协议传送到从服务器上。从服务器上的变化不能传送到主服务器上，也就是说是单向同步的。主从服务器的版本最好一样，以减少兼容性问题。主从服务器
的安装方法是一样的，关键是配置文件有所不同。我的操作系统是debian sarge，在确保主从服务器能正常运行的前提下进行以下配置：</p><div class="itemizedlist"><ul type="disc"><li><p>首先，把主从服务器关闭。通过以下三步操作静态同步主从服务器上的数据：</p><div class="orderedlist"><ol type="1"><li><p>把主服务器上/var/lib/ldap目录下的所有数据库文件全部拷贝到从服务器的同目录中，覆盖原有文件。</p></li><li><p>把主服务器上的/etc/ldap/schema目录下的所有schema文件拷贝到从服务器的同目录中，覆盖原有文件。</p></li><li><p>把主服务器上/etc/ldap/slapd.conf文件拷贝到从服务器的同目录中，覆盖原有文件。</p></li></ol></div></li><li><p>配置主服务器上的slapd.conf文件，取消replogfile指令前的注释符号，取消后的结果如下：</p><pre class="screen"># Where to store the replica logs for database #1<br />replogfile      /var/lib/ldap/replog<br /></pre><p>增加replica指令，如：</p><pre class="screen">#replace config<br />replica uri=ldap://192.168.6.195:389     #指定从服务器主机名和端口号<br />        binddn="cn=admin,dc=com"         #指定需同步的DN的管理员<br />        bindmethod=simple credentials=1  #指定验证方式和需同步的DN的管理员密码<br /></pre></li><li><p>配置从服务器上的slapd.conf文件，增加updatedn指令，如：</p><pre class="screen">updatedn "cn=admin,dc=com"          #与主服务器的binddn对应<br /></pre><p>在从服务器的配置文件中，不要包含replica和replogfile指令。</p></li><li><p>先启动主服务器的slapd和slurpd，再启动从服务器的slapd。</p></li></ul></div><p>配置完成后，我们可测试一下，在主服务器上修改一个目录项，在从服务器上可查看目录项的数据已同步。</p></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="id2808612"></a>Chapter 3. 管理工具</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808628">3.1. phpldapadmin</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808639">3.2. gq</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808650">3.3. CPU</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808661">3.4. JXplore</a></span></dt><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808672">3.5. LAM</a></span></dt></dl></div><p>开源的目录服务管理工具有很多，包括phpldapadmin，gq，CPU，JXplore等。这些工具可帮助我们方便维护目录服务器上的数据。这些工具各有优缺点，下面简要介绍一下，详细的内容可参考相关的官方网站。</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both;"><a name="id2808628"></a>3.1. phpldapadmin</h2></div></div></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both;"><a name="id2808639"></a>3.2. gq</h2></div></div></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both;"><a name="id2808650"></a>3.3. CPU</h2></div></div></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both;"><a name="id2808661"></a>3.4. JXplore</h2></div></div></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both;"><a name="id2808672"></a>3.5. LAM</h2></div></div></div><p>官方网站：<a href="http://lam.sourceforge.net/index.htm" target="_top">http://lam.sourceforge.net/index.htm</a></p></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="id2808693"></a>Chapter 4. HowTo</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="http://www.ringkee.com/note/opensource/openldap.htm#id2808700">4.1. 禁止整个服务器的匿名访问</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both;"><a name="id2808700"></a>4.1. 禁止整个服务器的匿名访问</h2></div></div></div><p>在slapd.conf配置文件中加入disallow bind_anon即可。</p></div></div></div><br /><img src ="http://www.blogjava.net/alex/aggbug/62716.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-10 09:33 <a href="http://www.blogjava.net/alex/archive/2006/08/10/62716.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]使用 OpenLDAP 集中管理用户帐号</title><link>http://www.blogjava.net/alex/archive/2006/08/10/62714.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 10 Aug 2006 01:19:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/10/62714.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/62714.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/10/62714.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/62714.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/62714.html</trackback:ping><description><![CDATA[key words : openldap ldap <br /><br /><br /><p>2006 年  6 月  26 日</p><blockquote>使用轻量级目录访问协议（LDAP）构建集中的身份验证系统可以减少管理成
本，增强安全性，避免数据复制的问题，并提高数据的一致性。随着 Linux® 的不断成熟，已经出现了很多工具用来简化用户帐号信息到 LDAP
目录的迁移。还开发了一些工具用来在客户机和目录服务器之间启用加密通信配置，并通过复制提供容错性。本文将向您展示如何配置服务器和客户机在 Red
Hat Linux 上使用 OpenLDAP。</blockquote><!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES--><p><a name="N1004F"><span class="atitle">简介</span></a></p><p>Linux 发行版中提供的 OpenLDAP 软件按照一个客户机/服务器模型实现了轻量级目录访问协议（LDAP）。LDAP
的设计目的是提供一种有效的方法来查找和管理信息。OpenLDAP
软件和包提供了创建目录信息树（一个主要进行读操作的数据库）的工具。本文向您展示如何存储用户的帐号信息，并修改身份验证服务来使用 LDAP
获取所需要的信息。内部细节并不重要，因为这些工具可以将数据库的内容以文本格式（LDAP 数据交换格式，LDIF）呈现在您的面前。</p><p>LDAP 信息被组织成属性和值的组合，称为 <i>条目（entry）</i>。条目可能会具有必须的属性或可选属性。一个条目的属性必须要遵循 /etc/openldap/schema/ 模式文件中定义的规则。规则包含在条目的 <i>objectclass</i> 属性中。看一下下面的关系，我们可以看出 <code>posixAccount</code> objectclass 中包含了密码文件条目的信息（<code>posixAccount userPassword</code> 是文件条目的 base64 编码）。</p><br /><a name="figure1"><b>图 1. LDAP 目录条目和 Linux 密码文件之间的关系</b></a><br /><img alt="LDAP 目录条目和 Linux 密码文件之间的关系" src="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/figure1.jpg" height="174" width="572" /><br /><p>文件 /etc/openldap/schema/nis.schema 为 posixAccount 对象类中的条目定义了所有的属性和 objectclass。例如，下面是对 <code>uidNumber</code> 属性的描述：</p><pre>attributetype ( 1.3.6.1.1.1.1.0 NAME 'uidNumber'<br />   DESC 'An integer uniquely identifying a user in an administrative domain'<br />   EQUALITY integerMatch<br />   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )<br /></pre><p>所有的属性类型都已经定义了，它们被收集到 <code>posixAccount</code> objectclass 中。例如：</p><pre>objectclass ( 1.3.6.1.1.1.2.0 NAME 'posixAccount' SUP top AUXILIARY<br />   DESC 'Abstraction of an account with POSIX attributes'<br />   MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )<br />   MAY ( userPassword $ loginShell $ gecos $ description ) )<br /></pre><p><code>ldapuser</code> 条目具有一个识别名属性 <code>dn</code>，它用作用户名，并与 <code>userPassword</code> 一起用来在 LDAP 目录中记录信息，或与 LDAP 目录绑定在一起使用。</p><p>LDAP 为作为容器使用的特殊条目提供了将这些条目组织成树结构的功能。在这个例子中，我们将使用一个容器 <code>People</code> 保存用户帐号信息，使用另外一个容器 <code>Groups</code> 保存组帐号信息。所生成的目录信息树如图 2 所示。</p><br /><a name="figure2"><b>图 2. 用户帐号信息使用的目录信息树</b></a><br /><img alt="用户帐号信息使用的目录信息树" src="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/figure2.gif" height="191" width="572" /><br /><p>让我们来看一下如何配置 OpenLDAP 服务器，如何将信息从系统文件迁移到 LDAP 目录中，如何配置 OpenLDAP 客户机通过
LDAP 对用户进行身份验证。在使用一个集中的身份验证数据库时，应该通过使用复制技术采用第二个 LDAP
服务器提供高可用性，这样在主服务器出现问题时，就可以使用第二个 LDAP
服务器响应客户机的请求。由于诸如密码之类的身份验证数据会通过网络进行传输，因此希望使用 TSL 协议建立加密通信连接。</p><p>我们的 OpenLDAP 服务器和客户机都是虚拟机，上面运行的是 Red Hat Enterprise Linux AS release 4（Nahant Update 1）。在我们的例子中使用了 <a href="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/#table1">表 1</a> 所列出的系统。如果想模仿这些例子，请使用适合您自己的设置。</p><br /><a name="table1"><b>表 1. 系统网络信息</b></a><br /><table class="data-table-1" summary="System network information" border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><th>角色</th><th>主机名</th><th>IP 地址</th></tr><tr><td class="tb-row">OpenLDAP 主服务器</td><td>dhcp64-233.ibm.com</td><td>9.47.64.233</td></tr><tr><td class="tb-row">OpenLDAP 从服务器</td><td>dhcp64-253.ibm.com</td><td>9.47.64.253</td></tr><tr><td class="tb-row">OpenLDAP 客户机</td><td>dhcp64-251.ibm.com</td><td>9.47.64.251</td></tr></tbody></table><br /><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br /><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br /><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" /><br /></td><td align="right" valign="top"><a href="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/#main" class="fbox"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="configserver"><span class="atitle">配置 LDAP 服务器</span></a></p><p>我们使用 Red Hat Enterprise Linux release 4 Update 1 上的包来构建服务器：</p><ul><li><b>openldap-2.2.13-2</b>：包含 OpenLDAP 配置文件、库和文档</li><li><b>openldap-servers-2.2.13-2</b>：包含 slapd 和 slurpd 服务器、迁移脚本和相关文件</li><li><b>openldap-clients-2.2.13-2</b>：包含客户机程序，用来访问和修改 OpenLDAP 目录</li></ul><p>OpenLDAP 包在服务器上安装了很多程序：</p><ul><li>守护进程：
<ul><li><b>slapd</b>：主 LDAP 服务器</li><li><b>slurpd</b>：负责与复制 LDAP 服务器保持同步的服务器</li></ul></li><li>对网络上的目录进行操作的客户机程序。下面这两个程序是一对儿：
<ul><li><b>ldapadd</b>：打开一个到 LDAP 服务器的连接，绑定、修改或增加条目</li><li><b>ldapsearch</b>：打开一个到 LDAP 服务器的连接，绑定并使用指定的参数进行搜索</li></ul></li><li>对本地系统上的数据库进行操作的几个程序：
<ul><li><b>slapadd</b>：将以 LDAP 目录交换格式（LDIF）指定的条目添加到 LDAP 数据库中</li><li><b>slapcat</b>：打开 LDAP 数据库，并将对应的条目输出为 LDIF 格式</li></ul></li></ul><p>OpenLDAP 的主要服务器配置文件是 /etc/openldap/slapd.conf。本例所使用的完整 slapd.conf 文件如 <a href="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/#listing18">清单 18</a> 所示。slapd.conf 文件中包括一系列全局配置选项，它们作为一个整体应用到 slapd 上面，后面是包含数据库特有信息的数据库后端定义。如果一行内容是以空格开始的，就认为它是上一行的延续。空行和以 “#” 字符开头的注释行都会被忽略。</p><p>如果您正把本文当作练习来做，那就可以按照下面指定的方式进行修改，从而启动 LDAP 服务器。一旦确认服务器正常工作之后，就可以添加复制功能，然后再添加安全性支持。首先是全局配置信息段的设置。其中每个选项的值都是我们想要的。</p><p>正如上面介绍的一样，信息被组织成属性和值的组合，称为条目。条目属性必须遵循的规则是使用 <code>objectclass</code> 专用属性进行组织的，这可以在 /etc/openldap/schema/ 模式文件中找到。对于身份验证来说，需要使用在 nis.schema 中定义的 <code>posixAccount</code> 和 <code>shadowAccount</code> objectclasses：</p><p><code>
include         /etc/openldap/schema/nis.schema
</code></p><p><code>loglevel</code> 行设置的是日志选项。可以将其设置为这样的级别：调试语句和操作统计信息都会被记录到 /var/log/slapd.log 中。日志级别是累加的：296 = 256 日志连接/操作/结果 + 32 搜索过滤器处理 + 8 连接管理：</p><p><code>
loglevel        296
</code></p><p>日志信息会被记录到 syslogd LOG_LOCAL4 机制中。还需要将下面的内容添加到 /etc/syslog.conf 中，并让 syslogd 重新读取自己的配置文件：</p><p><code>
local4.debug   /var/log/slapd.log
</code></p><p>access 行定义了谁可以访问目录中的内容。我们希望用户可以修改自己的密码，并更新自己的 shadow
信息来反映密码的变化。希望身份验证程序能够检索用户的密码。还希望用户能够读取所有其他条目。注意密码条目是不可读的，shadow
属性的惟一用处就是管理密码的过期问题。</p><pre>access to attrs=shadowLastChange,userPassword<br />      by self write<br />      by * auth<br /><br />access to *<br />      by * read<br /></pre><p>接下来，在 database 部分，要定义下面的内容。</p><p>使用新的 bdb 后端数据库：</p><p><code>
database        bdb
</code></p><p>指定后端数据库需要响应的查询的 DN 前缀。为了确保惟一性，根前缀应该从自己的网络域名构建出来。在本例的情况中，它是 .dc=svc,dc=beaverton,dc=ibm,dc=com.，但是在下面的例子中我们对其进行了简化：</p><p><code>
suffix              "dc=ibm,dc=com"
</code></p><p>指定管理 DN，它不用于访问控制或限制数据库的操作。也不需要在目录中为这个 DN 指定一个条目。为具有 rootpw 密码的管理员使用 DN 可以跳过 ACL 规则中的所有访问控制：</p><p><code>
rootdn           "cn=Manager,dc=ibm,dc=com"<br />
rootpw           {MD5}ijFYNcSNctBYg
</code></p><p>这就是我们现在想要设置的选项。稍后将返回 slapd.conf 文件来配置复制，然后在配置安全性。</p><p>现在，我们希望将数据添加到目录中，并确认可以访问这些信息。要实现这种功能，需要配置服务器来使用 ldap 客户机工具，例如
ldapadd 和 ldapsearch。ldap 客户机工具的配置文件是
/etc/openldap/ldap.conf。我们使用的这个文件的完整列表如本文末尾的 <a href="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/#listing19">清单 19</a> 所示。要在 ldap 服务器上运行这些工具，只需要将该行修改成下面的内容：</p><p><code>
BASE dc=ibm,dc=com
</code></p><p>设置启动脚本在级别 2、3 和 5 时启动 LDAP：</p><br /><a name="listing1"><b>清单 1. 设置启动运行级别</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># chkconfig --levels 235 ldap on<br /></pre></td></tr></tbody></table><br /><p>从命令行中启动服务：</p><br /><a name="listing2"><b>清单 2. 启动服务</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># service ldap start<br />Starting slapd:                               [  OK  ]<br /></pre></td></tr></tbody></table><br /><p>OpenLDAP 守护进程 slapd 应该已经运行了：</p><br /><a name="listing3"><b>清单 3. 检查服务正在运行</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># ps -ef | grep slap<br />ldap   13521  1  0 Oct24 ?     00:00:00 /usr/sbin/slapd -u ldap -h ldap:/// ldaps:///<br /></pre></td></tr></tbody></table><br /><p><code>ldapsearch -x</code> 命令应该可以成功完成，但不会返回任何数据。</p><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br /><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br /><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" /><br /></td><td align="right" valign="top"><a href="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/#main" class="fbox"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N101F5"><span class="atitle">迁移密码和 shadow 信息</span></a></p><p>Red Hat 所提供的 openldap-servers 包包含 PADL Software Pty Ltd. 公司的
MigrationTools 工具。我们将使用这些工具将数据从 Linux 系统文件（例如 /etc/group 和
/etc/password）转换成 LDAP LDIF 格式，这是数据库信息的一种文本格式的表示。这种格式是行界定、冒号分隔的属性-值对。</p><p>有一组 Perl 脚本被安装到 /usr/share/openldap/migration/ 中执行迁移。这些 Perl
脚本的配置信息包含在 migrate_common.ph
文件的开头。对于我们的目的来说，只需要修改命名前缀的变量来使用条目的识别名就足够了，如下所示：</p><p><code>
$DEFAULT_BASE = "dc=ibm,dc=com"
</code></p><p>在进行这些修改之后，请运行脚本 migrate_base.pl，它会创建根项，并为 Hosts、Networks、Group 和 People 等创建低一级的组织单元：</p><br /><a name="listing4"><b>清单 4. 运行 migrate_base.pl</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># migrate_base.pl &gt; base.ldif<br /></pre></td></tr></tbody></table><br /><p>编辑 base.ldif，删除除下面之外的所有条目：</p><br /><a name="listing5"><b>清单 5. base.ldif 条目</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># cat base.ldif<br />dn: dc=ibm,dc=com<br />dc: ibm<br />objectClass: top<br />objectClass: domain<br /><br />dn: ou=People,dc=ibm,dc=com<br />ou: People<br />objectClass: top<br />objectClass: organizationalUnit<br /><br />dn: ou=Group,dc=ibm,dc=com<br />ou: Group<br />objectClass: top<br />objectClass: organizationalUnit<br /></pre></td></tr></tbody></table><br /><p>在 LDAP 服务器上，使用 OpenLDAP 客户机工具 ldapadd 将以下条目插入到数据库中。简单身份验证必须要使用 <code>-x</code> 选项指定。在 slapd.conf 中定义的 <code>rootdn</code> 身份验证识别名是 “cn=Manager,dc=ibm,dc=com”。对于简单身份验证来说，必须使用密码。选项 <code>-W</code> 强制提示输入密码。这个密码就是在 slapd.conf 文件中指定的 <code>rootpw</code> 参数的值。包含这些条目的 LDIF 文件是使用 <code>-f</code> 选项指定的：</p><br /><a name="listing6"><b>清单 6. 使用 ldapadd 插入条目</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># ldapadd -x -D "cn=Manager,dc=ibm,dc=com" -W -f base.ldif<br /></pre></td></tr></tbody></table><br /><p>接下来，从 /etc/group 中迁移 ldapuser 组：</p><br /><a name="listing7"><b>清单 7. 迁移 ldapuser 组</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># grep ldapuser /etc/group &gt; group.in<br /># ./migrate_group.pl group.in &gt; group.ldif<br /><br />#  cat group.ldif<br />dn: cn=ldapuser,ou=Group,dc=ibm,dc=com<br />objectClass: posixGroup<br />objectClass: top<br />cn: ldapuser<br />userPassword: {crypt}x<br />gidNumber: 500<br /><br /># ldapadd -x -D "cn=Manager,dc=ibm,dc=com" -W -f group.ldif<br /></pre></td></tr></tbody></table><br /><p>最后，从 /etc/passwd 和 /etc/shadow 中迁移 ldapuser 的信息：</p><br /><a name="listing8"><b>清单 8. 迁移 ldapuser 信息</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># grep ldapuser /etc/passwd &gt; passwd.in<br /># ./migrate_passwd.pl passwd.in &gt; passwd.ldif<br /><br /># cat passwd.ldif<br />dn: uid=ldapuser,ou=People,dc=ibm,dc=com<br />uid: ldapuser<br />cn: ldapuser<br />objectClass: account<br />objectClass: posixAccount<br />objectClass: top<br />objectClass: shadowAccount<br />userPassword: {crypt$1$TeOlOcMc$cpQaa0WpLSFRC1HIHW5bt1<br />shadowLastChange: 13048<br />shadowMax: 99999<br />shadowWarning: 7<br />loginShell: /bin/bash<br />uidNumber: 500<br />gidNumber: 500<br />homeDirectory: /home/ldapuser<br />gecos: ldapuser<br /><br /># ldapadd -x -D "cn=Manager,dc=ibm,dc=com" -W -f passwd.ldif<br /></pre></td></tr></tbody></table><br /><p>现在检查已经添加到数据库中的信息。清单 9 给出了全部输出结果：</p><br /><a name="listing9"><b>清单 9. 以 LDIF 格式填充的 OpenLDAP 数据库</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># ldapsearch -x<br /><br /># extended LDIF<br />#<br /># LDAPv3<br /># base &lt;&gt; with scope sub<br /># filter: (objectclass=*)<br /># requesting: ALL<br />#<br /><br /># ibm.com<br />dn: dc=ibm,dc=com<br />dc: ibm<br />objectClass: top<br />objectClass: domain<br /><br /># People, ibm.com<br />dn: ou=People,dc=ibm,dc=com<br />ou: People<br />objectClass: top<br />objectClass: organizationalUnit<br /><br /># Group, ibm.com<br />dn: ou=Group,dc=ibm,dc=com<br />ou: Group<br />objectClass: top<br />objectClass: organizationalUnit<br /><br /># ldapuser, Group, ibm.com<br />dn: cn=ldapuser,ou=Group,dc=ibm,dc=com<br />objectClass: posixGroup<br />objectClass: top<br />cn: ldapuser<br />gidNumber: 500<br /><br /># ldapuser, People, ibm.com<br />dn: uid=ldapuser,ou=People,dc=ibm,dc=com<br />uid: ldapuser<br />cn: ldapuser<br />objectClass: account<br />objectClass: posixAccount<br />objectClass: top<br />objectClass: shadowAccount<br />shadowMax: 99999<br />shadowWarning: 7<br />loginShell: /bin/bash<br />uidNumber: 500<br />gidNumber: 500<br />homeDirectory: /home/ldapuser<br />gecos: test2<br /><br /># search result<br />search: 2<br />result: 0 Success<br /><br /># numResponses: 6<br /># numEntries: 5<br /></pre></td></tr></tbody></table><br /><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br /><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br /><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" /><br /></td><td align="right" valign="top"><a href="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/#main" class="fbox"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N10281"><span class="atitle">配置 LDAP 客户机</span></a></p><p>用来设置客户机的 Red Hat Enterprise Linux release 4 Update 1 包包括：</p><ul><li><b>nss_ldap-226-6</b>：包括两个 LDAP 访问客户机：nss_ldap 和 pam_ldap
<ul><li><b>nss_ldap</b> 是一组 C 库扩展，它允许 LDAP 目录服务器用作一个用户和组信息的主源</li><li><b>pam_ldap</b> 是一个 Linux-PAM 模块，它支持身份验证功能</li></ul></li></ul><p>LDAP 身份验证要想正确地工作，需要配置两个服务：系统命名服务和身份验证服务。</p><p>系统命名服务（NSS）需要配置为使用 LDAP 来解析诸如用户和组帐号之类的资源。例如，在运行命令 <code>ls -l</code> 时，如果某个文件 inode 给出文件的所有者是 “user 501”，那么命名服务就需要将 “uid 501” 解析成用户名，并在 <code>ls</code>
命令输出结果中输出。通常来说，这是通过查找 /etc/passwd 文件中的所有用户帐号实现的。由于用户现在都存储在 LDAP
目录中，因此系统需要配置成同时对 passwd 文件和 LDAP 目录中的帐号进行解析。这种功能是通过
/usr/lib/libnss_ldap.so 库提供的。</p><p>身份验证服务是实际向 LDAP 验证用户身份的服务。可插入身份验证模块（PAM）提供了本地 Linux 身份验证服务。下面我们将配置
PAM 先对本地的 /etc/passwd 文件检查用户帐号，然后再对 LDAP 服务器进行检查。PAM LDAP
模块可以用来将身份验证重定向到 LDAP 目录上。/lib/security/pam_ldap.so PAM 模块提供了 LDAP
身份验证功能。</p><p>身份验证本身是由 PAM 程序执行的，它从身份验证候选机制中获取用户名，将其绑定到 OpenLDAP 服务器上，检索与这个 uid
条目（用户名条目）相关的 DN；从身份验证候选机制中获取密码，然后使用这个 DN 和密码试图将其绑定到 OpenLDAP
服务器上。如果绑定成功，PAM 会报告说这个用户已经成功通过了 pam_ldap.so 提供的身份验证测试。根据 PAM
的配置不同，在用户看到命令行提示符之前可能会执行其他测试。</p><p>我们可以采用两种方法来配置 LDAP 客户机。一种快速而简单的方法是运行
/usr/sbin/authconfig，并在两个屏幕中输入信息。另外一种方法是通过编辑客户机 LDAP 配置文件
/etc/ldap.conf，然后修改 /etc/nsswitch.conf、/etc/sysconfig/authconfig 和
/etc/pam.d/system-auth。首先让我们来看一下如何运行 authconfig。</p><p>如图 3 所示进行选择，然后点击 <b>Next</b>。</p><br /><a name="figure3"><b>图 3. 执行 authconfig 命令的第一个页面</b></a><br /><img alt="执行 authconfig 命令的第一个页面" src="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/figure3.jpg" height="398" width="572" /><br /><p>在如图 4 所示的第二个屏幕中输入对应的信息，然后点击 <b>OK</b>。</p><br /><a name="figure4"><b>图 4. 执行 authconfig 命令的第二个页面</b></a><br /><img alt="执行 authconfig 命令的第二个页面" src="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/figure4.jpg" height="398" width="572" /><br /><p>要手工配置 OpenLDAP 客户机，请遵循下面的步骤。</p><p>用来跟踪特定身份验证机制是否已经启用的文件是 /etc/sysconfig/。我们可以希望以下条目的值都是 “yes”：</p><p><code>
USELDAP=yes<br />
USELDAPAUTH=yes<br />
USEMD5=yes<br />
USESHADOW=yes<br />
USELOCAUTHORIZE=yes
</code></p><p>PAM 和 NSS 模块使用的基本配置文件是 /etc/ldap.conf。host 选项指定 LDAP 服务器，base 选项指定这个目录使用的 DN，最初我们希望关闭加密功能：</p><p><code>
host dhcp64-233.ibm.com<br />
base dc=ibm,dc=com<br />
ssl off
</code></p><p>要让 NSS 服务使用 OpenLDAP 服务器，需要将 “ldap” 添加到 /etc/nsswitch.conf 文件的 passwd、shadow 和 group 行中，如下所示： </p><p><code>
passwd:     files ldap<br />
shadow:     files ldap<br />
group:      files ldap
</code></p><p>要让 PAM 身份验证服务使用 OpenLDAP 服务器，请将 pam_ldap 行加入到 /etc/pam.d/system-auth 中，位置在对应的标准 pam_unix.so 条目之后。尽管其他设置也可以实现相同的结果，但是我使用下面的文件设置：</p><p><code>
auth        required      /lib/security/$ISA/pam_env.so<br />
auth        sufficient    /lib/security/$ISA/pam_unix.so likeauth nullok<br />
auth        sufficient    /lib/security/$ISA/pam_ldap.so use_first_pass<br />
auth        required      /lib/security/$ISA/pam_deny.so<br /><br />
account     required      /lib/security/$ISA/pam_unix.so broken_shadow<br />
account     sufficient    /lib/security/$ISA/pam_localuser.so<br />
account     sufficient    /lib/security/$ISA/pam_succeed_if.so uid %lt; 100 quiet<br />
account     [default=bad success=ok user_unknown=ignore] /lib/security/$ISA/pam_ldap.so<br />
account     required      /lib/security/$ISA/pam_permit.so<br /><br />
password    requisite     /lib/security/$ISA/pam_cracklib.so retry=3<br />
password    sufficient    /lib/security/$ISA/pam_unix.so nullok use_authtok md5 shadow<br />
password    sufficient    /lib/security/$ISA/pam_ldap.so use_authtok<br />
password    required      /lib/security/$ISA/pam_deny.so<br /><br />
session     required      /lib/security/$ISA/pam_limits.so<br />
session     required      /lib/security/$ISA/pam_unix.so<br />
session     optional      /lib/security/$ISA/pam_ldap.so
</code></p><p>现在，用户帐号信息可以从客户机系统中删除并从 LDAP 目录中进行获取了。当用户试图登录客户机系统时，PAM 身份验证服务就会从用户那里获取用户名，在我们的例子中是 <code>ldapuser</code>。PAM 会从 LDAP 服务器中检索识别名（DN）条目 <code>.dn: uid=ldapuser, ou=People, dc=ibm, dc=com.</code>。PAM
然后会从用户那里获取密码。然后 PAM 试图使用这个 DN 和密码与 LDAP 服务器进行绑定。DN 和密码都以正文文本的格式发送给 LDAP
服务器。在对密码进行散列操作之后，如果服务器可以让用户登录，就会向 PAM 报告说已经成功进行了绑定。成功绑定可以完全满足 PAM 对
pam_ldap 模块汇报成功的标准，如果所有其他 PAM 标准都已经满足了，那么就允许用户登录到系统中。</p><p>当 LDAP 服务器对身份验证进行处理时，需要解决另外两个问题才能满足提供可靠安全的身份验证的目标。现在，任何客户机系统不能成功地与
LDAP 服务器进行通信都会阻止用户登录客户机系统。在下一节中我们将看到如何消除这种单点故障，这将显示客户机如何从备份服务器上访问 LDAP
目录。由于用户密码是在网络上以正文文本格式传输的，因此这并不能满足安全身份验证的需求。<a href="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/#configtls">配置 TLS 安全性</a> 将解决这个问题。</p><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br /><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br /><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" /><br /></td><td align="right" valign="top"><a href="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/#main" class="fbox"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N1034A"><span class="atitle">配置复制</span></a></p><p>为了防止出现客户机由于 LDAP 服务器的问题而不能登录的情况，我们需要采用复制技术来实现可靠性目标。复制是通过 OpenLDAP
复制进程 slurpd
提供的，它会周期性地唤醒，并检查主服务器上的日志文件，从而确定是否有任何更新。这些更新然后会传播到从服务器上。读请求可以由任何一个服务器进行解
析，而更新请求则只能由主服务器进行解析。客户机需要负责在推荐地址上重试更新操作。</p><p>要配置复制，需要停止 OpenLDAP 服务器的 slapd 守护进程：</p><br /><a name="listing10"><b>清单 10. 停止服务</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># service ldap stop<br /></pre></td></tr></tbody></table><br /><p>将以下内容添加到服务器的 /etc/openldap/slapd.conf 文件中，从而启用对新从服务器的复制。<code>replogfile</code> 行的内容指定类 LDIF 变化应该写入的文件。<code>replica</code> 原语定义了变化应该传播到的主机：</p><pre>#Replicas of this database<br />replogfile /var/lib/ldap/replog<br />replica host=dhcp64-253.ibm.com:389<br />        binddn="cn=Manager,dc=ibm,dc=com"<br />        credentials=secret<br />        bindmethod=simple<br /></pre><p>在运行从 OpenLDAP 服务器的系统上，请遵循 <a href="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/#configserver">配置 LDAP 服务器</a> 一节给出的步骤。然后通过将信息导出到一个 ldif 文件中并将其添加到从服务器数据库上，从而将数据库从主服务器拷贝到复制服务器上。</p><p>在主服务器上：</p><br /><a name="listing11"><b>清单 11. 将数据导出到 LDIF 文件中</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># ldapsearch -x &gt; database.ldif<br /></pre></td></tr></tbody></table><br /><p>在复制服务器上：</p><br /><a name="listing12"><b>清单 12. 将数据添加到从服务器数据库中</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># ldapadd -x -D "cn=Manager,dc=ibm,dc=com" -W -f database.ldif<br /></pre></td></tr></tbody></table><br /><p>将以下内容添加到复制服务器的 /etc/openldap/slapd.conf 文件中。<code>updatedn</code> 指定了在更新从目录时主 slurpd 守护进程使用的 DN。<code>updateref</code> 指定的是主目录服务器。当一个 LDAP 客户机请求从服务器进行更新时，从服务器就将客户机重定向到这个主服务器上。</p><p><code>
updatedn  "cn=Manager,dc=ibm,dc=com"<br />
updateref ldap://dhcp64-233.ibm.com:389/
</code></p><p>启动复制 OpenLDAP 服务器，当它运行之后，再启动主 OpenLDAP 服务器。在主服务器上，slapd 和 slurpd 都会启动。</p><p>现在，可以让 OpenLDAP 客户机除了主服务器之外还可以使用复制服务器，这可以通过运行 authconfig 并将复制主机名添加到第二个屏幕中的 Server 行中实现，也可以通过在 /etc/ldap.conf 中修改 host 实现：</p><p><code>
host dhcp64-253.ibm.com dhcp64-233.ibm.com
</code></p><p>为了确认复制可以正常工作，需要研究一下在更新 <code>gecos</code> 属性时到底发生了什么。复制日志使用了与 LDIF
类似的格式。在读取 replogfile 之后，slurpd 会将这个条目拷贝到自己的重做日志中。实际的变化都以 LDIF 格式保存在主
LDAP 服务器上 /var/lib/ldap/replica/ 中的 slurpd.replog 文件中。</p><p>使用文件 user_mod 中的变化，客户机程序 ldapmodify 应用这些变化：</p><br /><a name="listing13"><b>清单 13. 应用 user_mod 的变化</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># cat user_mod<br />dn: uid=ldapuser,ou=People,dc=ibm,dc=com<br />changetype: modify<br />replace: gecos<br />gecos: test2<br /><br /># tail -f /var/lib/ldap/replog &amp;<br /><br /># ldapmodify -x -r -f /home/ldapuser/user_mod -D'cn=Manager,dc=ibm,dc=com' -W<br />Enter LDAP Password:<br />modifying entry "uid=ldapuser,ou=People,dc=ibm,dc=com"<br /><br />replica: dhcp64-253.ibm.com:389<br />time: 1130111686<br />dn: uid=ldapuser,ou=People,dc=ibm,dc=com<br />changetype: modify<br />replace: gecos<br />gecos: test2<br />-<br />replace: entryCSN<br />entryCSN: 20051023235446Z#000001#00#000000<br />-<br />replace: modifiersName<br />modifiersName: cn=Manager,dc=ibm,dc=com<br />-<br />replace: modifyTimestamp<br />modifyTimestamp: 20051023235446Z<br />-<br /></pre></td></tr></tbody></table><br /><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br /><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br /><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" /><br /></td><td align="right" valign="top"><a href="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/#main" class="fbox"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="configtls"><span class="atitle">配置 TLS 安全性</span></a></p><p>LDAP 是以明文的格式通过网络来发送所有信息的，包括密码。我们将采用 TLS 所提供的加密机制（SSL 的后继者）来解决这个问题。在传输层，数据使用 TLS 协议进行加密和封装，然后通过网络进行传输。用来配置加密的工具都是由 OpenSSL 包提供的。</p><p>虽然加密是一个复杂的主题，但是要使用 OpenSSL 包，我们依然需要简要介绍一下 TLS
是如何工作的。数据块使用一个对称密钥算法进行加密，它使用一个密钥来实现对数据的加密和解密。我们还有一个问题：如何防止出现以正文文本格式将密钥从
LDAP 服务器发送到 LDAP
客户机上的情况。我们使用公钥算法来解决这个问题，其中客户机可以使用一个自由获取的公钥对自己的密钥进行加密，而只有服务器才可以对这个密钥进行解密。</p><p>公钥是作为证书的一部分来创建和分发的，其中包含了一些支持信息，例如 ID、过期日期、提供这个证书的 LDAP
服务器的完整域名（FQDN）。在 LDAP
客户机使用证书进行加密之前，它会验证自己正在与之进行交谈的服务器拥有这个证书，这是通过加密一个挑战并验证服务器可以对其进行解密实现的。</p><p>要验证发行这个证书的服务器是一个已经批准过的 LDAP 服务器，客户机被配置为只接受本地证书机构（CA）所签署的证书。它使用 CA 所生成的证书中的公钥，这个公钥保存到客户机中以验证这个 LDAP 所产生的证书是有效的。</p><p>在这个例子中，我们将自己的 LDAP 服务器设置为证书机构，并创建一个自签署的证书供 LDAP 客户机和服务器在加密信息中使用。</p><p>用来构建 TLS 服务器的 Red Hat Enterprise Linux release 4 Update 1 包是：</p><ul><li><b>openssl-0.9.7a-43.1</b>：包括一个证书管理工具和提供各种加密算法和协议的共享库</li></ul><p>要构建证书机构的工作环境并生成自己的自签署证书，需要运行 /usr/share/ssl/misc/CA shell 脚本，这是一个对 <code>openssl</code> 命令的封装程序。私密性增强邮件（PEM）是一种用来对数据进行加密和编码的格式：</p><br /><a name="listing14"><b>清单 14. 运行 CA shell 脚本</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># cd /usr/share/ssl/misc<br /># ./CA -newca<br />CA certificate filename (or enter to create)<br /><br />Making CA certificate ...<br />Generating a 1024 bit RSA private key<br />.........++++++<br />......++++++<br />writing new private key to './demoCA/private/./cakey.pem'<br />Enter PEM pass phrase:<br />Verifying - Enter PEM pass phrase:<br />Enter PEM pass phrase:<br />Verifying - Enter PEM pass phrase:<br />-----<br />You are about to be asked to enter information that will be incorporated into<br />your certificate request.<br />What you are about to enter is what is called a Distinguished Name or a DN.<br />There are quite a few fields but you can leave some blank<br />For some fields there will be a default value,<br />If you enter '.', the field will be left blank.<br />-----<br />Country Name (2 letter code) [GB]:US<br />State or Province Name (full name) [Berkshire]:Oregon<br />Locality Name (eg, city) [Newbury]:Beaverton<br />Organization Name (eg, company) [My Company Ltd]:IBM<br />Organizational Unit Name (eg, section) []:its<br />Common Name (eg, your name or your server's hostname) []:dhcp64-233.ibm.com<br />Email Address []:root@dhcp64-233.ibm.com<br /></pre></td></tr></tbody></table><br /><p>接下来，要生成由证书机构进行签署的服务器证书。其余的步骤只会对主 LDAP 服务器执行一次，此时指定的是 <code>CN=dhcp64-233.ibm.com</code>；然后对从服务器执行一次，此时指定的是 <code>CN=dhcp64-253.ibm.com</code>。还要使用 <code>nodes</code> 选项，这样就不用在每次启动 OpenLDAP 服务器守护进程 slapd 时都需要输入密码了。签署后的公钥被嵌入到证书请求 slapd-req.pem 中，与之匹配的私钥嵌入在 slapd-key.pem 中：</p><br /><a name="listing15"><b>清单 15. 生成服务器证书</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># openssl req -new -nodes -subj<br />   '/CN=dhcp64-233.ibm.com/O=IBM/C=US/ST=Oregon/L=Beaverton'<br />   -keyout slapd-key.pem -out slapd-req.pem -days 365<br />Generating a 1024 bit RSA private key<br />...............++++++<br />.....................................++++++<br />writing new private key to 'slapd-key.pem'<br />-----<br /></pre></td></tr></tbody></table><br /><p>使用在第一个步骤中创建的 CA 证书对这个证书进行签署：</p><br /><a name="listing16"><b>清单 16. 对证书进行签署</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># openssl ca -out slapd-cert.pem -infiles slapd-req.pem<br />Using configuration from /usr/share/ssl/openssl.cnf<br />Enter pass phrase for ./demoCA/private/cakey.pem:<br />Check that the request matches the signature<br />Signature ok<br />Certificate Details:<br />        Serial Number: 1 (0x1)<br />        Validity<br />            Not Before: Oct 25 02:50:05 2005 GMT<br />            Not After : Oct 25 02:50:05 2006 GMT<br />        Subject:<br />            countryName               = US<br />            stateOrProvinceName       = Oregon<br />            organizationName          = IBM<br />            commonName                = dhcp64-233.ibm.com<br />        X509v3 extensions:<br />            X509v3 Basic Constraints:<br />            CA:FALSE<br />            Netscape Comment:<br />            OpenSSL Generated Certificate<br />            X509v3 Subject Key Identifier:<br />            11:A2:FB:59:42:A4:B3:26:73:1D:6D:F5:4D:2F:80:F0:FA:10:38:F5<br />            X509v3 Authority Key Identifier:<br />            keyid:F7:6A:25:F5:76:BE:20:E7:8D:0F:51:EF:D8:86:7B:AF:2C:74:2F:80<br />            DirName:/C=US/ST=Oregon/L=Beaverton/O=IBM/OU=its/CN=dhcp64-233.ibm.com<br />/emailAddress=root@dhcp64-233.ibm.com<br />            serial:00<br /><br />Certificate is to be certified until Oct 25 02:50:05 2006 GMT (365 days)<br />Sign the certificate? [y/n]:y<br /><br />1 out of 1 certificate requests certified, commit? [y/n]y<br />Write out database with 1 new entries<br />Data Base Updated<br /></pre></td></tr></tbody></table><br /><p>下一个步骤将所有需要的证书拷贝到 slapd 可以找到的地方。另外，还要对每个文件强制采用正确的权限：</p><br /><a name="listing17"><b>清单 17. 拷贝证书并强制设置权限</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section"># cp -p slapd-key.pem /etc/openldap/slapdkey.pem<br /># cp -p slapd-cert.pem /etc/openldap/slapdcert.pem<br /># chown ldap:ldap /etc/openldap/slapdcert.pem<br /># chmod 644 /etc/openldap/slapdcert.pem<br /># chown ldap:ldap /etc/openldap/slapdkey.pem<br /># chmod 400 /etc/openldap/slapdkey.pem<br /><br /># mkdir /etc/openldap/cacerts/<br /># cp /usr/share/ssl/misc/demoCA/cacert.pem /etc/openldap/cacerts/cacert.pem<br /># chown ldap:ldap /etc/openldap/cacerts cacert.pem<br /># chmod 644 /etc/openldap/cacerts cacert.pem<br /></pre></td></tr></tbody></table><br /><p>在 OpenLDAP 服务器上，将以下内容添加到 /etc/openldap/slapd.conf 文件的 <code>global</code> 段下面。<code>TLSCertificateFile</code> 和 <code>TLSCertificateKeyFile</code> 指定了证书文件和私钥文件的路径。<code>TLSCipherSuite</code> 指定了一个 OpenSSL 密码的列表，slapd 在与 TLS 协商建立连接时可以从中按照降序顺序依次选择。<code>HIGH</code> 的意思是 “所有密钥的长度都大于 128 位”；<code>MEDIUM</code> 表示 “所有密钥的长度都等于 128 位”；<code>+SSLv2</code> 表示 “不管密钥强度如何，所有密码都是以 SSL 协议版本 2 的形式指定的”。</p><p><code>
TLSCipherSuite  HIGH:MEDIUM:+SSLv2<br />
TLSCACertificateFile    /etc/openldap/cacerts/cacert.pem<br />
TLSCertificateFile      /etc/openldap/slapdcert.pem<br />
TLSCertificateKeyFile   /etc/openldap/slapdkey.pem
</code></p><p>将以下内容添加到 LDAP 服务器的第二个配置文件 /etc/openldap/ldap.conf 中：</p><p><code>
TLS_CACERTDIR /etc/openldap/cacerts<br />
TLS_REQCERT allow
</code></p><p>
为了允许从 OpenLDAP 客户机上使用安全连接，需要将以下内容添加到 /etc/openldap/ldap.conf 文件中：</p><p><code>
ssl start_tls<br />
tls_checkpeer yes<br />
tls_cacertfile /etc/openldap/cacerts/cacert.pem
</code></p><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br /><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br /><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" /><br /></td><td align="right" valign="top"><a href="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/#main" class="fbox"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N104A2"><span class="atitle">结束语</span></a></p><p>按照本文给出的提示，我们现在已经使用轻量级目录访问协议（LDAP）构建了一个集中的身份验证系统。我们最初是通过配置 LDAP
服务器来响应对 “dc=ibm,dc=com” 的基本请求开始入手的。我们使用了一组 Perl 脚本来将用户帐号信息迁移到 LDAP
目录中。我们对 Linux 用户帐号服务、PAM 和 NSS 服务进行了修改，从而可以从 LDAP 服务器中检索用户信息。还设置了一个
LDAP 服务器副本作为备用服务器来响应客户机的请求。然后，使用 TLS 协议在 LDAP 客户机和服务器之间对通信进行安全加密。恭喜！</p><p>为了参考方便，下面给出了本文中使用的配置文件的完整清单。</p><br /><a name="listing18"><b>清单 18. 本文例子中使用的服务器 /etc/openldap/slapd.conf 文件</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section">#<br /># See slapd.conf (5) for details on configuration options.<br />#<br />include         /etc/openldap/schema/core.schema<br />include         /etc/openldap/schema/cosine.schema<br />include         /etc/openldap/schema/inetorgperson.schema<br />include         /etc/openldap/schema/nis.schema<br /><br />loglevel        256<br />pidfile         /var/run/slapd.pid<br />argsfile        /var/run/slapd.args<br /><br /># The next three lines allow use of TLS for encrypting connections.<br />TLSCipherSuite  HIGH:MEDIUM:+SSLv2<br />TLSCACertificateFile    /etc/openldap/cacerts/cacert.pem<br />TLSCertificateFile      /etc/openldap/slapdcert.pem<br />TLSCertificateKeyFile   /etc/openldap/slapdkey.pem<br /><br /># access control policy:<br /># Restrict password access to change by owner and authentication.<br /># Allow read access by everyone to all other attributes.<br /><br />access to attrs=shadowLastChange,userPassword<br />   by self write<br />   by * auth<br /><br />access to *<br />   by * read<br /><br />#######################################################################<br /># database definition<br />#######################################################################<br /><br />database        bdb<br />suffix          "dc=ibm,dc=com"<br /><br />rootdn          "cn=Manager,dc=ibm,dc=com"<br />rootpw          {MD5}ijFYNcSNctBYg<br /><br />directory       /var/lib/ldap<br /><br /># Indices to maintain for this database<br />index objectClass                       eq,pres<br />index ou,cn,mail,surname,givenname      eq,pres,sub<br />index uidNumber,gidNumber,loginShell    eq,pres<br />index uid,memberUid                     eq,pres,sub<br />index nisMapName,nisMapEntry            eq,pres,sub<br /><br />#Replicas of this database<br />replica host=dhcp64-253.ibm.com:389<br />        binddn="cn=Manager,dc=ibm,dc=com"<br />        credentials=secret<br />        bindmethod=simple<br />replogfile /var/lib/ldap/replog<br /></pre></td></tr></tbody></table><br /><br /><a name="listing19"><b>清单 19. 本文例子中使用的服务器 /etc/openldap/ldap.conf 文件</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section">#<br /># LDAP Defaults<br />#<br /><br /># See ldap.conf(5) for details<br /><br />HOST 127.0.0.1<br />BASE dc=ibm,dc=com<br /><br />TLS_CACERTDIR /etc/openldap/cacerts<br />TLS_REQCERT allow<br /></pre></td></tr></tbody></table><br /><br /><a name="listing20"><b>清单 20. 本文例子中使用的客户机 /etc/ldap.conf 文件</b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><code></code><pre class="section">a<br /># @(#)$Id: ldap.conf,v 1.34 2004/09/16 23:32:02 lukeh Exp $<br />#<br /># This is the configuration file for the LDAP nameservice<br /># switch library and the LDAP PAM module.<br />#<br /># PADL Software<br /># http://www.padl.com<br />#<br /><br /># Your LDAP server.<br /># Multiple hosts may be specified, each separated by a<br /># space.<br /><br />host dhcp64-233.ibm.com dhcp64-233.ibm.com<br /><br /># The distinguished name of the search base.<br /><br />base dc=ibm,dc=com<br /><br /># OpenLDAP SSL mechanism, start_tls mechanism uses the normal LDAP port 389<br />ssl start_tls<br /><br />#Require and verify server certificate<br />tls_checkpeer yes<br /><br /># CA certificates for server certificate verification<br />tls_cacertfile /etc/openldap/cacerts/cacert.pem<br /><br />pam_password md5<br /></pre></td></tr></tbody></table><br /><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br /><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br /><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" /><br /></td><td align="right" valign="top"><a href="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/#main" class="fbox"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="resources"><span class="atitle">参考资料 </span></a></p><b>学习</b><br /><ul><li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/linux/library/l-openldap/?S_TACT=105AGX52&amp;S_CMP=cn-a-l" target="_blank">英文原文</a> 。<br /><br /></li><li><a href="http://www.openldap.org/">OpenLDAP 主页</a> 是 OpenLDAP 项目的主页。其中包含了有关如何配置 OpenLDAP 的丰富信息，以及将来的路线图和版本信息。请确保阅读 <a href="http://www.openldap.org/doc/admin23/">OpenLDAP Software 2.3 Administrator's Guide</a>。
<br /><br /></li><li>
在 <a href="http://www.openssl.org/">OpenSSL Project</a> 中，可以找到有关 SSL 和 TLS 的信息。
<br /><br /></li><li>
在 <a href="http://www.linux.com/howtos/LDAP-HOWTO/index.shtml">LDAP Linux HOWTO</a> 中，我们可以找到有关在 Linux 机器上安装、配置、运行和维护 LDAP（Lightweight Directory Access Protocol）服务器的详细信息。请在 <a href="http://www.linux.com/howtos/LDAP-Implementation-HOWTO/index.shtml">LDAP Implementation HOWTO</a> 中阅读使用 pam_ldap 和 nss_ldap 进行 LDAP 身份验证的讨论。
<br /><br /></li><li><a href="http://www.padl.com/">PADL 主页</a> 提供了 Perl 迁移脚本 nss_ldap 和 pam_ldap 以及很多其他有用的 LDAP 工具。
<br /><br /></li><li>
在 <a href="http://www.ibm.com/developerworks/cn/linux/">developerWorks Linux 专区</a> 中可以找到为 Linux 开发人员准备的更多资源。
<br /><br /></li><li>
随时关注 <a href="http://www.ibm.com/developerworks/offers/techbriefings/?S_TACT=105AGX52&amp;S_CMP=cn-a-l">developerWorks 技术活动和网络广播</a>。
</li></ul><br /><b>获得产品和技术</b><br /><ul><li><a href="http://www.ibm.com/developerworks/offers/sek/?S_TACT=105AGX52&amp;S_CMP=cn-a-l">索取免费的 SEK for Linux</a>，这有两张 DVD，包括最新的 IBM for Linux 的试用版软件，包括 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere®。
<br /><br /></li><li>

在您的下一个开发项目中采用 <a href="http://www.ibm.com/developerworks/downloads/?S_TACT=105AGX52&amp;S_CMP=cn-a-l">IBM 试用版软件</a>，这可以从 developerWorks 上直接下载。
<br /><br /></li></ul><br /><b>讨论</b><br /><ul><li><a href="http://www.openldap.org/lists/">OpenLDAP 邮件列表</a> 是讨论 OpenLDAP 的主要论坛。
<br /><br /></li><li>
通过参与 <a href="http://www.ibm.com/developerworks/blogs/?S_TACT=105AGX52&amp;S_CMP=cn-a-l">developerWorks blogs</a> 加入  developerWorks 社区。
<br /><br /></li></ul><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br /><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br /><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" /><br /></td><td align="right" valign="top"><a href="http://www-128.ibm.com/developerworks/cn/linux/l-openldap/#main" class="fbox"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="author"><span class="atitle">关于作者</span></a></p><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td colspan="3"><img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="100%" /></td></tr><tr align="left" valign="top"><td><p><img alt="Mike O'Reilly" src="http://www.ibm.com/developerworks/i/p-moreilly.jpg" align="left" border="0" height="80" width="64" /></p></td><td><img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="4" /></td><td width="100%"><p>Mike O'Reilly 是 IBM Linux 和 VMware ESX 产品支持小组的一员，他为 Linux 产品提供支持已经有 5 年的时间了。另外，他支持 VMware 超</p></td></tr></tbody></table><br /><img src ="http://www.blogjava.net/alex/aggbug/62714.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-10 09:19 <a href="http://www.blogjava.net/alex/archive/2006/08/10/62714.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]bash编程教学实例</title><link>http://www.blogjava.net/alex/archive/2006/06/16/53293.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Fri, 16 Jun 2006 06:20:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/06/16/53293.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/53293.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/06/16/53293.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/53293.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/53293.html</trackback:ping><description><![CDATA[key words: bash编程 <br /><br />转自 <a href="http://www.gd-linux.org/bbs/archive/index.php/t-126.html">这里</a><br /><br />另一篇 <a href="http://www.linuxsir.org/main/?q=node/134">详解Bash命令行处理</a><br /><br />bash编程教学实例<br /><br />
bash编程<br /><br />
--------------------------------------------------------------------------------<br />
時間：2004/03/02　　　　來源：不详<br /><br />
　　Shell Script(bash)简介<br /><br />
　　众所皆知地，UNIX上以小工具著名，利用许多简单的小工具，来完成原本需要大量软体开发的工作，这一点特色，使得UNIX成为许多人心目中理想的系统平台。　<br />
　　在众多的小工具中，Shell Script算得上是最基本、最强大、运用最广泛的一个。它运用围之广，不但从系统启动、程式编译、定期作业、上网连线，甚至安装整个Linux系统，都可以用它来完成。　<br /><br />
　　因为Shell
Script是利用您平日在使用的一些指令，将之组合起来，成为一个"程式"。如果您平日某些序列的指令下得特别频繁，便可以将这些指令组合起来，成为另
一个新的指令。这样，不但可以简化并加速操作速度，甚至还可以干脆自动定期执行，大大简化系统管理工作。　<br /><br />
　　*************************<br />
　　Bash(GNU Bourne-Again
SHell)是许多Linux平台的内定Shell，事实上，还有许多传统UNIX上用的Shell，像tcsh、csh、ash、bsh、ksh等等，
Shell Script大致都类同，当您学会一种Shell以后，其它的Shell会很快就上手，大多数的时候，一个Shell
Script通常可以在很多种Shell上使用。　<br />
　　这里我介绍您bash的使用方法。事实上，当您"man
bash"时，就可以看到bash的说明书，不过对许多人来说，这份说明书犹如"无字天书"一样难懂。这份文件，主要资料来源为"man
bash"，我加上一些实际日常的应用例来说明。希望这样能让那些始终不得其门而入的人们，多多少少能有点概念。　<br /><br /><br />
　　教学例子<br /><br />
　　"Hello world" Shell Script　<br />
　　照传统程式教学例，这一节介绍Shell Script的"Hello World"如何撰写。　<br /><br />
　　*************************<br /><br />
　　#!/bin/sh　<br />
　　# Filename : hello　<br />
　　echo "Hello world!"　<br /><br />
　　*************************<br /><br />
　　大家应该会注意到第一行的"#!/bin/sh"。在UNIX下，所有的可执行Script，不管是那一种语言，其开头都是"#!"，例如Perl是
"#!/usr/bin/perl"，tcl/tk是"#!/usr/bin/wish"，看您要执行的Script程式位置在那里。您也可以用"#!
/bin/bash"、"#!/bin/tcsh"等等，来指定使用特定的Shell。　<br />
　　echo是个bash的内建指令。　<br /><br />
　　*************************<br /><br />
　　接下来，执行hello这个script:　<br />
　　要执行一个Script的方式有很多种。　<br /><br />
　　*************************<br /><br />
　　第一种 : 将hello这个档案的权限设定为可执行。　<br />
　　[foxman@foxman bash]# chmod 755 hello　<br />
　　执行　<br />
　　[foxman@foxman bash]# ./hello　<br />
　　hello world　<br /><br />
　　*************************<br /><br />
　　第二种 : 使用bash内建指令"source"或"."。　<br />
　　[foxman@foxman bash]# source hello　<br />
　　hello world　<br />
　　或　<br />
　　[foxman@foxman bash]# . hello　<br />
　　hello world　<br /><br />
　　*************************<br /><br />
　　第三种 : 直接使用sh/bash/tcsh指令来执行。　<br />
　　[foxman@foxman bash]# sh hello　<br />
　　hello world　<br />
　　或　<br />
　　[foxman@foxman bash]# bash hello　<br />
　　hello world　<br /><br />
　　*************************<br /><br />
　　Bash执行选项　<br /><br />
　　*************************<br /><br />
　　-c string : 读取string来当命令。　<br />
　　-i : 互动介面。　<br />
　　-s : 由stdin读取命令。　<br />
　　- : 取消往后选项的读取。　<br />
　　-norc : 不要读~/.bashrc来执行。　<br />
　　-noprofile : 不要读/etc/profile、~/.bash_profile、~/.bash_login、~/.profile等等来执行。　<br />
　　-rcfile filename : 执行filename，而非~/.bashrc　<br />
　　-version : 显示版本。　<br />
　　-quiet : 启动时不要哩唆。　<br />
　　-login : 确保bash是个login shell。　<br />
　　-nobraceexpansion : 不要用curly brace expansion({}符号展开)。　<br />
　　-nolineediting : 不用readline来读取命令列。　<br />
　　-posix : 改采Posix 1003.2标准。　<br /><br /><br />
　　用于自动备份的Shell Script<br /><br /><br />
　　一个用于自动备份的Shell Script<br />
　　我们先前提到，可利用Shell Script搭配crond来作定期的工作。要作定期性的工作，在UNIX上，就是与crond的搭配运用。　<br /><br />
　　*************************<br /><br />
　　首先我们先来研究如何对系统进行备份。　<br />
　　要对系统进行备份，不外乎便是利用一些压缩工具。在许多UNIX系统上，tar及gzip是de
facto的资料交换标准。我们经常可以看见一些tar.gz或tgz档，这些档案，被称为tarball。当然了，您也可以用bzip2、zip等等压
缩工具来进行压缩，不必限定于gzip。但tar配合gzip是最普遍的，也是最方便的方式。　<br /><br />
　　要将我们想要的资料压缩起来，进行备份，可以结合tar及gzip一起进行。方式有很多种，最常用的指令是以下这一种:　<br /><br />
　　tar -c file/dir ... | gzip -9 &gt; xxxx.tar.gz　<br /><br />
　　您也可以分开来做:　<br /><br />
　　tar -r file/dir ... -f xxxx.tar　<br />
　　gzip -9 xxxx.tar　<br /><br />
　　或　<br /><br />
　　tar -r file/dir ... -f xxxx.tar　<br />
　　gzip -9 &lt; xxxx.tar &gt; xxxx.tar.gz　<br /><br />
　　*************************<br /><br />
　　在解过Linux下档案备份的基本知识后，我们来写一个将档案备份的Script。　<br />
　　#!/bin/sh　<br />
　　# Filename : backup　<br /><br />
　　DIRS="/etc /var /your_directories_or_files"　<br />
　　BACKUP="/tmp/backup.tgz"　<br /><br />
　　tar -c $DIRS | gzip -9 &gt; $BACKUP　<br /><br />
　　其中DIRS放的是您要备份的档案及目录，BACKUP是您的备份档。可不要将/tmp放进DIRS中，那样做，您是在做备份的备份，可能将您的硬碟塞爆。　<br /><br /><br />
　　*************************<br /><br />
　　接下来测试　<br />
　　[foxman@foxman bash]# chmod 755 backup　<br />
　　[foxman@foxman bash]# ./backup　<br /><br />
　　执行完成后在/tmp就会有一个backup.tgz，里面储存了您重要的资料。您可用　<br /><br />
　　gzip -dc /tmp/backup.tgz | tar -vt　<br />
　　或　<br />
　　tar vtfz /tmp/backup.tgz　<br /><br />
　　来看看里面的档案列表。　<br /><br />
　　要解开时，可用以下指令来完成复原:　<br /><br />
　　gzip -dc /tmp/backup.tgz | tar -xv　<br />
　　或　<br />
　　tar xvfz /tmp/backup.tgz　<br /><br />
　　备份通常是仅备份系统通常最重要的部份，/etc可说是不可缺少的一部份。另外，看您系统中有那些重要的资料需要备份。通常来说，您没有必要备份
/bin、/sbin、/usr/bin、/usr/sbin、/usr/X11R6/bin等等这些执行档目录。只要备份您重要的档案即可，别把整个硬
碟备份，那是蛮呆的动作。　<br /><br />
　　*************************<br /><br />
　　如果您有许多台机器，可利用其中一台任务较轻的内部网路主机，做为主要备份主机。将所有机器都自动执行备份，然后利用NFS/Coda/Samba等网路档案系统，将备份的资料放到该备份机器中，该机器则定时收取备份资料，然后您再由该机器中进行一次备份。　<br />
　　这里是整个系统备份方案的图示。　<br /><br />
　　在您进行之前，先解一下，系统中那些是要备份的，那些是不需要的。　<br /><br />
　　*************************<br /><br />
　　新的backup<br />
　　#!/bin/sh　<br />
　　HOSTNAME=`hostname`　<br />
　　DIRS="/etc /var /your_important_directory"　<br />
　　BACKUP="/tmp/$HOSTNAME.tgz"　<br />
　　NFS="/mnt/nfs"　<br /><br />
　　tar -c $DIRS | gzip -9 &gt; $BACKUP　<br />
　　mv -f $BACKUP $NFS　<br /><br /><br />
　　*************************<br /><br />
　　备份主机内的Script : collect_backup<br />
　　#!/bin/sh　<br />
　　NFS="/mnt/nfs"　<br />
　　BACKUP="/backup"　<br /><br />
　　mv -f $NFS/*.tgz $BACKUP　<br /><br /><br />
　　在此，您不能够将所有备份都直接放在/mnt/nfs，这是危险的。万一任一台机器不小心将/mnt/nfs所有内容删除，那么备份就会消失。因此，您需要将/mnt/nfs移到一个只有该备份主机可存取的目录中。　<br /><br /><br />
　　*************************<br /><br />
　　当这些个别的Script都测试好以后，接下来我们将他们放到crontab里面。找到您的crontab，它的位置可能在/var/spool/cron/crontabs/root、/etc/crontab、/var/cron/tabs/root。　<br />
　　在crontab中选择以下之一加入(看您定期的时间):　<br /><br />
　　Slackware : /var/spool/cron/crontabs/root<br />
　　01 * * * *　/full_backup_script_path/backup 1&gt; /dev/null 2&gt; /dev/null # 每小时(太过火一点)　<br />
　　30 16 * * *　/full_backup_script_path/backup 1&gt; /dev/null 2&gt; /dev/null # 每日16:30，下班前备份　<br />
　　30 16 * * 0　/full_backup_script_path/backup 1&gt; /dev/null 2&gt; /dev/null # 每周一16:30　<br />
　　0 5 1 * *　/full_backup_script_path/backup 1&gt; /dev/null 2&gt; /dev/null # 每月一号5:0　<br />
　　RedHat/Debian : /etc/crontab<br />
　　RedHat可直接将backup放入/etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly, /etc/cron.monthly。或采用如上加入/etc/crontab的方式:　<br />
　　有关crontab的用法，可查"man 5 crontab"，在此不详述。　<br /><br />
　　备份主机的设定类同。　<br /><br />
　　注意: 所有机器不要同时进行备份，否则网路会大塞车。备份主机收取备份的时间要设为最后，否则会收不到备份资料。您可以在实作后，将时间间隔调整一下。　<br /><br /><br />
　　*************************<br /><br />
　　看看，两个小小不到三行的Shell Script，配合cron这个定时工具。可以让原本需要耗时多个小时的人工备份工作，简化到不到十分钟。善用您的想像力，多加一点变化，可你让您的生活变得轻松异常，快乐悠哉。<br /><br /><br />
　　档案系统检查<br /><br />
　　系统安全一向是大多数电脑用户关心的事，在UNIX系统中，最重视的事，即系统中有没有"木马"(Trojan horse)。不管Trojan
horse如何放进来的，有一点始终会不变，即被放置木马的档案，其档案日期一定会被改变，甚至会有其它的状态改变。此外，许多状况下，系统会多出一些不
知名的档案。因此，平日检查整个档案系统的状态是否有被改变，将所有状态有改变的档案，以及目前有那些程式正在执行，自动报告给系统管理员，是个避免坐上
"木马"的良方。　<br /><br />
　　*************************<br /><br />
　　#!/bin/sh　<br />
　　# Filename : whatever_you_name_it　<br />
　　DIRS="/etc /home /bin /sbin /usr/bin /usr/sbin /usr/local /var /your_directory"　<br />
　　ADMIN="email@your.domain.com"　<br />
　　FROM="admin@your.domain.com"　<br />
　　# 写入Sendmail的标头　<br />
　　echo "Subject: $HOSTNAME filesystem check" &gt; /tmp/today.mail　<br />
　　echo "From: $FROM" &gt;&gt; /tmp/today.mail　<br />
　　echo "To: $ADMIN" &gt;&gt; /tmp/today.mail　<br />
　　echo "This is filesystem report comes from $HOSTNAME" &gt;&gt; /tmp/today.mail　<br />
　　# 报告目前正在执行的程式　<br />
　　ps axf &gt;&gt; /tmp/today.mail　<br />
　　# 档案系统检查　<br />
　　echo "File System Check" &gt;&gt; /tmp/today.mail　<br />
　　ls -alR $DIRS | gzip -9 &gt; /tmp/today.gz　<br />
　　zdiff /tmp/today.gz /tmp/yesterday.gz &gt;&gt; /tmp/today.mail　<br />
　　mv -f /tmp/today.gz /tmp/yesterday.gz　<br />
　　# 寄出信件　<br />
　　sendmail -t &lt; /tmp/today.mail　<br /><br />
　　然后把它放到一个不显眼的地方去，让别人找不到。　<br /><br />
　　把它加入crontab中。　<br /><br />
　　30 7 * * *　/full_check_script_path/whatever_you_name_it 1&gt; /dev/null 2&gt; /dev/null #上班前检查　<br /><br />
　　有些档案是固定会更动的，像/var/log/messages、/var/log/syslog、/dev/ttyX等等，不要太大惊小怪。<br /><br /><br />
　　控制圈for<br /><br />
　　演示了几个简单的Shell Script，相信您应该对Shell Script有点概念了。现在我们开始来仔细研究一些较高等的Shell
Script写作。一些进一步的说明，例如"$"、"&gt;"、"&lt;"、"&gt;&gt;"、"1&gt;"、"2&gt;"符号的使用，会在
稍后解释。　<br /><br />
　　*************************<br /><br />
　　for name [ in word; ] do list ; done<br />
　　控制圈。　<br />
　　word是一序列的字，for会将word中的个别字展开，然后设定到name上面。list是一序列的工作。如果[in word;]省略掉，那么name将会被设定为Script后面所加的参数。　<br /><br /><br />
　　*************************<br /><br />
　　例一:　<br />
　　#!/bin/sh　<br /><br />
　　for i in a b c d e f ; do　<br />
　　echo $i　<br />
　　done　<br /><br />
　　它将会显示出a到f。　<br /><br /><br />
　　*************************<br /><br />
　　例二: 另一种用法，A-Z<br />
　　#!/bin/sh　<br />
　　WORD="a b c d e f g h i j l m n o p q r s t u v w x y z"　<br /><br />
　　for i in $WORD ; do　<br />
　　echo $i　<br />
　　done　<br /><br />
　　这个Script将会显示a到z。　<br /><br /><br />
　　*************************<br /><br />
　　例三 : 修改副档名<br />
　　如果您有许多的.txt档想要改名成.doc档，您不需要一个一个来。　<br />
　　#!/bin/sh　<br /><br />
　　FILES=`ls /txt/*.txt`　<br /><br />
　　for txt in $FILES ; do　<br />
　　doc=`echo $txt | sed "s/.txt/.doc/"`　<br />
　　mv $txt $doc　<br />
　　done　<br /><br />
　　这样可以将*.txt档修改成*.doc档。　<br /><br /><br />
　　*************************<br /><br />
　　例四 : meow<br />
　　#!/bin/sh　<br />
　　# Filename : meow　<br />
　　for i ; do　<br />
　　cat $i　<br />
　　done　<br /><br />
　　当您输入"meow file1 file2 ..."时，其作用就跟"cat file1 file2 ..."一样。　<br /><br /><br />
　　*************************<br /><br />
　　例五 : listbin　<br />
　　#!/bin/sh　<br />
　　# Filename : listbin　<br /><br />
　　for i in /bin/* ; do　<br />
　　echo $i　<br />
　　done　<br /><br />
　　当您输入"listbin"时，其作用就跟"ls /bin/*"一样。　<br /><br /><br />
　　*************************<br /><br />
　　例六 : /etc/rc.d/rc　<br />
　　拿一个实际的例来说，Red Hat的/etc/rc.d/rc的启动程式中的一个片断。　<br /><br />
　　for i in /etc/rc.d/rc$runlevel.d/S*; do　<br />
　　# Check if the script is there.　<br />
　　[ ! -f $i ] &amp;&amp; continue　<br /><br />
　　# Check if the subsystem is already up.　<br />
　　subsys=${i#/etc/rc.d/rc$runlevel.d/S??}　<br />
　　[ -f /var/lock/subsys/$subsys ] || \　<br />
　　[ -f /var/lock/subsys/${subsys}.init ] &amp;&amp; continue　<br /><br />
　　# Bring the subsystem up.　<br />
　　$i start　<br />
　　done　<br /><br />
　　这个例中，它找出/etc/rc.d/rcX.d/S*所有档案，检查它是否存在，然后一一执行。　<br /><br /><br />
　　流程控制case<br /><br />
　　case word in [ pattern [ | pattern ] ... ) list ;; ] ... esac<br />
　　case/esac的标准用法大致如下:　<br />
case $arg in　<br />
　　pattern | sample) # arg in pattern or sample　<br />
　　;;　<br />
　　pattern1) # arg in pattern1　<br />
　　;;　<br />
　　*) #default　<br />
　　;;　<br />
esac　<br />
　　arg是您所引入的参数，如果arg内容符合pattern项目的话，那么便会执行pattern以下的程式码，而该段程式码则以两个分号";;"做结尾。　<br /><br />
　　可以注意到"case"及"esac"是对称的，如果记不起来的话，把"case"颠倒过来即可。　<br /><br /><br />
*************************<br /><br />
　　例一 : paranoia<br />
#!/bin/sh　<br />
case $1 in　<br />
　　　　start | begin)　<br />
　　　　　echo "start something"　<br />
　　　　;;　<br />
　　　　stop | end)　<br />
　　　　　echo "stop something"　<br />
　　　　;;　<br />
　　　　*)　<br />
　　　　　echo "Ignorant"　<br />
　　　　;;　<br />
esac　<br /><br />
　　执行<br />
　　[foxman@foxman bash]# chmod 755 paranoia　<br />
　　[foxman@foxman bash]# ./paranoia　<br />
　　Ignorant　<br />
　　[foxman@foxman bash]# ./paranoia start　<br />
　　start something　<br />
　　[foxman@foxman bash]# ./paranoia begin　<br />
　　start something　<br />
　　[foxman@foxman bash]# ./paranoia stop　<br />
　　stop something　<br />
　　[foxman@foxman bash]# ./paranoia end　<br />
　　stop something　<br /><br />
*************************<br /><br />
　　例二 : inetpanel<br />
　　许多的daemon都会附上一个管理用的Shell Script，像BIND就附上ndc，Apache就附上apachectl。这些管理程式都是用shell script来写的，以下示一个管理inetd的shell script。　<br />
#!/bin/sh　<br /><br />
case $1 in　<br />
　　start | begin | commence)　<br />
　　　 /usr/sbin/inetd　<br />
　　;;　<br />
　　stop | end | destroy)　<br />
　　　 killall inetd　<br />
　　;;　<br />
　　restart | again)　<br />
　　　 killall -HUP inetd　<br />
　　;;　<br />
　　*)　<br />
　　　 echo "usage: inetpanel [start | begin | commence | stop | end | destory | restart | again]"　<br />
　　;;　<br />
esac　<br /><br /><br />
*************************<br /><br />
　　例三 : 判断系统<br />
　　有时候，您所写的Script可能会跨越好几种平台，如Linux、FreeBSD、Solaris等等，而各平台之间，多多少少都有不同之处，有时候需要判断目前正在那一种平台上执行。此时，我们可以利用uname来找出系统资讯。　<br />
#!/bin/sh　<br /><br />
SYSTEM=`uname -s`　<br /><br />
case $SYSTEM in　<br />
　　Linux)　<br />
　　　　echo "My system is Linux"　<br />
　　　　echo "Do Linux stuff here..."　<br />
　　;;　<br />
　　FreeBSD)　<br />
　　　　echo "My system is FreeBSD"　<br />
　　　　echo "Do FreeBSD stuff here..."　<br />
　　;;　<br />
　　*)　<br />
　　　　echo "Unknown system : $SYSTEM"　<br />
　　　　echo "I don't what to do..."　<br />
　　;;　<br />
esac　<br /><br /><br />
　　流程控制select<br /><br />
　　select name [ in word; ] do list ; done<br />
　　select顾名思义就是在word中选择一项。与for相同，如果[in word;]省略，将会使用Script后面所加的参数。　<br />
　　例:<br />
#!/bin/sh　<br />
WORD="a b c"　<br /><br />
select i in $WORD ; do　<br />
　case $i in　<br />
　　a)　<br />
　　　echo "I am A"　<br />
　　;;　<br />
　　b)　<br />
　　　echo "I am B"　<br />
　　;;　<br />
　　c)　<br />
　　　echo "I am C"　<br />
　　;;　<br />
　　*)　<br />
　　　break;　<br />
　　;;　<br />
　esac　<br />
done　<br /><br />
　　执行结果<br />
　　[foxman@foxman bash]# ./select_demo　<br />
1) a　<br />
2) b　<br />
3) c　<br />
#? 1　<br />
I am A　<br />
1) a　<br />
2) b　<br />
3) c　<br />
#? 2　<br />
I am B　<br />
1) a　<br />
2) b　<br />
3) c　<br />
#? 3　<br />
I am C　<br />
1) a　<br />
2) b　<br />
3) c　<br />
#? 4　<br /><br /><br />
　　返回状态Exit<br /><br />
　　在继续下去之前，我们必须要切入另一个话题，即返回状态值 - Exit Status。因为if/while/until都迁涉到了使用Exit Status来控制程式流程的问题。　<br /><br />
　　*************************<br /><br />
　　许多人都知道，在许多语言中(C/C++/Perl....)，都有一个exit的函数，甚至连Bash自己都有个exit的内建命令。而exit后面所带的数字，便是返回状态值 - Exit Status。　<br />
　　返回状态值可以使得程式与程式之间，利用Shell script来结合的可能性大增，利用小程式，透过Shell script，来完成很杂的工作。　<br /><br />
　　在shell中，返回值为零表示成功(True)，非零值为失败(False)。　<br /><br /><br />
　　*************************<br /><br />
　　举例来说，以下这个两个小程式yes/no分别会返回0/1(成功/失败):　<br />
　　/* yes.c */　<br />
　　void main(void) { exit(0); }　<br />
　　/* no.c */　<br />
　　void main(void) { exit(1); }　<br />
　　那么以下这个"YES"的shell script便会显示"YES"。　<br />
　　#!/bin/sh　<br />
　　# YES　<br />
　　if yes ; then　<br />
　　echo "YES"　<br />
　　fi　<br />
　　而"NO"不会显示任何东西。　<br />
　　#!/bin/sh　<br />
　　# NO　<br />
　　if no ; then　<br />
　　echo "YES"　<br />
　　fi　<br /><br />
　　*************************<br /><br />
　　test express　<br />
　　[ express ]　<br />
　　在Shell script中，test express/[ express
]这个语法被大量地使用，它是个非常实用的指令。由于它的返回值即Exit
Status，经常被运用在if/while/until的场合中。而在后面，我们也会大量运用到，在进入介绍if/while/until之前，有必要
先解一下。　<br /><br />
　　其返回值为0(True)或1(False)，要看表述(express)的结果为何。　<br /><br />
　　express格式　<br /><br />
　　-b file : 当档案存在并且属性是Block special(通常是/dev/xxx)时，返回True。　<br />
　　-c file : 当档案存在并且属性是character special(通常是/dev/xxx)时，返回True。　<br />
　　-d file : 当档案存在并且属性是目录时，返回True。　<br />
　　-e file : 当档案存在时，返回True。　<br />
　　-f file :　当档案存在并且是正常档案时，返回True。　<br />
　　-g file :　当档案存在并且是set-group-id时，返回True。　<br />
　　-k file :　当档案存在并且有"sticky" bit被设定时，返回True。　<br />
　　-L file :　当档案存在并且是symbolic link时，返回True。　<br />
　　-p file :　当档案存在并且是name pipe时，返回True。　<br />
　　-r file :　当档案存在并且可读取时，返回True。　<br />
　　-s file :　当档案存在并且档案大小大于零时，返回True。　<br />
　　-S file : 当档案存在并且是socket时，返回True。　<br />
　　-t fd : 当fd被开启为terminal时，返回True。　<br />
　　-u file : 当档案存在并且set-user-id bit被设定时，返回True。　<br />
　　-w file : 当档案存在并且可写入时，返回True。　<br />
　　-x file : 当档案存在并且可执行时，返回True。　<br />
　　-O file : 当档案存在并且是被执行的user id所拥有时，返回True。　<br />
　　-G file : 当档案存在并且是被执行的group id所拥有时，返回True。　<br />
　　file1 -nt file2 : 当file1比file2新时(根据修改时间)，返回True。　<br />
　　file1 -ot file2 : 当file1比file2旧时(根据修改时间)，返回True。　<br />
　　file1 -ef file2 : 当file1与file2有相同的device及inode number时，返回True。　<br />
　　-z string : 当string的长度为零时，返回True。　<br />
　　-n string : 当string的长度不为零时，返回True。　<br />
　　string1 = string2 : string1与string2相等时，返回True。　<br />
　　string1 != string2 : string1与string2不相等时，返回True。　<br />
　　! express : express为False时，返回True。　<br />
　　expr1 -a expr2 : expr1及expr2为True。　<br />
　　expr1 -o expr2 : expr1或expr2其中之一为True。　<br />
　　arg1 OP arg2 :
OP是-eq[equal]、-ne[not-equal]、-lt[less-than]、-le[less-than-or-equal]、-gt
[greater-than]、-ge[greater-than-or-equal]的其中之一。　<br /><br /><br /><br />
　　*************************<br /><br />
　　在Bash中，当错误发生在致命信号时，bash会返回128+signal
number做为返回值。如果找不到命令，将会返回127。如果命令找到了，但该命令是不可执行的，将返回126。除此以外，Bash本身会返回最后一个
指令的返回值。若是执行中发生错误，将会返回一个非零的值。　<br />
　　Fatal Signal : 128 + signo　<br />
　　Can't not find command : 127　<br />
　　Can't not execute : 126　<br />
　　Shell script successfully executed : return the last command exit status　<br />
　　Fatal during execution : return non-zero<br /><br />
　　流程控制if<br /><br />
　　if list then list [ elif list then list ] ... [ else list ] fi<br />
　　几种可能的写法　<br /><br />
*************************<br /><br />
第一种　<br />
if list then　<br />
　do something here　<br />
fi　<br />
当list表述返回值为True(0)时，将会执行"do something here"。　<br /><br />
例一 : 当我们要执行一个命令或程式之前，有时候需要检查该命令是否存在，然后才执行。　<br />
if [ -x /sbin/quotaon ] ; then　<br />
　　echo "Turning on Quota for root filesystem"　<br />
　　/sbin/quotaon /　<br />
fi　<br /><br />
例二 : 当我们将某个档案做为设定档时，可先检查是否存在，然后将该档案设定值载入。　<br />
# Filename : /etc/ppp/settings　<br />
PHONE=1-800-COLLECT　<br /><br />
#!/bin/sh　<br />
# Filename : phonebill　<br />
if [ -f /etc/ppp/settings ] ; then　<br />
　　source /etc/ppp/settings　<br />
　　echo $PHONE　<br />
fi　<br />
执行　<br />
[foxman@foxman ppp]# ./phonebill　<br />
1-800-COLLECT　<br /><br /><br />
*************************<br /><br />
第二种　<br />
if list then　<br />
　do something here　<br />
else　<br />
　do something else here　<br />
fi　<br />
例三 : Hostname　<br />
#!/bin/sh　<br />
if [ -f /etc/HOSTNAME ] ; then　<br />
　　HOSTNAME=`cat /etc/HOSTNAME`　<br />
else　<br />
　　HOSTNAME=localhost　<br />
fi　<br /><br /><br />
*************************<br /><br />
第三种　<br />
if list then　<br />
　do something here　<br />
elif list then　<br />
　do another thing here　<br />
fi　<br />
例四 : 如果某个设定档允许有好几个位置的话，例如crontab，可利用if then elif fi来找寻。　<br />
#!/bin/sh　<br /><br />
if [ -f /etc/crontab ] ; then　<br />
　　CRONTAB="/etc/crontab"　<br />
elif [ -f /var/spool/cron/crontabs/root ] ; then　<br />
　　CRONTAB="/var/spool/cron/crontabs/root"　<br />
elif [ -f /var/cron/tabs/root ] ; then　<br />
　　CRONTAB="/var/cron/tabs/root"　<br />
fi　<br />
export CRONTAB　<br /><br /><br />
*************************<br /><br />
第四种　<br />
if list then　<br />
　do something here　<br />
elif list then　<br />
　do another thing here　<br />
else　<br />
　do something else here　<br />
fi　<br />
例五 : 我们可利用uname来判断目前系统，并分别做各系统状况不同的事。　<br />
#!/bin/sh　<br /><br />
SYSTEM=`uname -s`　<br /><br />
if [ $SYSTEM = "Linux" ] ; then　<br />
　echo "Linux"　<br />
elif [ $SYSTEM = "FreeBSD" ] ; then　<br />
　echo "FreeBSD"　<br />
elif [ $SYSTEM = "Solaris" ] ; then　<br />
　echo "Solaris"　<br />
else　<br />
　echo "What?"　<br />
fi　<br /><br />
控制圈while/until<br /><br />
while list do list done<br />
当list为True时，该圈会不停地执行。　<br />
例一 : 无限回圈写法　<br />
#!/bin/sh　<br /><br />
while : ; do　<br />
　echo "do something forever here"　<br />
　sleep 5　<br />
done　<br /><br />
例二 : 强迫把pppd杀掉。　<br />
#!/bin/sh　<br /><br />
while [ -f /var/run/ppp0.pid ] ; do　<br />
　　killall pppd　<br />
done　<br /><br /><br />
*************************<br /><br />
until list do list done<br />
当list为False(non-zero)时，该圈会不停地执行。　<br />
例一 : 等待pppd上线。　<br />
#!/bin/sh　<br />
until [ -f /var/run/ppp0.pid ] ; do　<br />
　　sleep 1　<br />
done　<br /><br /><br />
　　参数与变数<br /><br />
　　在继续下去介绍function之前，我们必须停下来介绍"参数与变数"。　<br /><br />
　　*************************<br /><br />
　　参数(Parameters)是用来储存"值"的资料型态，有点像是一般语言中的变数。它可以是个名称(name)、数字(number)、或者是以下所列出来一些特殊符号(Special Parameters)。　<br />
　　在shell中，变数是由name形式的参数所构成的。　<br /><br /><br />
　　*************************<br /><br />
　　在前面的许多例中，我们事实上已经看到许多参数的运用。要设定一个Parameter实际很简单:　<br />
　　name=value　<br /><br />
　　例如说:　<br /><br />
　　MYHOST="foxman"　<br /><br />
　　而要使用它时，则是加个"$"符号。　<br /><br />
　　echo $MYHOST　<br /><br />
　　*************************<br /><br />
　　位置参数(Positional Parameters)　<br /><br />
　　*************************<br /><br />
　　所谓的位置参数便是0,1,2,3,4,5,6,7,8,9...。使用时，用$0,$1,$2...。　<br />
　　位置参数是当script被载入时，后面所附加的参数。$0是本身，$1则为第一个参数，$2为第二个，依此类推。而当Positional Parameters被function所使用时，它们会被暂时取代(下一节会介绍function)。　<br /><br />
　　例如以下这个script:　<br />
　　#!/bin/sh　<br />
　　# Filename : position　<br />
　　echo $0　<br />
　　echo $1　<br /><br />
　　执行时:　<br />
　　[foxman@foxman bash]# ./position abc　<br />
　　./position　<br />
　　abc　<br /><br />
　　当位置参数超过两位数时，有特别的方法来展开，称为Expansion。　<br /><br />
　　*************************<br /><br />
　　特殊参数(Speical Parameters)　<br />
　　这些符号，非常不人性，对新手来说很困扰。但上手后，会觉得方便无比，有些如果您看不懂的话，就--算了，不用浪费太多时间在上面。　<br /><br />
　　*************************<br /><br />
　　* 星号　<br />
　　将Positional Parameters合成一个参数，其间隔为IFS内定参数的第一个字元(见内建变数一节)。　<br />
　　例:　<br />
　　#!/bin/sh　<br />
　　# starsig　<br />
　　echo $*　<br /><br />
　　执行:　<br />
　　[foxman@foxman bash]# starsig a b c d e f g　<br />
　　a b c d e f g　<br /><br />
　　*************************<br /><br />
　　@ at符号　<br />
　　与*星号类同。不同之处在于不参照IFS。　<br /><br />
　　例:　<br />
　　#!/bin/sh　<br />
　　# atsig　<br />
　　echo $@　<br /><br />
　　执行:　<br />
　　[foxman@foxman bash]# atsig a b c d e f g　<br />
　　a b c d e f g　<br /><br /><br />
　　*************************<br /><br />
　　# 井字号　<br />
　　展开Positional parameters的数量。　<br /><br />
　　例:　<br />
　　#!/bin/sh　<br />
　　# poundsig　<br />
　　echo $#　<br /><br />
　　执行　<br />
　　[foxman@foxman bash]# poundsig a b c d e f g　<br />
　　7　<br /><br />
　　*************************<br /><br />
　　? 问号　<br />
　　最近执行的foreground pipeline的状态。　<br /><br /><br />
　　*************************<br /><br />
　　- 减号　<br />
　　最近执行的foreground pipeline的选项参数。　<br /><br />
　　*************************<br /><br />
　　$ 钱钱钱　<br />
　　本身的Process ID。　<br /><br />
　　[foxman@foxman bash]# ps ax | grep bash　<br />
　　1635　p1 S　　0:00 /bin/bash　<br /><br />
　　[foxman@foxman bash]# echo $$　<br />
　　1635　<br /><br />
　　*************************<br /><br />
　　! 惊号　<br />
　　最近执行背景命令的Process ID。　<br /><br />
　　*************************<br /><br />
　　0 零　<br />
　　在Positional Parameters一部份已经说明过了，是执行的shell script本身。但如果是用"bash -c"，则$0被设为第一个参数。　<br /><br />
　　[foxman@foxman bash]# echo $0　<br />
　　/bin/bash　<br /><br />
　　*************************<br /><br />
　　_ 底线符号　<br />
　　显示出最后一个执行的命令。　<br /><br />
　　[foxman@foxman bash]# echo $_　<br />
　　bash　<br /><br /><br />
　　*************************<br /><br />
　　内建变数(Shell Variables)　<br />
　　Bash有许多内建变数，像PATH、HOME、ENV......等等。这些内建变数将在另一节中，专门一一说明。<br /><br />
　　函数function<br /><br />
　　[ function ] name () { list; }<br />
　　function的参数是Positional Paraments。　<br /><br />
　　例　<br />
#!/bin/sh　<br /><br />
function func() {　<br />
　echo $1　<br />
　echo $2　<br />
　return 1　<br />
}　<br /><br />
func "Hello" "function"　<br /><br />
　　局部变数可用local来宣告。　<br /><br />
　　函数可export，使用下一层的shell可以使用。　<br /><br />
　　函数可递，没有递层数的限制。<br /><br />
　　Bash内建指令集　<br /><br />
　　以下的命令，大部份都没有使用例，您可能会看不出所以然，摸不著头脑。在我加入例说明前，建议您"man bash"，然后自己实际操作一次。　<br /><br />
　　*************************<br />
　　: [arguments]　<br />
　　不做任何事，除了[arguments]一些参数展开及一些特定重导向的作业外。　<br /><br />
　　永远返回零。它的用法跟true一样。　<br /><br />
　　*************************<br />
　　.　filename [arguments]　<br />
　　source filename [arguments]　<br />
　　由filename中读取命令，并执行。　<br />
　　您会在/etc/rc.d/*中发现很多　<br />
　　. /xxxx　<br />
　　的指令，而xxxx的permission都不是可执行的。事实上，在tcsh中，需要用　<br />
　　source /xxxx　<br />
　　来做同样的指令。　<br />
　　注意到"."的后面是有空格的(比较一下". /"跟"./"，不一样)。filename是内含指令的纯文字档即可，无须chmod 755 filename。　<br /><br />
　　例<br />
　　filename : my_source　<br />
　　DEV=lo　<br />
　　IP=127.0.0.1　<br />
　　NETMASK=255.0.0.0　<br />
　　BROADCAST=127.255.255.255　<br /><br />
　　ifconfig $IP netmask $NETMASK broadcast $BROADCAST dev $DEV　<br /><br />
　　接下来　<br />
　　. my_source　<br />
　　或　<br />
　　source my_source　<br /><br />
　　便可执行该script，而不需要"chmod 755 my_source"　<br /><br />
　　*************************<br />
　　alias [name[=value] ...]　<br />
　　昵称命令　<br />
　　例如您如果来自DOS的世界，对UNIX的指令不习惯，可用alias来修改，以符合您的习惯。　<br /><br />
　　例<br />
　　alias ls="ls --color"　<br />
　　alias dir="ls"　<br />
　　alias cd..="cd .."　<br />
　　alias copy="cp -f" # dangerous, recommend, "cp -i"　<br />
　　alias del="rm -f" # dangerous, recommend, "rm -i"　<br />
　　alias move="mv -f" # dangerous, recommend, "mv -i"　<br />
　　alias md="mkdir"　<br />
　　alias rd="rmdir"　<br /><br />
　　*************************<br />
　　unalias [-a] [name ...]　<br />
　　unalias取消alias的设定。"unalias -a"将全部alias取消。　<br /><br />
　　例<br />
　　unalias copy　<br /><br />
　　*************************<br />
　　bg [jobspec]　<br />
　　将指定任务放到背景中，如果jobspec未指定，内定为目前的。　<br /><br />
　　*************************<br />
　　fg [jobspec]　<br />
　　将指定任务放到前景中，如果jobsepc没有指定，那么内定为目前的。　<br /><br />
　　*************************<br />
　　jobs [-lnp] [ jobspec ... ]　<br />
　　第一种形式列出目前正在工作的任务。　<br />
　　-l : 除了列出一般资讯外，还列出Process IDs。　<br />
　　-p : 仅列出该工作群"首脑"(Process group leader)的Process ID.　<br />
　　-n : 则仅列出有改变的jobs的状态。　<br />
　　如果给定jobspec，输出资讯则只有该jobspec。　<br /><br />
　　返回值为零，除非有非法的选项发生。　<br /><br />
　　jobs -x command [ args ... ]　<br /><br />
　　如果使用第二种形式(-x)，jobs取代指定的command及args，并执行返回其Exit Status。　<br /><br />
　　*************************<br />
　　kill [-s sigspec | -sigspec] [pid | jobspec] ...　<br />
　　将sigspec的信号送到pid或jobspec。　<br />
　　sigspec可以是SIGKILL/KILL这种形式或是信号号码。如果sigspec是signal name，则大小写无关，而且可以没有SIG。　<br />
　　kill -l [signum]　<br />
　　列出信号名称。　<br /><br />
　　[foxman@foxman bash]# kill -l　<br />
　　1) SIGHUP　　　 2) SIGINT　　　 3) SIGQUIT　　　4) SIGILL　<br />
　　5) SIGTRAP　　　6) SIGIOT　　　 7) SIGBUS　　　 8) SIGFPE　<br />
　　9) SIGKILL　　 10) SIGUSR1　　 11) SIGSEGV　　 12) SIGUSR2　<br />
　　13) SIGPIPE　　 14) SIGALRM　　 15) SIGTERM　　 17) SIGCHLD　<br />
　　18) SIGCONT　　 19) SIGSTOP　　 20) SIGTSTP　　 21) SIGTTIN　<br />
　　22) SIGTTOU　　 23) SIGURG　　　24) SIGXCPU　　 25) SIGXFSZ　<br />
　　26) SIGVTALRM　 27) SIGPROF　　 28) SIGWINCH　　29) SIGIO　<br />
　　30) SIGPWR　<br /><br />
　　*************************<br />
　　wait [n]　<br />
　　等待指定的行程，并返回其结束状态。n可以是个jobspec或Process
ID。如果n未指定，则等待所有的子行程，及返回值为零。若n为不存在的job或process，则返回127。否则，返回值为最后一个
job/process的Exit Status。　<br /><br />
　　*************************<br />
　　bind [-m keymap] [-lvd] [-q name]　<br />
　　bind [-m keymap] -f filename　<br />
　　bind [-m keymap] keyseq:function-name　<br />
　　显示出目前readline的按键及链结函数设定或是巨集。　<br /><br />
　　-m keymap : 设定keymap binding。　<br />
　　-l : 显示出所有readline function的名称。　<br />
　　-v : 显示出目前的function name及bindings。　<br />
　　-d : 显示出function name及bindings。　<br />
　　-f filename : 从filename读取key bindings。　<br />
　　-q function : 询问那个按键触发function。　<br /><br />
　　*************************<br />
　　break [n]　<br />
　　跳出控制回圈for/while/until中使用。如果有指定n，则跳出n层。n必须是大于等于1。若n大于巢状圈数，则所有的圈都会跳离。返回值回零。　<br /><br />
　　*************************<br />
　　continue [n]　<br />
　　还原控制回圈for/while/until中使用。如果有指定n，则返回n层。n必须是大于等于1。若n大于巢状圈数，则还原到最上层。返回值回零。　<br /><br />
　　*************************<br />
　　exit [n]　<br />
　　离开程式。n是Exit Status。　<br /><br />
　　*************************<br />
　　return [n]　<br />
　　在function中使用。n为返回值，其作用与Exit Status一样。　<br /><br />
　　*************************<br />
　　builtin shell-builtin [arguments]　<br />
　　执行内建函数。当您定义了与内建函数相同的指令时，可用此命令来执行内建函数。　<br /><br />
　　*************************<br />
　　cd [dir]　<br />
　　更换目录到dir。如果没有指定，内定为HOME所指定的目录。　<br /><br />
　　*************************<br />
　　command [-pVv] command [arg ...]　<br />
　　用command指定可取消正常的shell function寻找。只有内建命令及在PATH中找得到的才会被执行。"-p"选项，搜寻命令的方式是用PATH来找。"-V"或"-v"选项，会显示出该命令的一些简约描述。　<br /><br />
　　*************************<br />
　　declare [-frxi] [name[=value]]　<br />
　　typeset [-frxi] [name[=value]]　<br />
　　宣告参数并给它们设定属性。如果没有给定名称，将会显示各参数值。　<br /><br />
　　-f : 仅使用函数名称。　<br />
　　-r : 将name设为readonly。　<br />
　　-x : 将name输出给后续环境使用。　<br />
　　-i : 该参数被设为integer来使用，可用于算术表述。　<br /><br />
　　用"+"时，关闭该属性。　<br /><br />
　　*************************<br />
　　dirs [-l] [+/-n]　<br />
　　显示目前记忆的目录。目录可透过pushd/popd来操作。　<br /><br />
　　+n : 显示开始的记录n个。　<br />
　　-n : 显示结尾的记录n个。　<br />
　　-l : 显示较多的资讯。　<br /><br />
　　*************************<br />
　　echo [-neE] [arg ...]　<br />
　　输出显示args，由空白分隔。返回值永为零。　<br /><br />
　　-n : 不跳行。　<br />
　　-e : 启动"\"符号的解译。　<br />
　　-E : 将ESC解译功能取消。　<br /><br />
　　"\a" : alert(bell)，发出声响。　<br />
　　"\b" : backspace，倒退。　<br />
　　"\c" : suppress trailing newline，不跳行。　<br />
　　"\f" : form feed，跳行跳格。　<br />
　　"\n" : new line，新行。　<br />
　　"\r" : carriage return，回到行起点。　<br />
　　"\t" : horizontal tab，水平跳位。　<br />
　　"\v" : vertical tab，垂直跳位。　<br />
　　"\\" : 输出"\"。　<br />
　　"\nnn" : 输出ASCII Code号码nnn(八进位)。　<br /><br />
　　*************************<br />
　　enable [-n] [-all] [name ...]　<br />
　　启动或关闭内建函数命令。使用"-n"将所有指定命令皆关闭，否则都是启动的。如果只有"-n"参数，它将会显示所有关闭的函数。如果只有"-all"，它将会显示所有内建命令。　<br /><br />
　　*************************<br />
　　eval [arg ...]　<br />
　　读取args，并将args合为一个命令，然后执行。其返回值成为eval的返回值。如果没有参数，eval返回True。　<br /><br />
　　*************************<br />
　　exec [[-] command [arguments]]　<br />
　　当命令执行时，该命令取代shell，没有新的process产生。如果第一个参数是"-"，shell会将"-"放入第零个参数，传给command。　<br /><br />
　　*************************<br />
　　export [-nf] [name[=word]] ...　<br />
　　export -p　<br />
　　将name输出给环境，给往后的命令使用。"-f"选项表示name是函数。"-p"显示出所有export的名称。"-n"移除name。　<br /><br />
　　*************************<br />
　　set [--abefhkmnptuvxldCHP] [-o option] [arg ...]　<br />
　　-a : 自动将变数标记为可让后面环境所使用。　<br />
　　-b : 立即报告被终结的背景程式状态。　<br />
　　-e : 当命令(simple-command，见后面)返回非零值时，立即跳出。　<br />
　　-f : 取消pathname expansion。　<br />
　　-h : 找出所记忆的函数命令位置。　<br />
　　-k : 所有keyword参数都放到环境中。　<br />
　　-m : 监督模式。　<br />
　　-n : 读取命令，但不要执行。可用于语法检查。　<br />
　　-p : 打开privileged模式。　<br />
　　-t : 当读取一个命令并执行后，立即离开。　<br />
　　-u : 当参数展开时，把unset参数当成是错误。　<br />
　　-v : 列出shell input lines。　<br />
　　-x : 在展开每个simple-command后，bash显示展开值在PS4上。　<br />
　　-l : 储存并还原name binding在for语法中。　<br />
　　-d : 关闭hasing command搜寻。　<br />
　　-C : 跟`noclobber=`一样。请见内定参数一节。　<br />
　　-H : 启动! style history substitution。　<br />
　　-P : 在使用像cd这种指令时，不要跟随symbolic links。　<br />
　　-- : "--"之后，没有参数跟在后面。　<br />
　　- : 指定将所有后面的参数当成是位置参数。　<br />
　　-o option-name : option-name可以是以下之一　<br />
　　allexport : 与"-a"相同。　<br />
　　braceexpand : 启动Brace Expansion。这是内定设定。　<br />
　　emacs : 使用emacs-style命令列编辑界面。　<br />
　　errexit : 与"-e"相同。　<br />
　　histexpand : 与"-H"相同。　<br />
　　ignoreeof : 效果跟`IGNOREEOF=10`一样。　<br />
　　interactive-commands : 允许#做为解。　<br />
　　monitor : 与"-m"相同。　<br />
　　noclobber : 与"-C"相同。　<br />
　　noexec : 与"-n"相同。　<br />
　　noglob : 与"-f"相同。　<br />
　　nohash : 与"-d"相同。　<br />
　　notify : 与"-b"相同。　<br />
　　nounset : 与"-u"相同。　<br />
　　physical : 与"-P"相同。　<br />
　　posix : Bash行为修改为Posix 1003.2标准。　<br />
　　privileged : 与"-p"相同。　<br />
　　verbose : 与"-v"相同。　<br />
　　vi : 使用vi-style命令列编辑程式。　<br />
　　xtrace : 与"-x"相同。　<br /><br />
　　*************************<br />
　　unset [-fv] [name ...]　<br />
　　移除对映于name的参数。要注意PATH、IFS、PPID、PS1、PS2、UID、EUID不能unset。若RANDOM、SECONDS、
LINENO、HISTCMD被unset，它们会丧失原有意义，既始它们后来被重设也一样。返回值为True，除非name是不能被unset的。　<br /><br />
　　*************************<br />
　　fc [-e ename] [-nlr] [first] [last]　<br />
　　fc -s [pat=rep] [cmd]　<br />
　　修正命令。　<br /><br />
　　*************************<br />
　　getopts optstring name [args]　<br />
　　解析位置参数。　<br /><br />
　　*************************<br />
　　help [pattern]　<br />
　　显示协助资讯。　<br /><br />
　　*************************<br />
　　history [n]　<br />
　　history -rwan [filename]　<br />
　　没有参数时，会显示所下命令的历史记录。带有参数"n"则显示最后n个。　<br /><br />
　　其它参数如下:　<br />
　　-a : 新增"新历史"到历史档中。　<br />
　　-n : 读取尚未读到历史中的记录。　<br />
　　-r : 读取filename做为历史档，并用它为目前历史记录。　<br />
　　-w : 将现有历史记录写到filename中。　<br /><br />
　　*************************<br />
　　let arg [arg ...]　<br />
　　算术表述。请参考算术表述一节。　<br /><br />
　　*************************<br />
　　local [name[=value] ...]　<br />
　　产生一个局部参数。如果用于function，则其作用围在function内及其子函数。　<br /><br />
　　*************************<br />
　　logout　<br />
　　离开login shell。　<br /><br />
　　*************************<br />
　　popd [+/-n]　<br />
　　移除目录堆叠。"+n"移除上面n个，"-n"移除下面n个。　<br /><br /><br />
　　*************************<br />
　　pushd [dir]　<br />
　　pushd +/-n　<br />
　　将目录新增到目录堆叠的最上面。"+n"旋转该堆叠，使第n个目录变成最上面。"-n"旋转该堆叠，使倒数第n个目录变成最上面。　<br /><br />
　　*************************<br />
　　pwd　<br />
　　列出目前工作目录的绝对路径。　<br /><br />
　　*************************<br />
　　read [-r] [name ...]　<br />
　　读进一行，然后第一个字设到第一个name，第二个设到第二个name，依此类推。如果没有name在参数中，则read会将值设到REPLY。返回值为零，除非遇到End-Of-File。若有"-r"选项，则"\n"被考虑为该行的一部份。　<br /><br />
　　*************************<br />
　　readonly [-f] [name ...]　<br />
　　readonly -p　<br />
　　将给定的name标记为readonly。如果是"-f"选项，则函数也一样被标记为readonly。"-p"会列出所有readonly的name。"--"取消检查剩余的参数。　<br /><br />
　　*************************<br />
　　shift [n]　<br />
　　Positional Parameters从n+1...开始，会被改为$1...。n若为零，则没有改变。n若未给定，则内定为1。n必须是非负数，并且小于或等于$#。若n大于$#，则没有改变。返回值为零，除非n大于$#或小于零。　<br /><br />
　　*************************<br />
　　suspend [-f]　<br />
　　暂停这个shell的执行，直到它收到SIGCONT信号。"-f"选项则是叫login shell不要抱怨，不过还是一样暂停。返回状态零，除非该shell是个login shell，而且没有"-f"选项。　<br /><br />
　　*************************<br />
　　test expr　<br />
　　[ expr ]　<br />
　　我们在Exit Status的部份已经说过了，不再重。　<br /><br />
　　*************************<br />
　　times　<br />
　　列出该shell的累积的使用者及系统时间及从shell执行的process时间，返回值为零。　<br /><br />
　　------------------------------------------------------------------------------<br />
　　trap [-l] [arg] [sigspec]　<br />
　　当收到sigspec信号时，执行arg命令。"-l"显示出信号名称及号码。　<br /><br />
　　*************************<br />
　　type [-all] [-type | -path] name [name ...]　<br />
　　没有参数的状况下，它会显示出shell如何解译name做为命令。如果有"-type"，它将会显示alias、keyword、
function、builtin或file。如果有"-path"的参数，它将会显示该命令的路径，找不到的话，不显示任何东西。如果有"-all"的
参数，它将会显示所有可执行name的可能路径。type接受"-a"、"-t"、"-p"做为缩写。　<br /><br />
　　*************************<br />
　　ulimit [-SHacdfmstpnuv [limit]]　<br />
　　ulimit提供了对shell的可获取资源控制的功能。　<br /><br />
　　-a : 报告目前所有限制。　<br />
　　-c : 设定最大可产生的core档案。　<br />
　　-d : 行程资料段(process's data segment)最大值。　<br />
　　-f : 可被这个shell产生的最大档案。　<br />
　　-m : resident set size最大值。　<br />
　　-s : 堆叠最大值。　<br />
　　-t : CPU TIME最大值(以秒计算)。　<br />
　　-p : pipe size in 512-byte blocks的最大值。　<br />
　　-n : 可开启的file descriptors最大值。　<br />
　　-u : 单一使用者可使用的最大process数。　<br />
　　-v : 该shell最大虚拟记忆体可用值。　<br /><br />
　　所有项目是以1024做为单位。　<br /><br />
　　*************************<br />
　　umask [-S] [mode]　<br />
　　将使用者的file-creation mask设为mode。"-S"选项将mask印成符号形式。<br /><br /><br />
　　Bash内建参数<br /><br />
　　PPID : 该bash的呼叫者process ID.　<br /><br />
　　PWD : 目前的工作目录。　<br /><br />
　　OLDPWD : 上一个工作目录。　<br /><br />
　　REPLY : 当read命令没有参数时，直接设在REPLY上。　<br /><br />
　　UID : User ID。　<br /><br />
　　EUID : Effective User ID。　<br /><br />
　　BASH : Bash的完整路径。　<br /><br />
　　BASH_VERSION : Bash版本。　<br /><br />
　　SHLVL : 每次有Bash执行时，数字加一。　<br /><br />
　　RANDOM : 每次这个参数被用到时，就会产生一个乱数在RANDOM上。　<br /><br />
　　SECONDS : 从这个Shell一开始启动后的时间。　<br /><br />
　　LINENO : Script的行数。　<br /><br />
　　HISTCMD : 历史记录数。　<br /><br />
　　OPTARG : getopts处理的最后一个选项参数。　<br /><br />
　　OPTIND : 下一个要由getopts所处理的参数号码。　<br /><br />
　　HOSTTYPE : 机器种类。　<br /><br />
　　OSTYPE : 作业系统名称。　<br /><br />
　　IFS : Internal Field Separator。　<br /><br />
　　PATH : 命令搜寻路径。　<br />
　　PATH="/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:."　<br /><br />
　　HOME : 目前使用者的home directory;　<br /><br />
　　CDPATH : cd命令的搜寻路径。　<br /><br />
　　ENV : 如果这个参数被设定，每次有shell script被执行时，将会执行它所设定的档名做为环境设定。　<br /><br />
　　MAIL : 如果这个参数被设定，而且MAILPATH没有被设定，那么有信件进来时，bash会通知使用者。　<br /><br />
　　MAILCHECK : 设定多久时间检查邮件一次。　<br /><br />
　　MAILPATH : 一串的邮件检查路径。　<br /><br />
　　MAIL_WARNING : 如果有设定的话，邮件被读取后，将会显示讯息。　<br /><br />
　　PS1 : 提示讯息设定，内定为"bash\$ "。(请详见提示讯息一节。)　<br /><br />
　　PS2 : 第二提示讯息设定，内定为"&gt; "。　<br /><br />
　　PS3 : select命令所使用的提示讯息。　<br /><br />
　　PS4 : 执行追踪时用的提示讯息设定，内定为"+ "。　<br /><br />
　　HISTSIZE : 命令历史记录量，内定为500。　<br /><br />
　　HISTFILE : 历史记录档，内定~/.bash_history。　<br /><br />
　　HISTFILESIZE : 历史记录档行数最大值，内定500。　<br /><br />
　　OPTERR : 如果设为1，bash会显示getopts的错误。　<br /><br />
　　PROMPT_COMMAND : 如果设定的话，该值会在每次执行命令前都显示。　<br /><br />
　　IGNOREEOF : 将EOF值当成输入，内定为10。　<br /><br />
　　TMOUT : 如果设为大于零，该值被解译为输入等待秒数。若无输入，当成没有输入。　<br /><br />
　　FCEDIT : fc命令的内定编辑器。　<br /><br />
　　FIGNORE : 请详见READLINE。　<br /><br />
　　INPUTRC : readline的startup file，内定~/.inputrc　<br /><br />
　　notify : 如果设定了，bash立即报告被终结的背景程式。　<br /><br />
　　history_control, HISTCONTROL : history使用。　<br /><br />
　　command_oriented_history : 存入多行指令。　<br /><br />
　　glob_dot_filenames : 如果设定了，bash将会把"."包含入档案路径中。　<br /><br />
　　allow_null_glob_expansion : 如果设定了，bash允许路径明称为null string。　<br /><br />
　　histchars : history使用。　<br /><br />
　　nolinks : 如果设定了，执行指令时，不会跟随symbolic links。　<br /><br />
　　hostname_completion_file, HOSTFILE : 包含与/etc/hosts相同格式的档名。　<br /><br />
　　noclobber : 如果设定了，Bash不会覆写任何由"&gt;"、"&gt;&amp;"及"&lt;&gt;"所操作的档案。　<br /><br />
　　auto_resume : 请见任务控制一节。　<br /><br />
　　no_exit_on_failed_exec : 如果该值存在，非互动的shell不会因为exec失败而跳出。　<br /><br />
　　cdable_vars : 如果启动，而cd命令找不到目录，可切换到参数形态指定的目录下。<br /><br /><br />
　　提示符号<br /><br />
　　Bash使用PS1~PS4来显示提示符号，其格式如下:　<br /><br />
　　*************************<br /><br />
　　\t : 现在时间。　<br />
　　\d : 现在日期。　<br />
　　\n : 新行。　<br />
　　\s : shell的名称。　<br />
　　\w : 目前工作目录。　<br />
　　\W : 目前工作目录完整路径。　<br />
　　\u : 使用者名称。　<br />
　　\h : Hostname。　<br />
　　\# : 这个命令的号码。　<br />
　　\! : 历史号码。　<br />
　　\$ : 如果EUID是0，则#，否则为$。　<br />
　　\nnn : 八进位的字元。　<br />
　　\\ : "\"符号。　<br />
　　\[ : 开始一序列不可列印的字元。　<br />
　　\] : 结束一序列不可列印的字元。<br /><br /><br />
　　算术表述<br /><br />
　　- +　<br />
　　! ~　<br />
　　* / %　<br />
　　+ -　<br />
　　&lt;&lt; &gt;&gt;　<br />
　　&lt;= &gt;= &lt; &gt;　<br />
　　== !=　<br />
　　&amp;　<br />
　　^　<br />
　　|　<br />
　　&amp;&amp;　<br />
　　||　<br />
　　= *= /= %= += -= &lt;&lt;= &gt;&gt;= &amp;= ^= |=　<br /><br />
　　重导Redirection<br /><br />
　　&gt;　<br />
　　&gt;&gt;　<br />
　　1&gt;　<br />
　　.　<br />
　　.　<br /><br /><br />
　　语法<br /><br />
　　Simple Command　<br /><br /><br />
　　Pipelines　<br /><br /><br />
　　Lists　<br /><br />
　　(list)　<br />
　　{ list; }<img src ="http://www.blogjava.net/alex/aggbug/53293.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-06-16 14:20 <a href="http://www.blogjava.net/alex/archive/2006/06/16/53293.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]iptables使用实例</title><link>http://www.blogjava.net/alex/archive/2006/06/06/50815.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 06 Jun 2006 09:05:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/06/06/50815.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/50815.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/06/06/50815.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/50815.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/50815.html</trackback:ping><description><![CDATA[首先让我们看一下服务器/客户机的交互原理。服务器提供某特定功能的服务总是由特定的后台程序提供的。在TCP/IP网络中，常常把这个特定的服务绑定到
特定的TCP或UDP端口。之后，该后台程序就不断地监听（listen)该端口，一旦接收到符合条件的客户端请求，该服务进行TCP握手后就同客户端建
立一个连接，响应客户请求。与此同时，再产生一个该绑定的拷贝，继续监听客户端的请求。 <br /><br />举一个具体的例子：假设网络中有一台服务器A
(IP地址为1.1.1.1)提供WWW服务，另有客户机B(2.2.2.2)、C(3.3.3.3)。首先，服务器A运行提供WWW服务的后台程序（比
如Apache）并且把该服务绑定到端口80，也就是说，在端口80进行监听。当B发起一个连接请求时,B将打开一个大于1024的连接端口(1024内
为已定义端口),假设为1037。A在接收到请求后，用80端口与B建立连接以响应B的请求，同时产生一个80端口绑定的拷贝，继续监听客户端的请求。假
如A又接收到C的连接请求（设连接请求端口为1071），则A在与C建立连接的同时又产生一个80端口绑定的拷贝继续监听客户端的请求。如下所示，因为系
统是以源地址、源端口、目的地址、目的端口来标识一个连接的，所以在这里每个连接都是唯一的。 <br /><br />服务器 客户端 <br />连接1：a.b.c.1:80 &lt;=&gt; a.b.c.4:1037 <br />连接2：a.b.c.1:80 &lt;=&gt; a.b.c.7:1071 <br /><br />每
一种特定的服务都有自己特定的端口，一般说来小于1024的端口多为保留端口，或者说是已定义端口，低端口分配给众所周知的服务（如WWW、FTP等
等），从512到1024的端口通常保留给特殊的UNIX TCP/IP应用程序，具体情况请参考/etc/services文件或RFC1700。 <br /><br />假设网络环境如下：某一单位，租用DDN专线上网，网络拓扑如下： <br /><br />+--------------+ <br />| 内部网段 | eth1+--------+eth0 DDN <br />| +------------|firewall|&lt;===============&gt;Internet <br />| 198.168.80.0 | +--------+ <br />+--------------+ <br />eth0: 198.199.37.254 <br />eth1: 198.168.80.254 <br /><br />以上的IP地址都是Internet上真实的IP，故没有用到IP欺骗。并且，我们假设在内部网中存在以下服务器： <br />www服务器：www.yourdomain.com 198.168.80.11 <br />ftp服务器：ftp.yourdomain.com 198.168.80.12 <br />email服务器：mail.yourdomain.com 198.168.80.13 <br /><br />下面我们将用iptables一步一步地来建立我们的包过滤防火墙，需要说明的是，在这个例子中，我们主要是对内部的各种服务器提供保护。 <br /><br />1.
在/etc/rc.d/目录下用touch命令建立firewall文件，执行chmod u+x firewll以更改文件属性
，编辑/etc/rc.d/rc.local文件，在末尾加上 /etc/rc.d/firewall 以确保开机时能自动执行该脚本。 <br /><br />2. 刷新所有的链的规则 <br />#!/bin/sh <br /><br />echo "Starting iptables rules..." <br /><br />#Refresh all chains <br /><br />/sbin/iptables -F <br /><br />3. 我们将首先禁止转发任何包，然后再一步步设置允许通过的包。 <br />所以首先设置防火墙FORWARD链的策略为DROP： <br /><br />/sbin/iptables -P FORWARD DROP <br /><br />4.设置关于服务器的包过虑规则： <br /><br />在这里需要注意的是，服务器/客户机交互是有来有往的，也就是说是双向的，所以我们不仅仅要设置数据包出去的规则，还要设置数据包返回的规则，我们先建立针对来自Internet数据包的过虑规则。 <br /><br />WWW服务：服务端口为80，采用tcp或udp协议。规则为：eth0=&gt;允许目的为内部网WWW服务器的包。 <br /><br />###########################Define HTTP packets#################################### <br /><br />#Allow www request packets from Internet clients to www servers <br />/sbin/iptables -A FORWARD -p tcp -d 198.168.80.11 --dport www -i eth0 -j ACCEPT <br /><br />FTP
服务：FTP服务有点特别，因为需要两个端口，因为FTP有命令通道和数据通道。其中命令端口为21，数据端口为20，并且有主动和消极两种服务模式，其
消极模式连接过程为：FTP客户端首先向FTP服务器发起连接请求，三步握手后建立命令通道，然后由FTP服务器请求建立数据通道，成功后开始传输数据，
现在大多数FTP客户端均支持消极模式，因为这种模式可以提高安全性。FTP服务采用tcp协议。规则为：eth0=&gt;仅允许目的为内部网ftp服
务器的包。 <br /><br />############################Define FTP packets##################################### <br /><br />#Allow ftp request packets from Internet clients to Intranet ftp server <br />/sbin/iptables -A FORWARD -p tcp -d 198.168.80.12 --dport ftp -i eth0 -j ACCEPT <br /><br /><br />EMAIL服务：包含两个协议，一是smtp，一是pop3。出于安全性考虑，通常只提供对内的pop3服务，所以在这里我们只考虑针对smtp的安全性问题。smtp端口为21，采用tcp协议。eth0=&gt;仅允许目的为email服务器的smtp请求。 <br /><br />###########################Define smtp packets#################################### <br />/sbin/iptables -A FORWARD -p tcp -d 198.168.80.13 --dport smtp -i eth0 -j ACCEPT <br /><br />5. 设置针对Intranet客户的过虑规则： <br /><br />在
本例中我们的防火墙位于网关的位置，所以我们主要是防止来自Internet的攻击，不能防止来自Intranet的攻击。假如我们的服务器都是基于
linux的，也可以在每一部服务器上设置相关的过虑规则来防止来自Intranet的攻击。对于Internet对Intranet客户的返回包，我们
定义如下规则。 <br /><br />#############Define packets from Internet server to Intranet####################### <br />/sbin/iptables -A FORWARD -p tcp -s 0/0 --sport ftp-data -d 198.168.80.0/24 -i eth0 -j ACCEPT <br />/sbin/iptables -A FORWARD -p tcp -d 198.168.80.0/24 ! -syn -i eth0 -j ACCEPT <br />/sbin/iptables -A FORWARD -p udp -d 198.168.80.0/24 -i eth0 -j ACCEPT <br /><br />说明：第一条允许Intranet客户采用消极模式访问Internet的FTP服务器；第二条接收来自Internet的非连接请求tcp包；最后一条接收所有udp包，主要是针对oicq等使用udp的服务。 <br /><br />6. 接受来自整个Intranet的数据包过虑，我们定义如下规则： <br /><br />#############Define packets from Internet server to Intranet server############### <br />/sbin/iptables -A FORWARD -s 198.168.80.0/24 -i eth1 -j ACCEPT <br /><br />7. 处理ip碎片 <br /><br />我们接受所有的ip碎片，但采用limit匹配扩展对其单位时间可以通过的ip碎片数量进行限制，以防止ip碎片攻击。 <br /><br />#################################Define fregment rule################################## <br />/sbin/iptables -A FORWARD -f -m limit --limit 100/s --limit-burst 100 -j ACCEPT <br /><br />说明：对不管来自哪里的ip碎片都进行限制，允许每秒通过100个ip碎片，该限制触发的条件是100个ip碎片。 <br /><br />8. 设置icmp包过滤 <br /><br />icmp包通常用于网络测试等，故允许所有的icmp包通过。但是黑客常常采用icmp进行攻击，如ping of death等，所以我们采用limit匹配扩展加以限制： <br /><br />#################################Define icmp rule################################## <br />/sbin/iptables -A FORWARD -p icmp -m limit --limit 1/s --limit-burst 10 -j ACCEPT <br /><br />说明：对不管来自哪里的icmp包都进行限制，允许每秒通过一个包，该限制触发的条件是10个包。 <br /><br /><br />通
过以上个步骤，我们建立了一个相对完整的防火墙。只对外开放了有限的几个端口，同时提供了客户对Internet的无缝访问，并且对ip碎片攻击和
icmp的ping of death提供了有效的防护手段。以下是完整的脚本文件内容，希望通过这个实例能是对iptables的用法有所了解： <br /><br />#!/bin/sh <br /><br />echo "Starting iptables rules..." <br /><br />#Refresh all chains <br /><br />/sbin/iptables -F <br /><br />###########################Define HTTP packets#################################### <br /><br />#Allow www request packets from Internet clients to www servers <br />/sbin/iptables -A FORWARD -p tcp -d 198.168.80.11 --dport www -i eth0 -j ACCEPT <br /><br />############################Define FTP packets##################################### <br /><br />#Allow ftp request packets from Internet clients to Intranet ftp server <br />/sbin/iptables -A FORWARD -p tcp -d 198.168.80.12 --dport ftp -i eth0 -j ACCEPT <br /><br />###########################Define smtp packets#################################### <br />/sbin/iptables -A FORWARD -p tcp -d 198.168.80.13 --dport smtp -i eth0 -j ACCEPT <br /><br />#############Define packets from Internet server to Intranet####################### <br />/sbin/iptables -A FORWARD -p tcp -s 0/0 --sport ftp-data -d 198.168.80.0/24 -i eth0 -j ACCEPT <br />/sbin/iptables -A FORWARD -p tcp -d 198.168.80.0/24 ! -syn -i eth0 -j ACCEPT <br />/sbin/iptables -A FORWARD -p udp -d 198.168.80.0/24 -i eth0 -j ACCEPT <br /><br />#############Define packets from Intranet to Internet############### <br />/sbin/iptables -A FORWARD -s 198.168.80.0/24 -i eth1 -j ACCEPT <br /><br />#################################Define fregment rule################################## <br />/sbin/iptables -A FORWARD -f -m limit --limit 100/s --limit-burst 100 -j ACCEPT <br /><br />#################################Define icmp rule################################## <br />/sbin/iptables -A FORWARD -p icmp -m limit --limit 1/s --limit-burst 10 -j ACCEPT<img src ="http://www.blogjava.net/alex/aggbug/50815.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-06-06 17:05 <a href="http://www.blogjava.net/alex/archive/2006/06/06/50815.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]iptables基础</title><link>http://www.blogjava.net/alex/archive/2006/06/06/50813.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 06 Jun 2006 08:58:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/06/06/50813.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/50813.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/06/06/50813.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/50813.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/50813.html</trackback:ping><description><![CDATA[key words: iptables linux防火墙 防火墙设置<br /><br /><br />
［作者序］：本来是要翻译<a href="http://www.justlinux.com/nhf/Security/IPtables_Basics.html" target="_blank">http://www.justlinux.com/nhf/Security/IPtables_Basics.html</a>这篇文章的，可惜当年实在是没有学好语法，许多句子按照原文翻译，如何也理不通顺。只好按照自己的理解重新组织了，但愿不会有太大的偏差。好在，无论如何，现在读起来，基本通顺了。<img src="http://bbs.linuxsky.net/images/smilies/icon_mrgreen.gif" align="absmiddle" border="0" /><br /><br />
Iptables用三种链来管理放出、进入或经过你计算机的（数据）包。INPUT链管理进入你计算机的包，OUTPUT链管理你计算机放出的包，FORWARD链管理经过你的计算机转送到另一台计算机的包。<br /><br />
所以，设置iptables的过程事实上就是定义一些规则来决定如何处理这三种包的过程。<br /><br />
例如，如果你访问http://www.yahoo.com，你的计算机将放出一个包向Yahoo!请求。这个包就要经过OUTPUT链的审核。内核会浏览OUTPUT链，看看是否有某条规则不允许放出这个包，如果有的话，就拒绝放出。<br /><br />
现在让我们来处理一些实际问题。比如你想阻塞所有来自200.200.200.1的包。首先你需要用-s选项来指明源IP地址或DNS：<br /><center><table style="width: 680px; height: 36px;" border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div class="codetop">CODE:</div><div class="codemain">iptables -s 200.200.200.1</div></td></tr></tbody></table></center><br />然后可以用-j选项来说明如何处理这个包。最常用的处理方式有三种：ACCEPT、DENY和DROP。ACCEPT顾名思义表示接受包，DENY不接受同时回送一条拒绝信息，而DROP则根本对包不予理睬。如果确信某个IP可疑，那么最好选择DROP而不是DENY：<br /><center><table border="0" cellpadding="0" cellspacing="0" width="90%"><tbody><tr><td><div class="codetop">CODE:</div><div class="codemain">iptables -s 200.200.200.1 -j DROP</div></td></tr></tbody></table></center><br />但是仅仅使用上面这条命令，我们的计算机会无所适从，因为它不知道该用哪条链来处理这项规则。这就要用到-A选项，它表示把某条规则追加到某个链的末尾。我们打算拒绝所有来自200.200.200.1的包，所以使用：<br /><center><table border="0" cellpadding="0" cellspacing="0" width="90%"><tbody><tr><td><div class="codetop">CODE:</div><div class="codemain">iptables -A INPUT -s 200.200.200.1 -j DROP</div></td></tr></tbody></table></center><br />选项的顺序不会影响最终的处理结果，-j DROP也可以放在-s 200.200.200.1的前面，只不过放在后面似乎更容易理解。<br />
现在扩展一下，假设我们不想发送任何包给200.200.200.1该如何做呢？很简单，只要把INPUT换成OUTPUT，同时用-d替换-s就可以了：<br /><center><table border="0" cellpadding="0" cellspacing="0" width="90%"><tbody><tr><td><div class="codetop">CODE:</div><div class="codemain">iptables -A OUTPUT -d 200.200.200.1 -j DROP</div></td></tr></tbody></table></center><br />那
么，如果我们打算忽略来自这台机器的telnet请求该怎么办呢？你可能知道telnet使用的是23端口，但是如果你愿意，你也可以在iptables
中使用telnet关键字而不是端口号。Telnet，像大多数服务一样，运行于TCP协议之上。我们可以使用-p选项来指明所用的协议。但是只指明协议
不会有任何作用，还需要使用—destination-port来指出我们要为哪个目标端口指定规则。与之相对应，--source-prot用来指明源
端口，确信别把二者弄混了。所以我们可以这样拒绝某台机器的telnet请求：<br /><center><table border="0" cellpadding="0" cellspacing="0" width="90%"><tbody><tr><td><div class="codetop">CODE:</div><div class="codemain">iptables -A INPUT -s 200.200.200.1 -p tcp --destination-port telnet -j DROP</div></td></tr></tbody></table></center><br />扩展一下，如果你想拒绝一个网段的telnet请求，可以使用200.200.200.0/24来代替上面的200.200.200.1，它匹配任何200.200.200.*这样的IP地址。<br /><br />
再复杂一些。假设我们同时可以连接到本地局域网和internet，eth0网卡用来连接本地局域网，ppp0用来拨号到internet。我们可能只想
为本地局域网提供telnet服务而不想为不安全的internet提供此项服务。有两种选择：在OUTPUT链上用-o选项阻塞设备输出数据，但更好的
是在INPUT链上用-i选项阻塞设备输入数据。因此，这条规则可以这样设置：<br /><center><table border="0" cellpadding="0" cellspacing="0" width="90%"><tbody><tr><td><div class="codetop">CODE:</div><div class="codemain">iptables -A INPUT -p tcp --destination-port telnet -i ppp0 -j DROP</div></td></tr></tbody></table></center><br />这将关闭一切来自internet的telnet请求但是开放局域网同样的请求。<br /><br />
规则可以使用-A选项来追加在规则列表之后
，也可以使用-I选项插入在某条规则之前。例如，如果我们想把一条规则放在INPUT链的最前面，我们可以使用“-I INPUT
1”。其中的1代表规则列表的第一行，你也可以把它换成其它的数字。除此之外，我们还可以使用-R选项来替换某条规则（它将删除原来的规则），-D选项来
删除某条规则，-L选项来列出所有已经设置的规则，-F选项来初始化所有规则。<br /><br />
现在，再深入一步。网络中的数据包通常使用某种协议，如果这种协议是TCP，它还会使用某个端口。你可能想干脆关闭所有端口拒绝进来的包，但是记着，如果
你的计算机同另一台计算机会话，另一台计算机肯定会发送反馈信息。如果你关闭了所有进来的端口，那本质上就表示你的连接就没有用了。而且对于大多数非服务
程序来说，你无法预知它们使用哪个端口进行会话。但是仍然有一种办法。当两台计算机在TCP连接上进行会话时，连接一定会首先被初始化。完成这项任务的包
叫作SYN。一个SYN包简单的表明另一台计算机已经做好了会话的准备。只有发出服务请求的计算机才发送SYN包。所以如果你仅拒绝进来的SYN包，它将
终止其它计算机打开你计算机上的服务，但是不会终止你使用其它计算机上的服务，如果它没有拒绝你发送的SYN包的话。这是一种折衷的办法，但是可以完成许
多我们想完成的任务。这个选项是--syn，用在你指明的TCP协议之后。所以制定一条规则阻塞所有来自internet的连接会是这样：<br /><center><table border="0" cellpadding="0" cellspacing="0" width="90%"><tbody><tr><td><div class="codetop">CODE:</div><div class="codemain">iptables -A INPUT -i ppp0 -p tcp --syn -j DROP</div></td></tr></tbody></table></center><br />这是一条非常有用的规则除非你的计算机运行有web服务。如果你仅打算开放一个端口，比如说80（HTTP），有种简单的办法。和许多编程语言一样，可以用一个惊叹号表示“非”。例如，你打算阻塞所有80端口以外的SYN包，我想会是这样：<br /><center><table border="0" cellpadding="0" cellspacing="0" width="90%"><tbody><tr><td><div class="codetop">CODE:</div><div class="codemain">iptables -A INPUT -i ppp0 -p tcp --syn --destination-port ! 80 -j DROP</div></td></tr></tbody></table></center><br />这稍微有点复杂但并不难理解。<br /><br />
最后，如何改变链的现有规则呢？INPUT链和OUTPUT链通常默认被设置为ACCEPT而FORWARD链默认则被设置为DENY。如果你打算把一台
计算机作为路由器，你可能要设置FORWARD规则为ACCEPT。如何做这个？事实上很简单。只要使用-P选项，在它后面跟上链的名字和你制定的新规则
就可以了。例如，把FORWARD链改为ACCEPT规则，我们这样做：<br /><center><table border="0" cellpadding="0" cellspacing="0" width="90%"><tbody><tr><td><div class="codetop">CODE:</div><div class="codemain">iptables -P FORWARD ACCEPT</div></td></tr></tbody></table></center><img src ="http://www.blogjava.net/alex/aggbug/50813.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-06-06 16:58 <a href="http://www.blogjava.net/alex/archive/2006/06/06/50813.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]RHEL AS 3 安装及启动 Oracle10g 指南</title><link>http://www.blogjava.net/alex/archive/2006/05/09/45191.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 09 May 2006 05:12:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/05/09/45191.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/45191.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/05/09/45191.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/45191.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/45191.html</trackback:ping><description><![CDATA[
		<p>
				<font size="4">
						<strong>转自: <a href="http://blog.csdn.net/casularm/archive/2006/02/22/605382.aspx">这里</a><br /></strong>
				</font>
		</p>
		<p>
				<font size="4">
						<strong>1. 配置RedHat AS 3</strong>
				</font>
		</p>
		<p>
				<font size="3">操作系统版本： <br />Red Hat Enterprise Linux AS release 3 (Taroon)<br />Kernel 2.4.21-4.EL on an i686 <br />按照常规来安装操作系统,记得要安装开发工具(gcc等必要工具). </font>
		</p>
		<p>
				<font size="4">
						<strong>1.1 检查必要的硬件信息</strong>
				</font>
		</p>
		<p>
				<font size="3">
						<table>
								<tbody>
										<tr>
												<td>
														<strong>
																<font size="3">检查内容</font>
														</strong>
												</td>
												<td>
														<strong>
																<font size="3">最小值</font>
														</strong>
												</td>
												<td>
														<strong>
																<font size="3">检查命令参考</font>
														</strong>
												</td>
										</tr>
										<tr>
												<td>
														<font size="3">物理内存</font>
												</td>
												<td>
														<font size="3">512M</font>
												</td>
												<td>
														<font size="3"># grep MemTotal /proc/meminfo </font>
												</td>
										</tr>
										<tr>
												<td>
														<font size="3">交换空间</font>
												</td>
												<td>
														<font size="3">1.0 GB或者2倍内存大小</font>
												</td>
												<td>
														<font size="3"># grep SwapTotal /proc/meminfo </font>
												</td>
										</tr>
										<tr>
												<td>
														<font size="3">/tmp 空间</font>
												</td>
												<td>
														<font size="3">400 MB </font>
												</td>
												<td>
														<font size="3"># df -k /tmp </font>
												</td>
										</tr>
										<tr>
												<td>
														<font size="3">软件所需空间</font>
												</td>
												<td>
														<font size="3">2.5 GB </font>
												</td>
												<td>
														<font size="3"># df -k (空间越大越好,如果是正式系统,应该进行详尽的规划) </font>
												</td>
										</tr>
										<tr>
												<td>
														<font size="3">数据库文件</font>
												</td>
												<td>
														<font size="3">1.2 GB </font>
												</td>
												<td>
														<font size="3"># df -k (空间越大越好,如果是正式系统,应该进行详尽的规划) </font>
												</td>
										</tr>
								</tbody>
						</table>
				</font>
				<font size="3">检查完如上各项之后, 应该修改核心参数.执行如下命令:</font>
		</p>
		<p>
				<font color="#0000ff" size="3">#vi /etc/sysctl.conf</font>
		</p>
		<p>
				<font size="3">#注释:<br />#表示使用root用户操作,$表示使用oracle 用户进行操作.提示符后面的蓝色部分表示需要输入的命令，以下同． </font>
		</p>
		<p>
				<font size="3">在该文件末尾加入如下内容: <br /><font color="#000080">kernel.shmall = 2097152 <br />kernel.shmmax = 2147483648 <br />kernel.shmmni = 4096 <br />kernel.sem = 250 32000 100 128 <br />fs.file-max = 65536 <br />net.ipv4.ip_local_port_range = 1024 65000</font></font>
		</p>
		<p>
				<font size="3">编辑完之后,保存,执行 <font color="#0000ff"># /sbin/sysctl -p</font> 命令操作来使我们所做的变更生效. <br />注:上面kernel.shmmax/kernel.sem等是典型的核心参数配置.您可能需要根据您的实际环境进行适当的变动. </font>
		</p>
		<p>
				<font size="3">关于这些核心参数的说明在Oracle的 Oracle9i Installation Guide Release 2 (9.2.0.1.0) for UNIX Systems 中有很详细的说明.( </font>
				<a href="http://download-west.oracle.com/docs/html/A96167_01/toc.htm">
						<font size="3">http://download-west.oracle.com/docs/html/A96167_01/toc.htm</font>
				</a>
				<font size="3"> ) </font>
		</p>
		<p>
				<font size="3">然后,应该检查一下上面的操作是否正确: <br /><font color="#0000ff"># /sbin/sysctl -a | grep sem <br /># /sbin/sysctl -a | grep shm<br /># /sbin/sysctl -a | grep file-max<br /># /sbin/sysctl -a | grep ip_local_port_range</font></font>
		</p>
		<p>
				<font size="3">为Oracle用户设定Shell的限制<br />一般来说，出于性能上的考虑,还需要需要进行如下的设定，以便改进Oracle用户的有关 nofile(可打开的文件描述符的最大数)和nproc(单个用户可用的最大进程数量)</font>
		</p>
		<p>
				<font size="3">
						<font color="#0000ff"># vi /etc/security/limits.conf</font>
						<br /># 添加如下的行</font>
		</p>
		<p>
				<font color="#000080" size="3">*               soft    nproc   2047<br />*               hard    nproc   16384<br />*               soft    nofile  1024<br />*               hard    nofile  65536</font>
		</p>
		<p>
				<font size="3">添加如下的行到/etc/pam.d/login 文件： <br /><font color="#000080">session    required     /lib/security/pam_limits.so</font></font>
		</p>
		<p>
				<font size="3">编辑 /etc/profile 文件,添加如下部分： <br /><font color="#000080">if [ $USER = "oracle" ]; then  <br />        if [ $SHELL = "/bin/ksh" ]; then  <br />                ulimit -p 16384  <br />                ulimit -n 65536  <br />        else  <br />                ulimit -u 16384 -n 65536  <br />        fi  <br />fi<br /></font>之后，执行<font color="#0000ff">$ ulimit</font> 验证一下.</font>
		</p>
		<p>
				<font size="3">
						<font size="4">
								<strong>1.2 检查并安装相关补丁</strong>
						</font>
						<br />在这个版本的RHEL上安装Oracle,必须要有几个软件包. 确认以下 rpm包都已经安装: </font>
		</p>
		<p>
				<font size="3">make-3.79<br />binutils-2.11<br />openmotif-2.2.2-16<br />setarch-1.3-1 <br />compat-db-4.0.14.5<br />compat-gcc-7.3-2.96.122<br />compat-gcc-c++-7.3-2.96.122<br />compat-libstdc++-7.3-2.96.122<br />compat-libstdc++-devel-7.3-2.96.122</font>
		</p>
		<p>
				<font size="3">
						<font color="#0000ff"># rpm -qa | grep compat</font>
						<br /># 在机器上输出如下:</font>
		</p>
		<p>
				<font color="#800080" size="3">compat-gcc-c++-7.3-2.96.122<br />compat-libstdc++-7.3-2.96.122<br />compat-libstdc++-devel-7.3-2.96.122<br />compat-glibc-7.x-2.2.4.32.5<br />compat-db-4.0.14-5<br />compat-gcc-7.3-2.96.122</font>
		</p>
		<p>
				<font size="3">
						<font color="#0000ff"># rpm -qa | grep openmotif</font>
						<br />
						<font color="#800080">openmotif-devel-2.2.2-16<br />openmotif-2.2.2-16</font>
				</font>
		</p>
		<p>
				<font size="3">
						<font color="#0000ff"># rpm -qa | grep setarch</font>
						<br />
						<font color="#800080">setarch-1.3-1</font>
				</font>
		</p>
		<p>
				<br />
				<font size="3">上面显示的内容是在笔者已经安装了具体的RPM包之后的结果.一般情况下,你的系统上的输出结果和这个不同.如果个别包没有安装,把系统安装光盘mount上,找到具体的软件包(大多数在第三张光盘上),然后利用如下的命令来安装相应的包: <br /><font color="#0000ff"># rpm -ivh *.rpm</font></font>
		</p>
		<p>
				<font size="3">要额外注意的是,这些软件包之间是有依赖性的,先后的顺序要找好.否则会报告不能安装的错误. 此外，最好验证一下 gcc和glibc的版本(要求是gcc-3.2.3-2 或者更高): <br /><font color="#0000ff">#gcc -v <br />#rpm -q glibc</font></font>
		</p>
		<p>
				<font size="3">
						<font size="4">
								<strong>1.3 创建用户和相关的组</strong>
						</font>
						<br />
						<font color="#0000ff"># /usr/sbin/groupadd oinstall<br /># /usr/sbin/groupadd dba<br /># /usr/sbin/useradd -g oinstall -G dba oracle</font>　</font>
		</p>
		<p>
				<font size="3">如果只是测试目的的话，不创建oinstall组也没什么. 不过还是规范一点比较好.如果oracle 用户和dba组等已经存在，作适当的调整即可. </font>
		</p>
		<p>
				<font size="3">
						<font size="4">
								<strong>1.4 检查并调整环境变量</strong>
								<br />
						</font>登录为oracle用户</font>
		</p>
		<p>
				<font color="#0000ff" size="3"># su - oracle<br />$ cd <br />$ vi .bash_profile</font>
		</p>
		<p>
				<font size="3">#添加如下内容,你的具体值应该不会和这个完全相同. <br /><font color="#000080">export ORACLE_BASE=/oracle<br />export ORACLE_HOME=$ORACLE_BASE/product/dbse<br />export ORACLE_SID=orcl<br />export PATH=$PATH:$HOME/bin:$ORACLE_HOME/bin<br />export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/usr/lib<br />export LC_CTYPE=en_US.UTF-8</font></font>
		</p>
		<p>
				<font size="3">然后执行 <br /><font color="#0000ff">$ source .bash_profile</font></font>
		</p>
		<p>
				<font size="3">使环境变量生效. /oracle 等目录应该建立好并做合适的授权. </font>
		</p>
		<p>
				<font size="3">
						<font size="4">
								<strong>2. 安装Orale10g</strong>
						</font>
						<br />mount安装盘.由于10g无法以root安装，以前面建的oracle用户登录.执行:</font>
		</p>
		<p>
				<font size="3">
						<font color="#0000ff">$ ./runInstaller</font>
				</font>
		</p>
		<p>
				<font size="3">按照提示安装即可，最后还需要以root运行两个脚本。</font>
		</p>
		<p>
				<font size="3">
						<font size="4">
								<strong>3. 配置TNS参数</strong>
						</font>
						<br />在 /oracle/product/dbse/network/admin/ 目录下有 listener.ora 和 tnsnames.ora 两个文件，设置如下：</font>
		</p>
		<p>
				<font color="#000080" size="3">#listener.ora<br />SID_LIST_LISTENER =<br />  (SID_LIST =<br />     (SID_DESC =<br />      (GLOBAL_DBNAME = orcl)<br />      (ORACLE_HOME = /oracle/product/dbse)<br />      (SID_NAME = orcl)<br />     )<br />  )</font>
		</p>
		<p>
				<font color="#000080" size="3">LISTENER =<br />  (DESCRIPTION_LIST =<br />    (DESCRIPTION =<br />        (ADDRESS_LIST =<br />      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC))<br />        )<br />        (ADDRESS_LIST =<br />      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.100)(PORT = 1521))<br />        )<br />    )<br />  )</font>
		</p>
		<p>
				<font color="#000080" size="3">#tnsnames.ora<br />ORCL =<br />  (DESCRIPTION =<br />    (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.100)(PORT = 1521))<br />    (CONNECT_DATA =<br />      (SERVER = DEDICATED)<br />      (SERVICE_NAME = orcl)<br />    )<br />  )</font>
		</p>
		<p>
				<font color="#000080" size="3">EXTPROC_CONNECTION_DATA =<br />  (DESCRIPTION =<br />      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC))<br />        (CONNECT_DATA =<br />      (SID = PLSExtProc)<br />      (PRESENTATION = RO)<br />    )<br />  )</font>
		</p>
		<p>
				<font size="3">其中SERVICE_NAME与SID_NAME一定要和.bash_profile中的ORACLE_SID相一致，否则无法启动</font>
		</p>
		<p>
				<font size="3">
						<font size="4">
								<strong>4. 启动Oracle</strong>
						</font>
						<br />以oracle用户登录</font>
		</p>
		<p>
				<font size="3">
						<font size="4">
								<strong>4.1 启动TNS监听器</strong>
						</font>
						<br />
						<font color="#0000ff">$ lsnrctl start<br /></font>出现如下显示，表示监听服务成功开启<br /><font color="#800080">LSNRCTL for Linux: Version 10.2.0.1.0 - Production on 22-FEB-2006 10:24:03</font></font>
		</p>
		<p>
				<font color="#800080" size="3">Copyright (c) 1991, 2005, Oracle.  All rights reserved.</font>
		</p>
		<p>
				<font color="#800080" size="3">Starting /oracle/product/dbse/bin/tnslsnr: please wait...</font>
		</p>
		<p>
				<font color="#800080" size="3">TNSLSNR for Linux: Version 10.2.0.1.0 - Production<br />System parameter file is /oracle/product/dbse/network/admin/listener.ora<br />Log messages written to /oracle/product/dbse/network/log/listener.log<br />Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC)))<br />Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.1.100)(PORT=1521)))</font>
		</p>
		<p>
				<font color="#800080" size="3">Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC)))<br />STATUS of the LISTENER<br />------------------------<br />Alias                     LISTENER<br />Version                   TNSLSNR for Linux: Version 10.2.0.1.0 - Production<br />Start Date                22-FEB-2006 10:24:03<br />Uptime                    0 days 0 hr. 0 min. 0 sec<br />Trace Level               off<br />Security                  ON: Local OS Authentication<br />SNMP                      OFF<br />Listener Parameter File   /oracle/product/dbse/network/admin/listener.ora<br />Listener Log File         /oracle/product/dbse/network/log/listener.log<br />Listening Endpoints Summary...<br />  (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC)))<br />  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.1.100)(PORT=1521)))<br />Services Summary...<br />Service "orcl" has 1 instance(s).<br />  Instance "orcl", status UNKNOWN, has 1 handler(s) for this service...<br />The command completed successfully</font>
		</p>
		<p>
				<br />
				<font size="3">
						<font size="4">
								<strong>4.2启动数据库</strong>
						</font>
				</font>
				<font size="3">
						<br />9i 之后已经没有 svrmgrl 了，所有的管理工作都通过 sqlplus 来完成： <br /><font color="#0000ff">$ sqlplus /nolog <br />SQL&gt; connect system/change_on_install as sysdba <br />SQL&gt; startup</font></font>
		</p>
		<p>
				<font size="3">出现如下显示，表示Oracle已经成功启动<br /><font color="#800080">ORACLE instance started.</font></font>
		</p>
		<p>
				<font color="#800080" size="3">Total System Global Area  285212672 bytes<br />Fixed Size                  1218968 bytes<br />Variable Size              88082024 bytes<br />Database Buffers          188743680 bytes<br />Redo Buffers                7168000 bytes<br />Database mounted.<br />Database opened.</font>
		</p>
		<p>
				<font color="#000000" size="3">
						<strong>4.3 自动启动与关闭</strong>
				</font>
		</p>
		<p>
				<font size="3">编辑 /etc/oratab ，把所有的 instance 的重启动标志设置成 'Y'，如: <br /><font color="#000080">orcl:/oracle/product/dbse:Y</font><br /><br />做一个启动脚本 /etc/init.d/dbora ，如下所示: <br /><br /><font color="#000080">#!/bin/sh <br /># description: Oracle auto start-stop script. <br /># chkconfig: - 20 80 <br /># <br /># Set ORA_HOME to be equivalent to the $ORACLE_HOME <br /># from which you wish to execute dbstart and dbshut; <br /># <br /># Set ORA_OWNER to the user id of the owner of the <br /># Oracle database in ORA_HOME. <br /><br />ORA_HOME=/oracle/product/dbse <br />ORA_OWNER=oracle <br />if [ ! -f $ORA_HOME/bin/dbstart ] <br />then <br />echo "Oracle startup: cannot start" <br />exit <br />fi <br />case "$1" in <br />'start') <br /><br /># Start the Oracle databases: <br /># The following command assumes that the oracle login <br /># will not prompt the user for any values <br /><br />su - $ORA_OWNER -c $ORA_HOME/bin/dbstart <br />su - $ORA_OWNER -c "$ORA_HOME/bin/lsnrctl start" <br />;; <br />'stop') <br /><br /># Stop the Oracle databases: <br /># The following command assumes that the oracle login <br /># will not prompt the user for any values <br /><br />su - $ORA_OWNER -c "$ORA_HOME/bin/lsnrctl stop" <br />su - $ORA_OWNER -c $ORA_HOME/bin/dbshut <br />;; <br />'restart') <br />$0 stop <br />$0 start <br />;; <br />esac <br /></font><br />赋予执行权限 <br /><font color="#0000ff">chmod 750 /etc/init.d/dbora</font><br /><br />作成以下链接: <br /><font color="#0000ff">ln -s /etc/init.d/dbora /etc/rc0.d/K10dbora <br />ln -s /etc/init.d/dbora /etc/rc3.d/S99dbora</font><br /><br />执行以下命令: <br /><font color="#0000ff">chkconfig --level 345 dbora on</font><br /><br />这样就OK了。下次开关机的时候，Oracle也会随之启动/停止。</font>
		</p>
		<p>
				<font size="3">参考信息</font>
		</p>
		<p>
				<font size="3">http://www.dbanotes.net</font>
		</p>
<img src ="http://www.blogjava.net/alex/aggbug/45191.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-05-09 13:12 <a href="http://www.blogjava.net/alex/archive/2006/05/09/45191.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>