کاملترین آموزش رایگان گام به گام مدیریت لینوکس (Linux) | LPIC 1

در این مقاله شما با مدیریت سیستم عامل لینوکس و سفارشی سازی Shell لینوکس (LPIC 1) برای کار با این سیستم عامل آشنا خواهید شد. هر چند برای یادگیری بهتر این موضوع پیشنهاد می کنیم که از دوره های آموزشی لینوکس موجود در قسمت دوره های آموزشی توسینسو استفاده کنید و بصورت اصولی لینوکس یاد بگیرید.

دوره های شبکه، برنامه نویسی، مجازی سازی، امنیت، نفوذ و ... با برترین های ایران

متغیرها

سلام و وقت بخیر. در این دوره میخوایم اصول مدیریت سیستم های لینوکسی با استفاده از ترمینال لینوکس رو توضیح بدیم. مطالبی که ارائه خواهد شد پایه ای ترین مباحث لینوکس خواهند بود و مناسب کسانی که تازه لینوکس رو شروع کردن. سرفصل ها بیشتر جزء lpic1 خواهد بود ولی اگه لازم باشه از lpic2 یا جاهای دیگه هم میگم. کمی پیش زمینه یا مطالعه قبلی داشته باشید بهتره چون مطالب رو از صفر صفر نمیگم. امیدوارم مطالب مفید باشه. بسیار خوب. دستگاه لینوکسی خود را روشن کنید و ترمینال آنرا باز کنید.

SHELL چیست؟

SHELL واسط میان ما و سیستم عامل است. SHELL دستورات را از کاربر گرفته و به زبان سطح پایین قابل فهم برای سیستم عامل ترجمه میکند. SHELL ها میتوانند بصورت رابط خط دستور CLI و یا بصورت رابط گرافیکی GUI باشند. مثلا در ویندوز Command Prompt یا CMD یک SHELL است. در بسیاری از توزیع های لینوکس SHELL پیش فرض BASH است. BASH یک رابط خط دستور است. انواع دیگری از SHELL هم وجود دارد به نام های ksh و csh و bsh و ... که کمتر و در موارد خاص استفاده میشوند و ما بیشتر با همان Bash کار میکنیم.

سلام و وقت بخیر.  در این دوره میخوایم اصول مدیریت سیستم های لینوکسی با استفاده از ترمینال لینوکس رو توصیح بدیم. مطالبی که ارائه خواهد شد پایه ای ترین مباحث لینوکس خواهند بود و مناسب کسانی که تازه لینوکس رو شروع کردن. سرفصل ها بیشتر جزء lpic1 خواهد بود ولی اگه لازم باشه از lpic2 یا جاهای دیگه هم میگم. کمی پیش زمینه یا مطالعه قبلی داشته باشید بهتره چون مطالب رو از صفر صفر نمیگم. امیدوارم مطالب مفید باشه. بسیار خوب. دستگاه لینوکسی خود را روشن کنید و ترمینال آنرا باز کنید.

!! SHELL چیست ؟؟
SHELL واسط میان ما و سیستم عامل است. SHELL دستورات را از کاربر گرفته و به زبان سطح پایین قابل فهم برای سیستم عامل ترجمه میکند. SHELL ها میتوانند بصورت رابط خط دستور CLI و یا بصورت رابط گرافیکی GUI باشند. مثلا در ویندوز Command Prompt یا CMD یک SHELL است. در بسیاری از توزیع های لینوکس SHELL پیش فرض BASH است. BASH یک رابط خط دستور است. انواع دیگری از SHELL هم وجود دارد به نام های ksh و csh و bsh و ... که کمتر و در موارد خاص استفاده میشوند و ما بیشتر با همان Bash کار میکنیم. 
<center>
||http://tosinso.com/files/get/4f311229-cf0a-466f-b5cc-86f6efb2f5e0||
<center>
حال ترمینال سیستم خود را باز کنید. برای اینکه بفهمید از کدام SHELL استفاده میکنید دستور زیر را وارد کنید.

<c#>
[root@CentOS6 ~]# echo $0
bash
[root@CentOS6 ~]# 
<c#>

پس روی سیستم من Bash نصب است. و اگر میخواهید بفهمید که در کجا نصب شده دستور زیر را وارد کنید.

<c#>
[root@CentOS6 ~]# echo $SHELL
/bin/bash
[root@CentOS6 ~]# 
<c#>

!! تعریف متغیر
تعریف متغیر ها در Bash بسیار ساده است. ابتدا نام متغیر و سپس مساوی و مقدار آن. (بدون space). متغیر ها حساس به حروف کوچک و بزرگ هستند، ینی متغیر color با Color فرق دارد. برای چاپ کردن محتوای یک متغیر از کلمه کلیدی echo و علامت $ قبل نام متغیر استفاده میکنیم. برای جدا کردن دستورات از ; استفاده کنید.

<c#>
[root@CentOS6 ~]# color='blue'
[root@CentOS6 ~]# echo $color
blue
[root@CentOS6 ~]# Color='red'
[root@CentOS6 ~]# echo $Color
red
[root@CentOS6 ~]# echo $Color ; echo $color
red
blue
[root@CentOS6 ~]# 
[root@CentOS6 ~]# 
<c#>

از دستور echo برای چاپ انواع خروجی در صفحه استفاده میشود. برای چاپ مقدار محتوای یک متغیر در جمله از ساختار زیر استفاده کنید. به تفاوت دستور ها دقت کنید.

<c#>
[root@CentOS6 ~]# echo my Tshirt is $color
my Tshirt is blue
[root@CentOS6 ~]# echo 'my Tshirt is $color'
my Tshirt is $color
[root@CentOS6 ~]# echo my Tshirt is $color
my Tshirt is blue
[root@CentOS6 ~]# 
<c#>

برای دیدن نام کاربری که با آن وارد شدیم و مسیر home directory آن کاربر میتوانید متغیری که این مقادیر در آنها دخیره شده را چاپ کنید.

<c#>
[root@CentOS6 ~]# echo $USER
root
[root@CentOS6 ~]# echo $HOME
/root
[root@CentOS6 ~]#
<c#>

حال یک Shell دیگر با دستور bash باز کنید. دوباره سعی کنید که متغیر color را چاپ کنید. میبینید که همچین متغیری وجود ندارد. وقتی یک متغیر تعریف میکنیم، فقط در همان شلی که هستیم وجود دارد. برای اینکه متغیر سراسری شود، از دستور export استفاده میکنیم. هر shell یا بهتر بگم هر پروسه یک شماره شناسایی یکتا به نام pid در سیستم دارد با دستور $$ echo میتوان این شماره شناسایی یکتای شلی که در آن هستیم را ببینیم. به کد های زیر دقت کنید.

<c#>
[root@CentOS6 ~]# color=red // یک متغیر تغریف کردم
[root@CentOS6 ~]# echo $$ // چاپ شماره شناسایی شلی که توش هستم
11080 
[root@CentOS6 ~]# bash  // با این دستور یک شل جدید زیر مجموعه این شل درست کردم
[root@CentOS6 ~]# echo $$ حالا شماره این شل جدید رو میخوام
11092
[root@CentOS6 ~]# echo $color // ببینم متغیر اینجا هم هست یا نه 

[root@CentOS6 ~]# exit // خروج از شل زیر مجموعه
exit
[root@CentOS6 ~]# echo $$ // مطمئن بشم تو شل قبلی هستم
11080
[root@CentOS6 ~]# export color // متعیر رو سراسری میکنم
[root@CentOS6 ~]# bash // دوباره یک شل زیرمجموعه میسازم
[root@CentOS6 ~]# echo $$ // میبینم که شماره شناساییش جدیده پس درست ایجاد شده
11101
[root@CentOS6 ~]# echo $color // دوباره ببینم متغیر هست یا نه
red
[root@CentOS6 ~]# 
<c#>

دستور bash اصطلاحا یک subshell میسازد. وجود این subshell وابسته به وجود پدر خود است. اگر پدر از بین رود تمام subshell ها نابود میشوند. با دستور export یک متغیر را در شل پدر در شل های فرزندش کپی کردیم. با دستور ps میتوان دید چه پروسه هایی در حال اجراست. به خوبی مشخص میشود که چند subshell در حال اجرا هستند.

<c#>
[root@CentOS6 ~]# bash
[root@CentOS6 ~]# bash
[root@CentOS6 ~]# bash
[root@CentOS6 ~]# ps
  PID TTY          TIME CMD
11338 pts/0    00:00:00 bash
11348 pts/0    00:00:00 bash
11357 pts/0    00:00:00 bash
11368 pts/0    00:00:00 bash
11377 pts/0    00:00:00 ps
[root@CentOS6 ~]# 
<c#>

با دستور set میتوان تمام متغیر های محلی و سراسری را نشان داد و با دستور env میتوان متغیر های export شده را دید.
خوب برای یک جلسه کافیه. امیدوارم زیاد پیچیدش نکرده باشم. منتظر انتقادات و پیشنهادات اساتید itpro هستیم !!!
پایان قسمت اول از بخش اول

نویسنده : سید محمد باقر موسوی
منبع : |جزیره لینوکس و سیستم های متن باز وب سایت توسینسو::https://linux.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی است

حال ترمینال سیستم خود را باز کنید. برای اینکه بفهمید از کدام SHELL استفاده میکنید دستور زیر را وارد کنید.

[root@CentOS6 ~]# echo $0
bash
[root@CentOS6 ~]# 

پس روی سیستم من Bash نصب است. و اگر میخواهید بفهمید که در کجا نصب شده دستور زیر را وارد کنید.

[root@CentOS6 ~]# echo $SHELL
/bin/bash
[root@CentOS6 ~]# 

آموزش تعریف متغیر در BASH

تعریف متغیر ها در Bash بسیار ساده است. ابتدا نام متغیر و سپس مساوی و مقدار آن. (بدون space). متغیر ها حساس به حروف کوچک و بزرگ هستند، ینی متغیر color با Color فرق دارد. برای چاپ کردن محتوای یک متغیر از کلمه کلیدی echo و علامت $ قبل نام متغیر استفاده میکنیم. برای جدا کردن دستورات از ; استفاده کنید.

[root@CentOS6 ~]# color='blue'
[root@CentOS6 ~]# echo $color
blue
[root@CentOS6 ~]# Color='red'
[root@CentOS6 ~]# echo $Color
red
[root@CentOS6 ~]# echo $Color ; echo $color
red
blue
[root@CentOS6 ~]# 
[root@CentOS6 ~]# 

از دستور echo برای چاپ انواع خروجی در صفحه استفاده میشود. برای چاپ مقدار محتوای یک متغیر در جمله از ساختار زیر استفاده کنید. به تفاوت دستور ها دقت کنید.

[root@CentOS6 ~]# echo "my Tshirt is $color"
my Tshirt is blue
[root@CentOS6 ~]# echo 'my Tshirt is $color'
my Tshirt is $color
[root@CentOS6 ~]# echo my Tshirt is $color
my Tshirt is blue
[root@CentOS6 ~]# 

برای دیدن نام کاربری که با آن وارد شدیم و مسیر home directory آن کاربر میتوانید متغیری که این مقادیر در آنها دخیره شده را چاپ کنید.

[root@CentOS6 ~]# echo $USER
root
[root@CentOS6 ~]# echo $HOME
/root
[root@CentOS6 ~]#

حال یک Shell دیگر با دستور bash باز کنید. دوباره سعی کنید که متغیر color را چاپ کنید. میبینید که همچین متغیری وجود ندارد. وقتی یک متغیر تعریف میکنیم، فقط در همان شلی که هستیم وجود دارد. برای اینکه متغیر سراسری شود، از دستور export استفاده میکنیم. هر shell یا بهتر بگم هر پروسه یک شماره شناسایی یکتا به نام pid در سیستم دارد با دستور $$ echo میتوان این شماره شناسایی یکتای شلی که در آن هستیم را ببینیم. به کد های زیر دقت کنید.

[root@CentOS6 ~]# color=red // یک متغیر تغریف کردم
[root@CentOS6 ~]# echo $$ // چاپ شماره شناسایی شلی که توش هستم
11080 
[root@CentOS6 ~]# bash  // با این دستور یک شل جدید زیر مجموعه این شل درست کردم
[root@CentOS6 ~]# echo $$ حالا شماره این شل جدید رو میخوام
11092
[root@CentOS6 ~]# echo $color // ببینم متغیر اینجا هم هست یا نه 

[root@CentOS6 ~]# exit // خروج از شل زیر مجموعه
exit
[root@CentOS6 ~]# echo $$ // مطمئن بشم تو شل قبلی هستم
11080
[root@CentOS6 ~]# export color // متعیر رو سراسری میکنم
[root@CentOS6 ~]# bash // دوباره یک شل زیرمجموعه میسازم
[root@CentOS6 ~]# echo $$ // میبینم که شماره شناساییش جدیده پس درست ایجاد شده
11101
[root@CentOS6 ~]# echo $color // دوباره ببینم متغیر هست یا نه
red
[root@CentOS6 ~]# 

دستور bash اصطلاحا یک subshell میسازد. وجود این subshell وابسته به وجود پدر خود است. اگر پدر از بین رود تمام subshell ها نابود میشوند. با دستور export یک متغیر را در شل پدر در شل های فرزندش کپی کردیم. با دستور ps میتوان دید چه پروسه هایی در حال اجراست. به خوبی مشخص میشود که چند subshell در حال اجرا هستند.

[root@CentOS6 ~]# bash
[root@CentOS6 ~]# bash
[root@CentOS6 ~]# bash
[root@CentOS6 ~]# ps
  PID TTY          TIME CMD
11338 pts/0    00:00:00 bash
11348 pts/0    00:00:00 bash
11357 pts/0    00:00:00 bash
11368 pts/0    00:00:00 bash
11377 pts/0    00:00:00 ps
[root@CentOS6 ~]# 

با دستور set میتوان تمام متغیر های محلی و سراسری را نشان داد و با دستور env میتوان متغیر های export شده را دید.

تنظیمات Shell

در این جلسه به بررسی بعضی از تنطیمات shell میپردازیم. برای دیدن اینکه shell چه تنظیمانی دارد از دستور زیر استفاده کنید.

[root@CentOS6 ~]# set -o
allexport      	off
braceexpand    	on
emacs          	on
errexit        	off
errtrace       	off
functrace      	off
hashall        	on
histexpand     	on
history        	on
ignoreeof      	off
interactive-comments	on
keyword        	off
monitor        	on
noclobber      	off
noexec         	off
noglob         	off
nolog          	off
notify         	off
nounset        	off
onecmd         	off
physical       	off
pipefail       	off
posix          	off
privileged     	off
verbose        	off
vi             	off
xtrace         	off

برای روشن کردن یک option از set -o به همراه نام option و برای خاموش کردن آن از set +o و نام آن option استفاده میکنیم.

[root@CentOS6 ~]# set -o allexport //روشن کردن
[root@CentOS6 ~]# set +o allexport //خاموش کردن

این allexport باعث میشود اگر یک با چند subshell درست کردیم، بلافاصله تمام متغیر های شل پدر در آن کپی میشود و دیگر نیاز نیست دستی، تک تک متغیر ها را export کنیم.

[root@CentOS6 ~]# set -o allexport
[root@CentOS6 ~]# var1=amy
[root@CentOS6 ~]# var2=taylor
[root@CentOS6 ~]# bash
[root@CentOS6 ~]# echo $var1; echo $var2
amy
taylor
[root@CentOS6 ~]# 

یا مثلا اگر درون یک subshell باشیم، دکمه کنترل و d را فشار دهیم، از subshell خارج میشود. برای خاموش کردن این shortkey از یک option به نام ignoreeof استفاده میکنیم.

[root@CentOS6 ~]# set -o allexport
[root@CentOS6 ~]# var1=amy
[root@CentOS6 ~]# var2=taylor
[root@CentOS6 ~]# bash
[root@CentOS6 ~]# echo $var1; echo $var2
amy
taylor
[root@CentOS6 ~]# 
[root@CentOS6 ~]# exit
[root@CentOS6 ~]# set -o ignoreeof
[root@CentOS6 ~]# bash
[root@CentOS6 ~]# Use "exit" to leave the shell.  //اینجا کنترل و دی زده بودم که خطا داد
[root@CentOS6 ~]# 
[root@CentOS6 ~]# exit // اینجا کلمه خروج رو نوشتم تا خارج بشه
exit
[root@CentOS6 ~]# 
[root@CentOS6 ~]# 

یا یک option دیگر مثل noclober باعث میشود که نتوان در یک فایل overwrite کرد. البته میتوان با کمی تغییر دستور این overwrite را force کرد ولی این option بیشتر جنبه احتیاطی و هشدار دادن دارد. به مثال توجه کنید.

[root@CentOS6 ~]# ls > file1
[root@CentOS6 ~]# ls > file1
[root@CentOS6 ~]# ls > file1   // قبل از روشن کردن میتوان روی فایل قبلی نوشت
[root@CentOS6 ~]# set -o noclobber
[root@CentOS6 ~]# ls > file1
bash: file1: cannot overwrite existing file   // خطا میدهد که نمیتوانید روی فایلی که محتوا دارد بنویسید
[root@CentOS6 ~]# ls > file2
[root@CentOS6 ~]# ls > file2
bash: file2: cannot overwrite existing file
[root@CentOS6 ~]# ls >| file2   // با گذاشتن یک پایپ این عمل نوشتن رو فایل را فورس کردم
[root@CentOS6 ~]# 

ضمیمه : دستور ls محتویات مسیری که هستیم را نشان میدهد. (امتحان کنید). یعنی نام فایل و ها پوشه های مسیری که در آنیم را نشان میدهد. با < خروجی این دستور رو ریختم تو یه فایل یه اسم مثلا file1 .... حالا با دستور cat file1 محتوبات این فایل را ببینید.

[root@CentOS6 ~]# ls
a                d          file1  nohup.out         proje.sh  Templates  VMwareTools-10.0.6-3595377.tar.gz
anaconda-ks.cfg  Desktop    file2  Pictures          Public    test
b                Documents  IFS    post-install      sfk       Videos
c                Downloads  Music  post-install.log  temp      vm
[root@CentOS6 ~]# ls > file1
[root@CentOS6 ~]# cat file1
a
anaconda-ks.cfg
b
c
d
Desktop
Documents
Downloads
file1
file2
IFS
Music
nohup.out
Pictures
post-install
post-install.log
proje.sh
Public
sfk
temp
Templates
test
Videos
vm
VMwareTools-10.0.6-3595377.tar.gz
[root@CentOS6 ~]# 

کوتاه سازی دستورات با Alias ها

یکی از مهم ترین ویژگی های shell شاید alias باشد. alias نشان دهنده دستور است. برای اینکه یک دستور طولانی و یا پیچیده را بصورت کوتاه تر استفاده کنیم، برای آن یک alias نعریف میکنیم. alias مثل یک نام مستعار است. یک نام مستعار کوتاه تر و قابل یادآوری که به جای دستور طولانی یا پیچیده مینشیند. alias در حافظه موقت سیستم ذخیره میشود و با هر بار reboot سیستم مجبوریم آن را دوباره تعریف کنیم مگر اینکه آنرا ذخیره دائمی کرده باشیم. alias قبل از اینکه مسیر PATH برای هر کاربر پردازش شود، چک میشود. یکی از alias های پیش فرض سیستم، دستور ls است. در ترمینال خود type ls را وارد کنید. میبینید که دستور ls در حقیقت یک alias از دستور ls با سویچ اضافه است. به کد های زیر دقت کنید (اگه کد رو کپی میکردم رنگش نمی افتاد.)

در خط اول از دستور ls استفاده کردیم. محتویات درون مسیری که هستیم را نشان میدهد. رنگ آبی نشان دهنده مسیر است. رنگ سیاه یعنی فایل است. اگر هم فایل exe میداشتم سبز نشون میداد. سویچ F- نشان میدهد که جنس خروجی چیست. مثلا اگر directory باشد یک / میگذارد. اگر بخواهیم که دستور در حالت عادی اجرا شود و از alias استفاده نشود، قبل دستور یک \ میگذاریم. میبینید که وقتی \ گذاشتنم دیگه رنگی نشون نمیده. برای دیدن alias ها در ترمینال واژه alias را وارد کنید. لیستی مانند زیر نمایش داده خواهد شد.

سلام و وفت بخیر. یکی از مهم ترین feature های shell شاید alias باشد. alias نشان دهنده دستور است. برای اینکه یک دستور طولانی و یا پیچیده را بصورت کوتاه تر استفاده کنیم، برای آن یک alias نعریف میکنیم. alias مثل یک نام مستعار است. یک نام مستعار کوتاه تر و  قابل یادآوری که به جای دستور طولانی یا پیچیده مینشیند. alias در حافظه موقت سیستم ذخیره میشود و با هر بار reboot سیستم مجبوریم آن را دوباره تعریف کنیم مگر اینکه آنرا ذخیره دائمی کرده باشیم. alias قبل از اینکه مسیر PATH برای هر کاربر پردازش شود، چک میشود. یکی از alias های پیش فرض سیستم، دستور ls است. در ترمینال خود type ls را وارد کنید. میبینید که دستور ls در حقیقت یک alias از دستور ls با سویچ اضافه است. به کد های زیر دقت کنید (اگه کد رو کپی میکردم رنگش نمی افتاد.)

در خط اول از دستور ls استفاده کردیم. محتویات درون مسیری که هستیم را نشان میدهد. رنگ آبی نشان دهنده مسیر است. رنگ سیاه یعنی فایل است. اگر هم فایل exe میداشتم سبز نشون میداد. سویچ F- نشان میدهد که جنس خروجی چیست. مثلا اگر directory باشد یک / میگذارد. اگر بخواهیم که دستور در حالت عادی اجرا شود و از alias استفاده نشود، قبل دستور یک \ میگذاریم. میبینید که وقتی \ گذاشتنم دیگه رنگی نشون نمیده. برای دیدن alias ها در ترمینال واژه alias را وارد کنید. لیستی مانند زیر نمایش داده خواهد شد.
<center>
||http://tosinso.com/files/get/fece897b-c6cc-4aeb-a8de-dd29c4c3f6b0||
<center>
حال میخواهم خودم یک alias ایجاد کنم. کلمه alias را مینویسم، سپس کلمه ای که به عنوان alias در نظر دارم. بعد از آن مساوی و درون ' ' دستور اصلی را وارد میکنم.
<c#>
[root@CentOS6 /]# alias la='ls -al --color=auto'
[root@CentOS6 /]# type la
la is aliased to `ls -al --color=auto'
<c#>
توجه داشته باشید که بصورت پیش فرض در همین ترمینال که هستم فقط این la تعریف شده است. برای از بین بردن alias هم از دستور unalias و نام alias استفاده کنید.
<c#>
[root@CentOS6 ~]# alias la='ls -al --color=auto'
[root@CentOS6 ~]# alias
alias cp='cp -i'
alias l.='ls -d .* --color=auto'
alias la='ls -al --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
[root@CentOS6 ~]# unalias la
[root@CentOS6 ~]# alias
alias cp='cp -i'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
[root@CentOS6 ~]# 
<c#>
حاا این تنظیمات alias کجا ذخیره میشود؟؟ اگر شما هم مثل من از centos و یا یکی از توزیع های Red Hat استفاده میکنید، در مسیر home directory هر کاربر ( حتی root ) یک فایل به نام bashrc. وجود دارد. این فایل را باز کنید (با دستور cat) تا alias های دائمی را ببینید. برای اینکه یک alias همیشگی شود، آنرا در این فایل بنویسید. میتوانید از vim و یا gedit برای ویرایش این فایل استفاده کنید.  با دستور ( vim .bashrc یا  gedit .bashrc )

<c#>
[root@CentOS6 ~]# whoami
root
[root@CentOS6 ~]# pwd
/root
[root@CentOS6 ~]# cat .bashrc
# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# Source global definitions
if [ -f /etc/bashrc ]; then
	. /etc/bashrc
fi
[root@CentOS6 ~]# 
[root@CentOS6 ~]# cd /home/mohammad/
[root@CentOS6 mohammad]# cat .bashrc
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
	. /etc/bashrc
fi

# User specific aliases and functions
[root@CentOS6 mohammad]# 
<c#>
همانطور که در شکل مشخص است برای root سه تا alias پیش فرض وجود دارد ولی برای کاربر mohammad هنوز هیچ alias ثبت نشده است. ( فایل هایی مثل bashrc. که قبلشان نقطه است، اصطلاحا فایل های سیستمی هستند. ) تمرین : برای یک کاربر غیر از root یک alias درست کرده و برای همیشه آنرا ذخیره کنید. میتوانید از دستور << برای اضافه کردن ( append کردن) به انتهای فایل bashrc. استفاده کنید. 

پایان قسمت سوم از بخش اول

نویسنده : سید محمد باقر موسوی
منبع : |جزیره لینوکس و سیستم های متن باز وب سایت توسینسو::https://linux.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی است

حال میخواهم خودم یک alias ایجاد کنم. کلمه alias را مینویسم، سپس کلمه ای که به عنوان alias در نظر دارم. بعد از آن مساوی و درون ' ' دستور اصلی را وارد میکنم.

[root@CentOS6 /]# alias la='ls -al --color=auto'
[root@CentOS6 /]# type la
la is aliased to `ls -al --color=auto'

توجه داشته باشید که بصورت پیش فرض در همین ترمینال که هستم فقط این la تعریف شده است. برای از بین بردن alias هم از دستور unalias و نام alias استفاده کنید.

[root@CentOS6 ~]# alias la='ls -al --color=auto'
[root@CentOS6 ~]# alias
alias cp='cp -i'
alias l.='ls -d .* --color=auto'
alias la='ls -al --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
[root@CentOS6 ~]# unalias la
[root@CentOS6 ~]# alias
alias cp='cp -i'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
[root@CentOS6 ~]# 

حاا این تنظیمات alias کجا ذخیره میشود؟؟ اگر شما هم مثل من از centos و یا یکی از توزیع های Red Hat استفاده میکنید، در مسیر home directory هر کاربر ( حتی root ) یک فایل به نام bashrc. وجود دارد. این فایل را باز کنید (با دستور cat) تا alias های دائمی را ببینید. برای اینکه یک alias همیشگی شود، آنرا در این فایل بنویسید. میتوانید از vim و یا gedit برای ویرایش این فایل استفاده کنید. با دستور ( vim .bashrc یا gedit .bashrc )

[root@CentOS6 ~]# whoami
root
[root@CentOS6 ~]# pwd
/root
[root@CentOS6 ~]# cat .bashrc
# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# Source global definitions
if [ -f /etc/bashrc ]; then
	. /etc/bashrc
fi
[root@CentOS6 ~]# 
[root@CentOS6 ~]# cd /home/mohammad/
[root@CentOS6 mohammad]# cat .bashrc
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
	. /etc/bashrc
fi

# User specific aliases and functions
[root@CentOS6 mohammad]# 

همانطور که در شکل مشخص است برای root سه تا alias پیش فرض وجود دارد ولی برای کاربر mohammad هنوز هیچ alias ثبت نشده است. ( فایل هایی مثل bashrc. که قبلشان نقطه است، اصطلاحا فایل های سیستمی هستند. ) تمرین : برای یک کاربر غیر از root یک alias درست کرده و برای همیشه آنرا ذخیره کنید. میتوانید از دستور << برای اضافه کردن ( append کردن) به انتهای فایل bashrc. استفاده کنید.

اسکریپت های ورود

همانطور که کمی در قسمت قبل اشاره کردیم، برای اینکه Alias ها از بین نروند باید آنها را در bashrc. ذخیره کرد. در کل 2 فایل وجود دارد که این اطلاعات environment (منظور محیطی که توش هستیم) را نگه میدارد. اصطلاحا به این 2 فایل "Login Scripts" گفته میشود. با یکی از آنها آشنا شدیم که bashrc. نام دارد. دیگری bash_profile. نام دارد که این فایل هم در hone directory هر کاربر قرار دارد.

حال هر کدام چه نقشی بازی میکنند؟ bash_profile. ===>> این فایل فقط یک بار آن هم در هنگام log in خوانده میشود. میتواند به PATH هر کاربر Append شود. bashrc. ===>> هر بار که یک bash جدید باز میکنیم، خوانده میشود. برای تعریف متغیر ها و یا شخصی سازی prompt میتوان از آن استفاده کرد. به دستورات زیر دقت کنید.

[root@CentOS6 mohammad]# pwd
/home/mohammad
[root@CentOS6 mohammad]# ls -a .bash*
.bash_history  .bash_logout  .bash_profile  .bashrc
[root@CentOS6 mohammad]# 
  • فایل bash_history. دستوراتی که این کاربر زده را نگه میدارد.
  • فایل bash_logout. اسکریپت های log out را نگه میدارد. مثلا اگر بخواهیم هنگام خروج یک کاربر دستوراتی اجرا شود در این فایل میگذاریم. مثلا اگر بخواهیم هنگامی که کاربر خارج میشود تاریخچه دستوراتی که وارد کرده پاک شود، دستورات لازم را اینجا میگذاریم.
  • فایل bash_profile. یک بار آن هم هنگام log in خوانده میشود.
  • فایل bashrc. میتواند بارها بعد از log in خوانده شود. بیشتر تنظیمات سفارشی کردن shell در این فایل انجام میشود.

بیایید نگاهی به محتویات bash_profile. بیندازیم.

[mohammad@CentOS6 ~]$ echo $HOME
/home/mohammad
[mohammad@CentOS6 ~]$ pwd
/home/mohammad
[mohammad@CentOS6 ~]$ cat .bash_profile 
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
	. ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/bin

export PATH
[mohammad@CentOS6 ~]$ 
[mohammad@CentOS6 ~]$ 


دلیل اینکه این فایل یک بار خوانده میشود این است که وقتی کاربر وارد شد، برای او یک متغیر PATH تنظیم میشود. یک الگوی ثابت برای PATH وجود دارد و برای هر کاربر از این الگوی ثابت به اضافه مسیر bin که در home directory کاربر وجود دارد استفاده میشود. دقت کنید که متغیر PATH برابر مقدار پیش فرض خود به اضافه HOMEbin$ شده. منطقش اینه که PATH برابر خودش ( PATH=$PATH ) ، به اضافه HOME/bin$ که مقدار HOME$ را میبینید. از : برای جدا کردن مقادیر PATH استفاده میشود. شاید ندانید PATH چیست. در واقع PATH آدرس تمام دستوراتی است که یک کاربر میتواند اجرا کند، شامل کتابخانه ها و ... .

[mohammad@CentOS6 ~]$ 
[mohammad@CentOS6 ~]$ echo  $PATH
/usr/lib/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/mohammad/bin
[mohammad@CentOS6 ~]$ 
[mohammad@CentOS6 ~]$ 

به قسمت آخر PATH دقت کنید. اوت تیکه رو فایل bash-profile. درست کرده. این تعریف PATH فقط یکبار اتفاق میفته برای همین توی bash-profile. نوشته شده. اگه دوباره bash-profile. اجرا بشه، الکی طول این PATH زیاد میشه. ( شاید مشکلات دیگه ای هم باشه که من نمیدونم ). در قسمت بالای bash-profile. هم چک میکند که اگر bashrc. وجود دارد آنرا اجرا کند. برای همین بیشتر تنظیمات shell را در bashrc. میگذاریم. حال یه نگاهی هم به bashrc. بیندازیم.

[mohammad@CentOS6 ~]$ cat .bashrc
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
	. /etc/bashrc
fi

# User specific aliases and functions
[mohammad@CentOS6 ~]$ 
[mohammad@CentOS6 ~]$ 


در قسمت بالای فایل ابتدا چک میکند که آیا فایل bashrc. سراسری وجود دارد یا نه، اگر باشد آنرا میخواند. bashrc. سراسری برای تنظیمات shell همه کاربران است. برای همین در مسیر etc قرار دارد. مثلا اگر بخواهیم یک alias برای همه کاربران تعریف شود، آنرا در bashrc.

سراسری واقع در پوشه etc تعریف میکنیم. یا مثلا اگر خواستیم که هیچ کاربری نتواند هیچ فایلی را overwrite کند دستورش را در bashrc. سراسری وارد میکنیم. حال اگر خواستیم فایل bashrc. دوباره خوانده شود، مثلا تغییراتی در آن داده ایم، از یکی از 2 دستور زیر استفاده کنید. ممکن است هشداری مبنی بر تنظیمات جدید در سیستم دهد.

[mohammad@CentOS6 ~]$ . .bashrc
[mohammad@CentOS6 ~]$ source .bashrc


مثلا :

[mohammad@CentOS6 ~]$ echo "set -o noclobber" >> .bashrc
[mohammad@CentOS6 ~]$ source .bashrc
[mohammad@CentOS6 ~]$ cat .bashrc
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
	. /etc/bashrc
fi

# User specific aliases and functions

set -o noclobber
[mohammad@CentOS6 ~]$ ls > file1
[mohammad@CentOS6 ~]$ ls > file1
-bash: file1: cannot overwrite existing file
[mohammad@CentOS6 ~]$ 


ایجاد اسکریپت

در این بخش به بررسی اصول نوشتن Shell Script در لینوکس میپردازیم. برای نوشتن یک برنامه تحت Shell به نکات زیر توجه کنید.

  1. معمولا انتهای نام های برنامه های تحت Shell یک sh. میگذارند. این sh. به معنای پسوند فایل نیست. بر خلاف ویندوز که پسوند فایل ها در نام فابل مشخص میشود، در لینوکس پسوند فایل ها در متا دیتای فایل ذخیره میشود. این گذاشتن sh. فقط برای تفهیم کاربر است. مثلا برای برنامه های پایتون py. میگذاریم. گذاشتن و نذاشتن این اسامی تاثیری در اجرا و عملکرد برنامه ندارد. فقط برای اینکه خودمون متوجه بشیم محتویات و جنس فایل ها چیست به درد میخورد.
  2. مشخص کردن مسیر برای تفسیر برنامه، باید به سیستم عامل بگوییم از چه کتابخانه هایی برای خواندن و اجرای برنامه استفاده کند.
  3. فایل ها به طور پیش فرض executable نیستند، پس از نوتشن کد ها در یک فایل خالی، باید به فایل خاصیت exe بودن بدهیم.
  4. اگر لازم بود که برنامه را بتوان در هر مسیری اجرا کرد و از همه جا قابل اجرا کردن باشد، مسیر پوشه برنامه باید به PATH کاربر افزوده شود. این قسمت اجباری نیست. اگر این کار را نکنیم، برای اجرای برنامه لازم است آدرس absolute بدهیم، همین. ولی اگر در PATH کاربر هم تعریف شده باشد، در هر مسیری با نوشتن نام برنامه، برنامه اجرا میشود.

موارد بالا برای نوشتن هر نوع برنامه ای به هر زبانی در لینوکس است. چه پایتون، چه C، چه پرل و ... بریم سراغ اصل کار. به کد های زیر توجه کنید. برای کاربری که با نام آن وارد سیستم شدم، متغیر PATH را نگاه میکنم، قسمت آخر متغیر PATH را نگاه کنید. همان قسمتی بود که توسط bash-profile ایجاد شده بود. این مسیر بطور پیش فرض وجود ندارد. یعنی نمیتوانم به آن cd کنم ولی در PATH وجود دارد.

یعنی هر بار که دستوری زده میشود، این مسیر هم توسط سیستم عامل چک میشود. میتوان این پوشه را با دستور mkdir درست کرد. راحت تر است که برای نوشتن برنامه ها از این مسیر استفاده کنیم و فایل های برنامه را اینجا ذخیره کنیم، چون بصورت پیش قرض در PATH وجود داردو هر جای دیگر هم میتوان برنامه ها را ذخیره کرد. میتوان هر مسیری را هم به PATH اضافه کرد. این کاملا به شما بستگی دارد. فقط همانطور که گفتم اگر مسیر برنامه در PATH باشد، در هر مسیری قایل اجراست ولی اگر مسیر برنامه در PATH نباشد، برای اجرای آن باید آدرس absolute (یعنی آدرس از ریشه) بدهیم.

[mohammad@CentOS6 ~]$ pwd
/home/mohammad
[mohammad@CentOS6 ~]$ echo $PATH
/usr/lib/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/mohammad/bin
[mohammad@CentOS6 ~]$ cd bin
-bash: cd: bin: No such file or directory
[mohammad@CentOS6 ~]$ mkdir bin
[mohammad@CentOS6 ~]$ cd bin
[mohammad@CentOS6 bin]$ pwd
/home/mohammad/bin                 //برنامه ها را اینجا ذخیره میکنیم
[mohammad@CentOS6 bin]$ 

بسیار خوب ، بیاید یم مثال ساده رو اجرا کنیم. به کد زیر دقت کنید.

[mohammad@CentOS6 bin]$ vim hello.sh
[mohammad@CentOS6 bin]$ ls -l hello.sh 
-rw-rw-r--. 1 mohammad mohammad 44 Aug 18 13:45 hello.sh
[mohammad@CentOS6 bin]$ chmod +x hello.sh
[mohammad@CentOS6 bin]$ hello.sh 
We are ITPRO!!!
[mohammad@CentOS6 bin]$ ls -l hello.sh 
-rwxrwxr-x. 1 mohammad mohammad 44 Aug 18 13:45 hello.sh
[mohammad@CentOS6 bin]$ cd ~
[mohammad@CentOS6 ~]$ hello.sh 
We are ITPRO!!!
[mohammad@CentOS6 ~]$ 
[mohammad@CentOS6 ~]$ 
[mohammad@CentOS6 ~]$ bash -x bin/hello.sh
+ echo 'We are ITPRO!!!'
We are ITPRO!!!
+ exit 0
[mohammad@CentOS6 ~]$ 
[mohammad@CentOS6 ~]$ 

در همان مسیری که بودم با استفاده از vim یا gedit یک سند خالی درست کردم. درون آن کد ها زیر را وارد کردم.

#!/bin/bash

echo "We are ITPRO!!!"

exit 0

در خط اول به سیستم عامل میگوییم برای خواندن و اجرای برنامه از چه کتابخانه ای استفاده کند. مسیر نصب bash را وارد کردم. اگر داشتم پایتون مینوشتم مسیر نصب پایتون رو میدادم. خط بعد با دستور echo یک جمله را در خروجی چاپ کردم. در خط آخر هم گفتم 0 را برگردان. 0 به معنی اجرای صحیح برنامه است.

سپس برنامه را ذخیره کرده و خارج میشم. اگر با دستور ls جزئیات فایل hello.sh را چاپ کنم، متوجه میشوم که خاصیت exe یعنی خاصیت اجرایی ندارد. با دستور chmod این فایل را exe میکنم تا از حالت فقط متنی خارج شود. حالا اگر نام برنامه را بزنم، برنامه اجرا میشود. حتی اگر مسیرم را با دستور cd عوض کنم باز هم برنامه اجرا میشود. برای debug کردن یک برنامه از دستور bash و سویچ x- استفاده کنید.

دریافت ورودی از کاربر

مسلما ما فقط نمی خواهیم که برنامه یک رشته از قبل تعریف شده را چاپ کند. برنامه ما باید بتواند ورودی هم بگیرد. برای خواندن ورودی میتوان از 2 روش کلی استفاده کرد:

  1. دستور read
  2. Positional Parameters

دستور read دقیقا مثل دستور scanf در C و یا cin در ++C است. این دستور مقداری را از صفحه کلید کاربر میگیرد. به مثال ساده زیر توجه کنید. همان سندی که جلسه قبل ایجاد کردید را با vim یا gedit باز کنید و کد های زیر را درون آن بنویسید.

#!/bin/bash

echo -e "Enter your name: \c"

read INPUT_NAME

echo "Hello $INPUT_NAME"

exit 0

خروجی بصوزت زیر خواهد بود:

[mohammad@CentOS6 bin]$ hello.sh 
Enter your name: Mohammad
Hello Mohammad

دستور echo را با سویچ e- وارد کردیم و یک c\ گداشتیم. اگر از کاراکتر های خاص مثل c\ استفاده میکنیم باید e- بگذاریم. با این c\ برنامه تا زمان گرفتن ورودی جلو تر نمی رود. ( به صفحه manual این دستور مراجعه کنید. توضیح بیشترم نمیاد !!! ) با دستور read ورودی را از کاربر گرفته و درون یک متغیر میریزد. در آخر هم یک رشته را با متغیر پر شده توسط کاربر چاپ کردیم.

خوب برویم سراغ روش دوم. به تصویر زیر دقت کنید. وقتی که نام یک اسکریپت را در ترمینال برای اجرا میزنید، عباراتی که جلوی آن مینویسید، حکم آرگومان ارسالی برای برنامه را دارند. به ترتیب از یک این آرگومان ها شماره میگیرند و در برنامه میتوان آنها را استفاده کرد.

سلام و وقت بخیر. مسلما ما فقط نمی خواهیم که برنامه یک رشته از قبل تعریف شده را چاپ کند. برنامه ما باید بتواند ورودی هم بگیرد. برای خواندن ورودی میتوان از 2 روش کلی استفاده کرد:
1- دستور read
2- Positional Parameters
دستور read دقیقا مثل دستور scanf در C و یا cin در ++C است. این دستور مقداری را از صفحه کلید کاربر میگیرد. به مثال ساده زیر توجه کنید. همان سندی که جلسه قبل ایجاد کردید را با vim یا gedit باز کنید و کد های زیر را درون آن بنویسید.

<c#>
#!/bin/bash

echo -e Enter your name: \c

read INPUT_NAME

echo Hello $INPUT_NAME

exit 0
<c#>

خروجی بصوزت زیر خواهد بود:

<c#>
[mohammad@CentOS6 bin]$ hello.sh 
Enter your name: Mohammad
Hello Mohammad
<c#>

دستور echo را با سویچ e- وارد کردیم و یک c\ گداشتیم. اگر از کاراکتر های خاص مثل c\ استفاده میکنیم باید e- بگذاریم. با این c\ برنامه تا زمان گرفتن ورودی جلو تر نمی رود. ( به صفحه manual این دستور مراجعه کنید. توضیح بیشترم نمیاد !!! ) با دستور read ورودی را از کاربر گرفته و درون یک متغیر میریزد. در آخر هم یک رشته را با متغیر پر شده توسط کاربر چاپ کردیم.
خوب برویم سراغ روش دوم. به تصویر زیر دقت کنید. وقتی که نام یک اسکریپت را در ترمینال برای اجرا میزنید، عباراتی که جلوی آن مینویسید، حکم آرگومان ارسالی برای برنامه را دارند. به ترتیب از یک این آرگومان ها شماره میگیرند و در برنامه میتوان آنها را استفاده کرد. 
<center>
||http://tosinso.com/files/get/291cd852-eae1-4879-8351-effc9707150e||
<center>
<center>
||http://tosinso.com/files/get/5e57015e-e5b8-48d0-ab45-5c4ab67a3216||
<center>

به قطعه کد زیر دقت کنید، همان سند قبلی را اینطور تغییر دادم:

<c#>
#!/bin/bash

echo This is 1st arg: $1
echo This is 2nd arg: $2
echo This is 3rd arg: $3
echo This is 4th arg: $4
echo This is 5th arg: $5
echo This is 6th arg: $6

echo This is Script's name: $0

exit 0
<c#>

حالا من 6 تا آرگومان نوشتم، شما بیشتر هم میتونید استفاه کنید. حالا برای پاس دادن مقادیر به برنامه، عبارات را در مقابل نام برنامه وارد میکنیم. 

<c#>
[mohammad@CentOS6 bin]$ hello.sh centos redhat mint kali debian arch
This is 1st arg: centos
This is 2nd arg: redhat
This is 3rd arg: mint
This is 4th arg: kali
This is 5th arg: debian
This is 6th arg: arch
This is Script's name: /home/mohammad/bin/hello.sh
[mohammad@CentOS6 bin]$ 
<c#>

مطلب بسیار ساده است. سعی کنید برای خود مثال های بیشتری طراحی کنید. حالا بیاید یک نکته ریز را بررسی کنیم. #$ و @$ هر دو مقادیر آرگومانها را نگه میدارند. ولی تفاوت آنها در چیست؟؟ مثال زیر را ببینید. در حقیقت *$ یک single string است. در حالی که #$ یک آرایه ( array ) است.

<c#>
#!/bin/bash

echo This is counts of parameters: $#

echo Using \\$*\:
for a in $*; do
    echo >$a;
done

echo -e \nUsing \$*:
for a in $*; do
    echo >$a;
done

echo -e \nUsing \\$@\:
for a in $@; do
    echo >$a;
done

echo -e \nUsing \$@:
for a in $@; do
    echo >$a;
done

exit 0
<c#>

حال اگر به این برنامه ورودی بدهیم: 

<c#>
[mohammad@CentOS6 bin]$ hello.sh one two three four five six
This is counts of parameters: 5
Using $*:
>one two three four five six

Using $*:
>one
>two
>three
>four
>five
>six

Using $@:
>one
>two
>three
>four five
>six

Using $@:
>one
>two
>three
>four
>five
>six
[mohammad@CentOS6 bin]$ 
<c#>

فکر میکنم جای توضیح ندارد. فقط از حلقه for استفاده کردم. ساختار for به این صورت است که گفته به ازای تک تک مقادیر #$ یا *$ ، مقدار آنها درون a ریخته شود، درون بدنه for این متغیر a را چاپ کردم. مثلا میتوانید خروجی هر دستوری را وارد حلقه for کنید. مثلا اگر من بزنم `for var in `ls درون حلقه for مقدار متغیر var برابر با هر خط خروجی دستور ls خواهد بود. مثلا اگه بخوام روی همه فایل های یک پوشه کاری انجام بدم از این روش میشه استفاده کرد. منظورم یه همچین چیزیه:

<c#>
for var in `ls`
do
echo $var
done
<c#>

مثلا این الان محتوبات داخل مسیر رو نشون میده.
امیدوارم مبحث پیچیده نبوده باشه... منم هیچ فید بکی نمیگیرم نمیدونم اصن اینایی که میگم به درد میخوره یا نه ... ولی امیدوارم مفید باشه.
پایان قسمت دوم از بخش دوم

نویسنده : سید محمد باقر موسوی
منبع : |جزیره لینوکس و سیستم های متن باز وب سایت توسینسو::https://linux.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی است
سلام و وقت بخیر. مسلما ما فقط نمی خواهیم که برنامه یک رشته از قبل تعریف شده را چاپ کند. برنامه ما باید بتواند ورودی هم بگیرد. برای خواندن ورودی میتوان از 2 روش کلی استفاده کرد:
1- دستور read
2- Positional Parameters
دستور read دقیقا مثل دستور scanf در C و یا cin در ++C است. این دستور مقداری را از صفحه کلید کاربر میگیرد. به مثال ساده زیر توجه کنید. همان سندی که جلسه قبل ایجاد کردید را با vim یا gedit باز کنید و کد های زیر را درون آن بنویسید.

<c#>
#!/bin/bash

echo -e Enter your name: \c

read INPUT_NAME

echo Hello $INPUT_NAME

exit 0
<c#>

خروجی بصوزت زیر خواهد بود:

<c#>
[mohammad@CentOS6 bin]$ hello.sh 
Enter your name: Mohammad
Hello Mohammad
<c#>

دستور echo را با سویچ e- وارد کردیم و یک c\ گداشتیم. اگر از کاراکتر های خاص مثل c\ استفاده میکنیم باید e- بگذاریم. با این c\ برنامه تا زمان گرفتن ورودی جلو تر نمی رود. ( به صفحه manual این دستور مراجعه کنید. توضیح بیشترم نمیاد !!! ) با دستور read ورودی را از کاربر گرفته و درون یک متغیر میریزد. در آخر هم یک رشته را با متغیر پر شده توسط کاربر چاپ کردیم.
خوب برویم سراغ روش دوم. به تصویر زیر دقت کنید. وقتی که نام یک اسکریپت را در ترمینال برای اجرا میزنید، عباراتی که جلوی آن مینویسید، حکم آرگومان ارسالی برای برنامه را دارند. به ترتیب از یک این آرگومان ها شماره میگیرند و در برنامه میتوان آنها را استفاده کرد. 
<center>
||http://tosinso.com/files/get/291cd852-eae1-4879-8351-effc9707150e||
<center>
<center>
||http://tosinso.com/files/get/5e57015e-e5b8-48d0-ab45-5c4ab67a3216||
<center>

به قطعه کد زیر دقت کنید، همان سند قبلی را اینطور تغییر دادم:

<c#>
#!/bin/bash

echo This is 1st arg: $1
echo This is 2nd arg: $2
echo This is 3rd arg: $3
echo This is 4th arg: $4
echo This is 5th arg: $5
echo This is 6th arg: $6

echo This is Script's name: $0

exit 0
<c#>

حالا من 6 تا آرگومان نوشتم، شما بیشتر هم میتونید استفاه کنید. حالا برای پاس دادن مقادیر به برنامه، عبارات را در مقابل نام برنامه وارد میکنیم. 

<c#>
[mohammad@CentOS6 bin]$ hello.sh centos redhat mint kali debian arch
This is 1st arg: centos
This is 2nd arg: redhat
This is 3rd arg: mint
This is 4th arg: kali
This is 5th arg: debian
This is 6th arg: arch
This is Script's name: /home/mohammad/bin/hello.sh
[mohammad@CentOS6 bin]$ 
<c#>

مطلب بسیار ساده است. سعی کنید برای خود مثال های بیشتری طراحی کنید. حالا بیاید یک نکته ریز را بررسی کنیم. #$ و @$ هر دو مقادیر آرگومانها را نگه میدارند. ولی تفاوت آنها در چیست؟؟ مثال زیر را ببینید. در حقیقت *$ یک single string است. در حالی که #$ یک آرایه ( array ) است.

<c#>
#!/bin/bash

echo This is counts of parameters: $#

echo Using \\$*\:
for a in $*; do
    echo >$a;
done

echo -e \nUsing \$*:
for a in $*; do
    echo >$a;
done

echo -e \nUsing \\$@\:
for a in $@; do
    echo >$a;
done

echo -e \nUsing \$@:
for a in $@; do
    echo >$a;
done

exit 0
<c#>

حال اگر به این برنامه ورودی بدهیم: 

<c#>
[mohammad@CentOS6 bin]$ hello.sh one two three four five six
This is counts of parameters: 5
Using $*:
>one two three four five six

Using $*:
>one
>two
>three
>four
>five
>six

Using $@:
>one
>two
>three
>four five
>six

Using $@:
>one
>two
>three
>four
>five
>six
[mohammad@CentOS6 bin]$ 
<c#>

فکر میکنم جای توضیح ندارد. فقط از حلقه for استفاده کردم. ساختار for به این صورت است که گفته به ازای تک تک مقادیر #$ یا *$ ، مقدار آنها درون a ریخته شود، درون بدنه for این متغیر a را چاپ کردم. مثلا میتوانید خروجی هر دستوری را وارد حلقه for کنید. مثلا اگر من بزنم `for var in `ls درون حلقه for مقدار متغیر var برابر با هر خط خروجی دستور ls خواهد بود. مثلا اگه بخوام روی همه فایل های یک پوشه کاری انجام بدم از این روش میشه استفاده کرد. منظورم یه همچین چیزیه:

<c#>
for var in `ls`
do
echo $var
done
<c#>

مثلا این الان محتوبات داخل مسیر رو نشون میده.
امیدوارم مبحث پیچیده نبوده باشه... منم هیچ فید بکی نمیگیرم نمیدونم اصن اینایی که میگم به درد میخوره یا نه ... ولی امیدوارم مفید باشه.
پایان قسمت دوم از بخش دوم

نویسنده : سید محمد باقر موسوی
منبع : |جزیره لینوکس و سیستم های متن باز وب سایت توسینسو::https://linux.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی است

به قطعه کد زیر دقت کنید، همان سند قبلی را اینطور تغییر دادم:

#!/bin/bash

echo "This is 1st arg: $1"
echo "This is 2nd arg: $2"
echo "This is 3rd arg: $3"
echo "This is 4th arg: $4"
echo "This is 5th arg: $5"
echo "This is 6th arg: $6"

echo "This is Script's name: $0"

exit 0

حالا من 6 تا آرگومان نوشتم، شما بیشتر هم میتونید استفاه کنید. حالا برای پاس دادن مقادیر به برنامه، عبارات را در مقابل نام برنامه وارد میکنیم.

[mohammad@CentOS6 bin]$ hello.sh centos redhat mint kali debian arch
This is 1st arg: centos
This is 2nd arg: redhat
This is 3rd arg: mint
This is 4th arg: kali
This is 5th arg: debian
This is 6th arg: arch
This is Script's name: /home/mohammad/bin/hello.sh
[mohammad@CentOS6 bin]$ 

مطلب بسیار ساده است. سعی کنید برای خود مثال های بیشتری طراحی کنید. حالا بیاید یک نکته ریز را بررسی کنیم. #$ و @$ هر دو مقادیر آرگومانها را نگه میدارند. ولی تفاوت آنها در چیست؟؟ مثال زیر را ببینید. در حقیقت *$ یک single string است. در حالی که #$ یک آرایه ( array ) است.

#!/bin/bash

echo "This is counts of parameters: $#"

echo "Using \"\$*\":"
for a in "$*"; do
    echo ">"$a;
done

echo -e "\nUsing \$*:"
for a in $*; do
    echo ">"$a;
done

echo -e "\nUsing \"\$@\":"
for a in "$@"; do
    echo ">"$a;
done

echo -e "\nUsing \$@:"
for a in $@; do
    echo ">"$a;
done

exit 0

حال اگر به این برنامه ورودی بدهیم:

[mohammad@CentOS6 bin]$ hello.sh one two three "four five" six
This is counts of parameters: 5
Using "$*":
>one two three four five six

Using $*:
>one
>two
>three
>four
>five
>six

Using "$@":
>one
>two
>three
>four five
>six

Using $@:
>one
>two
>three
>four
>five
>six
[mohammad@CentOS6 bin]$ 

فکر میکنم جای توضیح ندارد. فقط از حلقه for استفاده کردم. ساختار for به این صورت است که گفته به ازای تک تک مقادیر #$ یا *$ ، مقدار آنها درون a ریخته شود، درون بدنه for این متغیر a را چاپ کردم. مثلا میتوانید خروجی هر دستوری را وارد حلقه for کنید. مثلا اگر من بزنم `for var in `ls درون حلقه for مقدار متغیر var برابر با هر خط خروجی دستور ls خواهد بود. مثلا اگه بخوام روی همه فایل های یک پوشه کاری انجام بدم از این روش میشه استفاده کرد. منظورم یه همچین چیزیه:

for var in `ls`
do
echo $var
done

مثلا این الان محتوبات داخل مسیر رو نشون میده.

دستور IF

در این جلسه در مورد ساختار شرط if صبت میکنیم. منطق if در زبان های برنامه نویسی مختلف یکسان است. یک یا چند شرط به عنوان ورودی به if میدیهم، اگر برقرار باشند یا نباشند دستورات خاصی اجرا میشود. به قطعه کد زیر دقت کنید.

#!/bin/bash

if (( $# < 1 ))
then
        echo "Usage : $0 <name> "
        exit 1
fi

echo "Hello $1"

exit 0

این شرط چک میکند که آیا هیچ پارامتری به برنامه ارسال شده یانه ؟؟ اگر پارامتری ارسال نشده، پیامی میدهد و با کد خطا از برنامه خارج میشود. در عیر این صورت ادامه برنامه اجرا میشود. اون fi به معنای خاتمه قطعه کد if است.

[mohammad@CentOS6 bin]$ if.sh Mohammad
Hello Mohammad
[mohammad@CentOS6 bin]$ if.sh
Usage : /home/mohammad/bin/if.sh <name> 
[mohammad@CentOS6 bin]$ 

راستش انقدر if پیج و خم داره که فک کنم بشه واسش به دوره جدا کامل نوشت. یه کوچولو اینجا مبحثشو باز میکنیم، بقیشو خودتون مطالعه کنید.

دستور if اسنفاده بسیار گسترده ای داره، مثلا برای چک کردن اینکه یک فایل وجود دارد یا خیر و یا اینکه قایبل خواندن است یا خیر از نمونه کئ زیر استفاده میکنیم.

if [ -r somefile ]; then
content=$(cat somefile)
elif [ -f somefile ]; then
echo “The file ‘somefile’ exists but is not readable to the script.”
else
echo “The file ‘somefile’ does not exist.”
fi

کد بالا ابتدا با سویچ r- چک میکند که فایل قابل خواندن ( readable ) هست یا نه. با سویچ f- چک میکند که فایل وجود دارد یا نه. در شرط اول، اگر برقرار باشد، فایل را باز میکند و درون متغیر content میریزد.

برای چک کردن محتوای یک متغیر و مقایسه مقدار آن از سویچ های زیر استفاده کنید.

سلام و وقت بخیر. در این جلسه در مورد ساختار شرط if صبت میکنیم. منطق if در زبان های برنامه نویسی مختلف یکسان است. یک یا چند شرط به عنوان ورودی به if میدیهم، اگر برقرار باشند یا نباشند دستورات خاصی اجرا میشود. به قطعه کد زیر دقت کنید.

<c#>
#!/bin/bash

if (( $# < 1 ))
then
        echo Usage : $0 <name> 
        exit 1
fi

echo Hello $1

exit 0
<c#>

این شرط چک میکند که آیا هیچ پارامتری به برنامه ارسال شده یانه ؟؟ اگر پارامتری ارسال نشده، پیامی میدهد و با کد خطا از برنامه خارج میشود. در عیر این صورت ادامه برنامه اجرا میشود. اون fi به معنای خاتمه قطعه کد if است. 

<c#>
[mohammad@CentOS6 bin]$ if.sh Mohammad
Hello Mohammad
[mohammad@CentOS6 bin]$ if.sh
Usage : /home/mohammad/bin/if.sh <name> 
[mohammad@CentOS6 bin]$ 
<c#>

راستش انقدر if پیج و خم داره که فک کنم بشه واسش به دوره جدا کامل نوشت. یه کوچولو اینجا مبحثشو باز میکنیم، بقیشو خودتون مطالعه کنید.
دستور if اسنفاده بسیار گسترده ای داره، مثلا برای چک کردن اینکه یک فایل وجود دارد یا خیر و یا اینکه قایبل خواندن است یا خیر از نمونه کئ زیر استفاده میکنیم.

<c#>
if [ -r somefile ]; then
content=$(cat somefile)
elif [ -f somefile ]; then
echo “The file ‘somefile’ exists but is not readable to the script.”
else
echo “The file ‘somefile’ does not exist.”
fi
<c#>

کد بالا ابتدا با سویچ r- چک میکند که فایل قابل خواندن ( readable ) هست یا نه. با سویچ f- چک میکند که فایل وجود دارد یا نه. در شرط اول، اگر برقرار باشد، فایل را باز میکند و درون متغیر content میریزد.

برای چک کردن محتوای یک متغیر و مقایسه مقدار آن از سویچ های زیر استفاده کنید.
<center>
||http://tosinso.com/files/get/29b0a282-df66-4023-a373-26b9d5cf6197||
<center>
حالا یه سری مثال با اینا ببینید:
<c#>
value=$( grep -ic Mohammad /etc/passwd )
if [ $value -eq 1 ]
then
  echo I found Mohammad
else
  echo I didn't find Mohammad
fi
<c#>

<c#>
value=$( grep -ic Mohammad /etc/passwd )
if [ $value -eq 1 ]
then
  echo I found one Mohammad
elif [ $value -gt 1 ]
then
  echo I found multiple Mohammad
else
  echo I didn't find any Mohammad
fi
<c#>

<c#>
read -p Enter value of i : i

if [ $i -eq 10 ]
then
    echo Value of i is 10
else
    echo Value of i is not equal to 10
fi
<c#>

<c#>
read -p Enter value of i : i
read -p Enter value of j : j
read -p Enter value of k : k

if [ $i -gt $j ]
then
    if [ $i -gt $k ]
    then
        echo i is greatest
    else
        echo k is greatest
    fi
else
    if [ $j -gt $k ]
    then
        echo j is greatest
    else
	echo k is greatest
    fi
fi
<c#>

حالا مثال های خیلی متنوعی میشه ساخت از اینا. جدول زیر یه دید کلی از سویج های if نشون میده.

<htm>
File tests
Operator syntax	Description	
-a <FILE>	True if <FILE> exists. :!: (not recommended, may collide with -a for AND, see below)	
-e <FILE>	True if <FILE> exists.	
-f <FILE>	True, if <FILE> exists and is a regular file.	
-d <FILE>	True, if <FILE> exists and is a directory.
-c <FILE>	True, if <FILE> exists and is a character special file.	
-b <FILE>	True, if <FILE> exists and is a block special file.	
-p <FILE>	True, if <FILE> exists and is a named pipe (FIFO).	
-S <FILE>	True, if <FILE> exists and is a socket file.	
-L <FILE>	True, if <FILE> exists and is a symbolic link.	
-h <FILE>	True, if <FILE> exists and is a symbolic link.	
-g <FILE>	True, if <FILE> exists and has sgid bit set.	
-u <FILE>	True, if <FILE> exists and has suid bit set.	
-r <FILE>	True, if <FILE> exists and is readable.	
-w <FILE>	True, if <FILE> exists and is writable.	
-x <FILE>	True, if <FILE> exists and is executable.	
-s <FILE>	True, if <FILE> exists and has size bigger than 0 (not empty).	
-t <fd>	True, if file descriptor <fd> is open and refers to a terminal.	
<FILE1> -nt <FILE2>	True, if <FILE1> is newer than <FILE2> (mtime). :!:	
<FILE1> -ot <FILE2>	True, if <FILE1> is older than <FILE2> (mtime). :!:	
<FILE1> -ef <FILE2>	True, if <FILE1> and <FILE2> refer to the same device and inode numbers. :!:	

String tests
Operator syntax	Description
-z <STRING>	True, if <STRING> is empty.
-n <STRING>	True, if <STRING> is not empty (this is the default operation).
<STRING1> = <STRING2>	True, if the strings are equal.
<STRING1> != <STRING2>	True, if the strings are not equal.
<STRING1> < <STRING2>	True if <STRING1> sorts before <STRING2> lexicographically (pure ASCII, not current locale!). Remember to escape! Use \<
<STRING1> > <STRING2>	True if <STRING1> sorts after <STRING2> lexicographically (pure ASCII, not current locale!). Remember to escape! Use \>

Arithmetic tests
Operator syntax	Description
<INTEGER1> -eq <INTEGER2>	True, if the integers are equal.
<INTEGER1> -ne <INTEGER2>	True, if the integers are NOT equal.
<INTEGER1> -le <INTEGER2>	True, if the first integer is less than or equal second one.
<INTEGER1> -ge <INTEGER2>	True, if the first integer is greater than or equal second one.
<INTEGER1> -lt <INTEGER2>	True, if the first integer is less than second one.
<INTEGER1> -gt <INTEGER2>	True, if the first integer is greater than second one.

Misc syntax
Operator syntax	Description
<TEST1> -a <TEST2>	True, if <TEST1> and <TEST2> are true (AND). Note that -a also may be used as a file test (see above)
<TEST1> -o <TEST2>	True, if either <TEST1> or <TEST2> is true (OR).
! <TEST>	True, if <TEST> is false (NOT).
( <TEST> )	Group a test (for precedence). Attention: In normal shell-usage, the ( and ) must be escaped; use \( and \)!
-o <OPTION_NAME>	True, if the shell option <OPTION_NAME> is set.
-v <VARIABLENAME>	True if the variable <VARIABLENAME> has been set. Use var[n] for array elements.
-R <VARIABLENAME>	True if the variable <VARIABLENAME> has been set and is a nameref variable (since 4.3-alpha)
<htm>

برای استفاده از امکان AND و OR کردن شرط ها با هم بهتر است از || به معنی AND و && به معنی OR استفاده کنید.

<c#>
if [[ condition1 ]] && [[ condition2 ]]; then    //OR

	do something
fi


if [[ condition1 ]] || [[ condition2 ]]; then    //AND

	do something
fi

if [[ condition1 ]] && [[ condition2 ]]	|| [[ condition3 ]] && [[ condition4 ]]	; then    //OR + AND

	do something
fi
<c#>

شاید دیده باشید که بعضی جاها در if از [ ] یا [[ ]] یا (( )) یا ( ) استفاده میکنند. هر کدام از اینا استفاده خاص خود را دارند.
1- [ ]
برای کار با رشته ها و فایل ها و مقایسه و محاسبات ریاضی
2- [[ ]]
خاصیت های [ ] را دارد ولی بهبود یافته آن است. تفاوت های کوچک کلیدی با هم دارند. بررسی تفاوت ها از حوصله این جلسه خیلی خارجه !!!
3- (( ))
بیشتر برای مقایسه ریاضی استفاده میشود. این از korn shell گرفته شده.

ضمیمه : دلم نمیاد مورد دوم رو بدون مثال ولش کنم!!! مثلا اینو ببینید:
<c#>
if [ -a *.sh ]; then
<c#>
اگه از همچین فایلی یکی وجود داشته باشه true برمیگردونه و اگه اصلا وجود نداشته باشه false برمیگردونه، اگه بیشتر از یکی وجود داشته باشه error میده کلا برنامه !!! برای همین در این مورد باید از این یکی استفاده کنیم که اگه چند تا فایل وجود داشت بتونه تشخیص بده:
<c#>
if [[ -a *.sh ]]; then
<c#>
 همانطور که گفتم دستور if واسه خودش یه دورس... یه اشاره کوچیکی ازش اینجا کردیم. امیدوارم مفید بوده باشه.
پایان قسمت سوم از بخش دوم

نویسنده : سید محمد باقر موسوی
منبع : |جزیره لینوکس و سیستم های متن باز وب سایت توسینسو::https://linux.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی است

حالا یه سری مثال با اینا ببینید:

value=$( grep -ic "Mohammad" /etc/passwd )
if [ $value -eq 1 ]
then
  echo "I found Mohammad"
else
  echo "I didn't find Mohammad"
fi
value=$( grep -ic "Mohammad" /etc/passwd )
if [ $value -eq 1 ]
then
  echo "I found one Mohammad"
elif [ $value -gt 1 ]
then
  echo "I found multiple Mohammad"
else
  echo "I didn't find any Mohammad"
fi
read -p "Enter value of i :" i

if [ $i -eq 10 ]
then
    echo "Value of i is 10"
else
    echo "Value of i is not equal to 10"
fi
read -p "Enter value of i :" i
read -p "Enter value of j :" j
read -p "Enter value of k :" k

if [ $i -gt $j ]
then
    if [ $i -gt $k ]
    then
        echo "i is greatest"
    else
        echo "k is greatest"
    fi
else
    if [ $j -gt $k ]
    then
        echo "j is greatest"
    else
	echo "k is greatest"
    fi
fi

حالا مثال های خیلی متنوعی میشه ساخت از اینا. جدول زیر یه دید کلی از سویج های if نشون میده.

File tests
Operator syntax	Description	
-a <FILE>	True if <FILE> exists. :!: (not recommended, may collide with -a for AND, see below)	
-e <FILE>	True if <FILE> exists.	
-f <FILE>	True, if <FILE> exists and is a regular file.	
-d <FILE>	True, if <FILE> exists and is a directory.
-c <FILE>	True, if <FILE> exists and is a character special file.	
-b <FILE>	True, if <FILE> exists and is a block special file.	
-p <FILE>	True, if <FILE> exists and is a named pipe (FIFO).	
-S <FILE>	True, if <FILE> exists and is a socket file.	
-L <FILE>	True, if <FILE> exists and is a symbolic link.	
-h <FILE>	True, if <FILE> exists and is a symbolic link.	
-g <FILE>	True, if <FILE> exists and has sgid bit set.	
-u <FILE>	True, if <FILE> exists and has suid bit set.	
-r <FILE>	True, if <FILE> exists and is readable.	
-w <FILE>	True, if <FILE> exists and is writable.	
-x <FILE>	True, if <FILE> exists and is executable.	
-s <FILE>	True, if <FILE> exists and has size bigger than 0 (not empty).	
-t <fd>	True, if file descriptor <fd> is open and refers to a terminal.	
<FILE1> -nt <FILE2>	True, if <FILE1> is newer than <FILE2> (mtime). :!:	
<FILE1> -ot <FILE2>	True, if <FILE1> is older than <FILE2> (mtime). :!:	
<FILE1> -ef <FILE2>	True, if <FILE1> and <FILE2> refer to the same device and inode numbers. :!:	

String tests
Operator syntax	Description
-z <STRING>	True, if <STRING> is empty.
-n <STRING>	True, if <STRING> is not empty (this is the default operation).
<STRING1> = <STRING2>	True, if the strings are equal.
<STRING1> != <STRING2>	True, if the strings are not equal.
<STRING1> < <STRING2>	True if <STRING1> sorts before <STRING2> lexicographically (pure ASCII, not current locale!). Remember to escape! Use \<
<STRING1> > <STRING2>	True if <STRING1> sorts after <STRING2> lexicographically (pure ASCII, not current locale!). Remember to escape! Use \>

Arithmetic tests
Operator syntax	Description
<INTEGER1> -eq <INTEGER2>	True, if the integers are equal.
<INTEGER1> -ne <INTEGER2>	True, if the integers are NOT equal.
<INTEGER1> -le <INTEGER2>	True, if the first integer is less than or equal second one.
<INTEGER1> -ge <INTEGER2>	True, if the first integer is greater than or equal second one.
<INTEGER1> -lt <INTEGER2>	True, if the first integer is less than second one.
<INTEGER1> -gt <INTEGER2>	True, if the first integer is greater than second one.

Misc syntax
Operator syntax	Description
<TEST1> -a <TEST2>	True, if <TEST1> and <TEST2> are true (AND). Note that -a also may be used as a file test (see above)
<TEST1> -o <TEST2>	True, if either <TEST1> or <TEST2> is true (OR).
! <TEST>	True, if <TEST> is false (NOT).
( <TEST> )	Group a test (for precedence). Attention: In normal shell-usage, the "(" and ")" must be escaped; use "\(" and "\)"!
-o <OPTION_NAME>	True, if the shell option <OPTION_NAME> is set.
-v <VARIABLENAME>	True if the variable <VARIABLENAME> has been set. Use var[n] for array elements.
-R <VARIABLENAME>	True if the variable <VARIABLENAME> has been set and is a nameref variable (since 4.3-alpha)

برای استفاده از امکان AND و OR کردن شرط ها با هم بهتر است از || به معنی AND و && به معنی OR استفاده کنید.

if [[ condition1 ]] && [[ condition2 ]]; then    //OR

	"do something"
fi


if [[ condition1 ]] || [[ condition2 ]]; then    //AND

	"do something"
fi

if [[ condition1 ]] && [[ condition2 ]]	|| [[ condition3 ]] && [[ condition4 ]]	; then    //OR + AND

	"do something"
fi

شاید دیده باشید که بعضی جاها در if از [ ] یا [[ ]] یا (( )) یا ( ) استفاده میکنند. هر کدام از اینا استفاده خاص خود را دارند.

1- [ ]

برای کار با "رشته ها" و "فایل ها" و "مقایسه و محاسبات ریاضی"

2- [[ ]]

خاصیت های [ ] را دارد ولی بهبود یافته آن است. تفاوت های کوچک کلیدی با هم دارند. بررسی تفاوت ها از حوصله این جلسه خیلی خارجه !!!

3- (( ))

بیشتر برای مقایسه ریاضی استفاده میشود. این از korn shell گرفته شده.

ضمیمه : دلم نمیاد مورد دوم رو بدون مثال ولش کنم!!! مثلا اینو ببینید:

if [ -a *.sh ]; then

اگه از همچین فایلی "یکی" وجود داشته باشه true برمیگردونه و اگه اصلا وجود نداشته باشه false برمیگردونه، اگه بیشتر از یکی وجود داشته باشه error میده کلا برنامه !!! برای همین در این مورد باید از این یکی استفاده کنیم که اگه چند تا فایل وجود داشت بتونه تشخیص بده:

if [[ -a *.sh ]]; then

همانطور که گفتم دستور if واسه خودش یه دورس... یه اشاره کوچیکی ازش اینجا کردیم.

دستور Case

هنگامی که قرار است برای یک ورودی مقادیر مختلفی چک شود و به ازای هر مقدار آن تصمیم خاصی گرفته شود، از case استفاده میکنیم. case یک if توسعه یافته است. منطق case در زبان های برنامه نویسی مختلف یکسان است. به ساختار زیر دقت کنید.

سلام و وقت بخیر. هنگامی که قرار است برای یک ورودی مقادیر مختلفی چک شود و به ازای هر مقدار آن تصمیم خاصی گرفته شود، از case استفاده میکنیم. case یک if توسعه یافته است. منطق case در زبان های برنامه نویسی مختلف یکسان است. به ساختار زیر دقت کنید. 
<center>
||http://tosinso.com/files/get/66c0d2a3-b36a-4b50-942a-532fc189991a||
<center>
یک مثال نسبتا ساده را از case در bash بررسی میکنیم. به کد زیر دقت کنید.
<c#>
#!/bin/bash

if [[ ! -d $1 ]]
then
	echo Usage: $0 <directory>
	exit 1
fi

case $2 in 
	directory)
			find $1 -maxdepth 1 -type d
			;;
	link)
			find $1 -maxdepth 1 -type l
			;;
	*)
			echo Usage: $0 <directory> directory | link 
			;;
esac

exit 0
<c#>
صورت مساله این است که برنامه ای بنویسید که یک مسیر بگیرد، سپس بر اساس اعلام کاربر به دنبال پوشه ها و یا لینک ها در این مسیر تا عمق یکی باشد.
اول از همه با دستور if بررسی میکند که آیا آرگومان اول ارسالی یک مسیر هست یا نه. علامت ! ینی نقیض. پس خط اول میشه اگه آرگومان اول یک directory نیست یک پیام چاپ کن و با کد خطا از برنامه خارج شو. اگر آرگومان اول یک مسیر باشد، شرط برقرار نمیشود و وارد بدنه دستور if نمیشود و برنامه ادامه میابد. بعد از آن از ساختار case برای تشخیص آرگومان ارسالی دوم استفاده کردیم. این case تصمیم میگیرد که با توجه به مقدار آرگومان دوم، چه دستوراتی اجرا شود. در حالت اول اگر مقدار آرگومان دوم directory باشد قطعه کئ زیر آن اجرا میشود. در حالت دوم هم اگر مقدار آرگومان دوم link باشد قطعه کد زیر آن اجرا میشود. مورد آخر که با ستاره مشخص شده یعنی حالت پیش فرض است اگر هیچ یک از سرایط بالا برقرار نباشد، قطعه کد درون ستاره اجرا میشود.
خروجی بصورت زیر است، حالت هایی که خطا میدهد را هم امتحان کردیم.
<c#>
[mohammad@CentOS6 ~]$ case.sh
Usage: /home/mohammad/bin/case.sh <directory>
[mohammad@CentOS6 ~]$ case.sh /etc
Usage: /home/mohammad/bin/case.sh <directory> directory | link 
[mohammad@CentOS6 ~]$ case.sh /etc link
/etc/grub.conf
/etc/rc1.d
/etc/redhat-release
/etc/favicon.png
/etc/rc6.d
/etc/rc2.d
/etc/init.d
/etc/rc.local
/etc/rc4.d
/etc/rc5.d
/etc/rc
/etc/rc3.d
/etc/system-release
/etc/rc0.d
/etc/rc.sysinit
[mohammad@CentOS6 ~]$ case.sh /etc directory
/etc
/etc/rpm
/etc/iproute2
/etc/iscsi
/etc/xml
/etc/sound
/etc/profile.d
/etc/festival
/etc/ssh
/etc/ld.so.conf.d
/etc/setuptool.d
/etc/reader.conf.d
/etc/request-key.d
/etc/cups
/etc/rsyslog.d
/etc/chkconfig.d
/etc/alternatives
/etc/event.d
/etc/spice
/etc/cron.weekly
/etc/libvirt
/etc/popt.d
/etc/skel
/etc/bluetooth
/etc/pcmcia
/etc/logrotate.d
/etc/NetworkManager
/etc/ntp
/etc/pulse
/etc/cron.monthly
/etc/dhcp
/etc/samba
/etc/default
/etc/gnupg
/etc/rpmdevtools
/etc/selinux
/etc/PackageKit
/etc/vmware-tools
/etc/makedev.d
/etc/named
/etc/fcoe
/etc/sasl2
/etc/sudoers.d
/etc/udev
/etc/security
/etc/prelink.conf.d
/etc/bash_completion.d
/etc/ssl
/etc/modprobe.d
/etc/hal
/etc/sysconfig
/etc/blkid
/etc/X11
/etc/acpi
/etc/rwtab.d
/etc/opt
/etc/pm
/etc/xdg
/etc/pam.d
/etc/libreport
/etc/gtk-2.0
/etc/sgml
/etc/yum
/etc/init
/etc/postfix
/etc/statetab.d
/etc/ghostscript
/etc/gnome-vfs-2.0
/etc/ConsoleKit
/etc/dnsmasq.d
/etc/foomatic
/etc/plymouth
/etc/scl
/etc/gcrypt
/etc/rc.d
/etc/dracut.conf.d
/etc/yum.repos.d
/etc/httpd
/etc/pango
/etc/audit
/etc/dbus-1
/etc/portreserve
/etc/pki
/etc/polkit-1
/etc/gdm
/etc/xinetd.d
/etc/cron.d
/etc/cron.daily
/etc/avahi
/etc/audisp
/etc/terminfo
/etc/bonobo-activation
/etc/gconf
/etc/cron.hourly
/etc/obex-data-server
/etc/fonts
/etc/vmware-caf
/etc/lvm
/etc/depmod.d
/etc/wpa_supplicant
/etc/ppp
/etc/kdump-adv-conf
/etc/openldap
/etc/alsa
/etc/lsb-release.d
/etc/multipath
[mohammad@CentOS6 ~]$ 
<c#>

بسیار خوب. این یک مثال برای درک مطلب بود. سعی کنید کمی خلاقیت به خرج بدین و مثال بسازید. مثلا case رو با دستور read ترکیب کنید که case بر اساس متغیر هایی که بوسیله دستور read از کاربر گرفته میشود، تصمیم گیری کند.
پایان قسمت چهارم از بخش دوم

نویسنده : سید محمد باقر موسوی
منبع : |جزیره لینوکس و سیستم های متن باز وب سایت توسینسو::https://linux.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی است

یک مثال نسبتا ساده را از case در bash بررسی میکنیم. به کد زیر دقت کنید.

#!/bin/bash

if [[ ! -d $1 ]]
then
	echo "Usage: $0 <directory>"
	exit 1
fi

case $2 in 
	"directory")
			find $1 -maxdepth 1 -type d
			;;
	"link")
			find $1 -maxdepth 1 -type l
			;;
	*)
			echo "Usage: $0 <directory> directory | link "
			;;
esac

exit 0

صورت مساله این است که برنامه ای بنویسید که یک مسیر بگیرد، سپس بر اساس اعلام کاربر به دنبال پوشه ها و یا لینک ها در این مسیر تا عمق یکی باشد.

اول از همه با دستور if بررسی میکند که آیا آرگومان اول ارسالی یک مسیر هست یا نه. علامت ! ینی نقیض. پس خط اول میشه اگه آرگومان اول یک directory نیست یک پیام چاپ کن و با کد خطا از برنامه خارج شو. اگر آرگومان اول یک مسیر باشد، شرط برقرار نمیشود و وارد بدنه دستور if نمیشود و برنامه ادامه میابد. بعد از آن از ساختار case برای تشخیص آرگومان ارسالی دوم استفاده کردیم. این case تصمیم میگیرد که با توجه به مقدار آرگومان دوم، چه دستوراتی اجرا شود. در حالت اول اگر مقدار آرگومان دوم directory باشد قطعه کئ زیر آن اجرا میشود. در حالت دوم هم اگر مقدار آرگومان دوم link باشد قطعه کد زیر آن اجرا میشود. مورد آخر که با ستاره مشخص شده یعنی حالت پیش فرض است اگر هیچ یک از سرایط بالا برقرار نباشد، قطعه کد درون ستاره اجرا میشود.

خروجی بصورت زیر است، حالت هایی که خطا میدهد را هم امتحان کردیم.

[mohammad@CentOS6 ~]$ case.sh
Usage: /home/mohammad/bin/case.sh <directory>
[mohammad@CentOS6 ~]$ case.sh /etc
Usage: /home/mohammad/bin/case.sh <directory> directory | link 
[mohammad@CentOS6 ~]$ case.sh /etc link
/etc/grub.conf
/etc/rc1.d
/etc/redhat-release
/etc/favicon.png
/etc/rc6.d
/etc/rc2.d
/etc/init.d
/etc/rc.local
/etc/rc4.d
/etc/rc5.d
/etc/rc
/etc/rc3.d
/etc/system-release
/etc/rc0.d
/etc/rc.sysinit
[mohammad@CentOS6 ~]$ case.sh /etc directory
/etc
/etc/rpm
/etc/iproute2
/etc/iscsi
/etc/xml
/etc/sound
/etc/profile.d
/etc/festival
/etc/ssh
/etc/ld.so.conf.d
/etc/setuptool.d
/etc/reader.conf.d
/etc/request-key.d
/etc/cups
/etc/rsyslog.d
/etc/chkconfig.d
/etc/alternatives
/etc/event.d
/etc/spice
/etc/cron.weekly
/etc/libvirt
/etc/popt.d
/etc/skel
/etc/bluetooth
/etc/pcmcia
/etc/logrotate.d
/etc/NetworkManager
/etc/ntp
/etc/pulse
/etc/cron.monthly
/etc/dhcp
/etc/samba
/etc/default
/etc/gnupg
/etc/rpmdevtools
/etc/selinux
/etc/PackageKit
/etc/vmware-tools
/etc/makedev.d
/etc/named
/etc/fcoe
/etc/sasl2
/etc/sudoers.d
/etc/udev
/etc/security
/etc/prelink.conf.d
/etc/bash_completion.d
/etc/ssl
/etc/modprobe.d
/etc/hal
/etc/sysconfig
/etc/blkid
/etc/X11
/etc/acpi
/etc/rwtab.d
/etc/opt
/etc/pm
/etc/xdg
/etc/pam.d
/etc/libreport
/etc/gtk-2.0
/etc/sgml
/etc/yum
/etc/init
/etc/postfix
/etc/statetab.d
/etc/ghostscript
/etc/gnome-vfs-2.0
/etc/ConsoleKit
/etc/dnsmasq.d
/etc/foomatic
/etc/plymouth
/etc/scl
/etc/gcrypt
/etc/rc.d
/etc/dracut.conf.d
/etc/yum.repos.d
/etc/httpd
/etc/pango
/etc/audit
/etc/dbus-1
/etc/portreserve
/etc/pki
/etc/polkit-1
/etc/gdm
/etc/xinetd.d
/etc/cron.d
/etc/cron.daily
/etc/avahi
/etc/audisp
/etc/terminfo
/etc/bonobo-activation
/etc/gconf
/etc/cron.hourly
/etc/obex-data-server
/etc/fonts
/etc/vmware-caf
/etc/lvm
/etc/depmod.d
/etc/wpa_supplicant
/etc/ppp
/etc/kdump-adv-conf
/etc/openldap
/etc/alsa
/etc/lsb-release.d
/etc/multipath
[mohammad@CentOS6 ~]$ 

بسیار خوب. این یک مثال برای درک مطلب بود. سعی کنید کمی خلاقیت به خرج بدین و مثال بسازید. مثلا case رو با دستور read ترکیب کنید که case بر اساس متغیر هایی که بوسیله دستور read از کاربر گرفته میشود، تصمیم گیری کند.

در این جلسه در مورد حلقه ها در bash صحبت میکنیم. حلقه ها در برنامه نویسی بسیار پرکاربرد هستند. انواع مختلفی از حلقه ها در bash وجود دارد.

1- حلقه for

2- حلقه until

3- حلقه while

قبل از اینکه وارد مبحث حلقه ها بشیم به نکته کوچیک بگم. توی چند قسمت گذشته توی مثال ها دیدید که بعضی وقت ها خروجی یک دستور رو میریختیم توی یه متغیر. این کار به 2 صورت انجام میشه.

راه اول: گذاشتن دستور داخل back quotation و برابر یک مقدار قرار دادن. مثلا خروجی دستور ls را درون متغیر var ریختیم

[root@CentOS6 boot]# var=`ls`
[root@CentOS6 boot]# echo $var
config-2.6.32-279.el6.i686 efi elf-memtest86+-4.10 grub initramfs-2.6.32-279.el6.i686.img lost+found memtest86+-4.10 symvers-2.6.32-279.el6.i686.gz System.map-2.6.32-279.el6.i686 vmlinuz-2.6.32-279.el6.i686
[root@CentOS6 boot]# ls
config-2.6.32-279.el6.i686  grub                               memtest86+-4.10                 vmlinuz-2.6.32-279.el6.i686
efi                         initramfs-2.6.32-279.el6.i686.img  symvers-2.6.32-279.el6.i686.gz
elf-memtest86+-4.10         lost+found                         System.map-2.6.32-279.el6.i686
[root@CentOS6 boot]# 

راه دوم : دستور را داخل ()$ گذاشتن و برابر یک متغیر قرار دادن:

[root@CentOS6 boot]# var=$(ls)
[root@CentOS6 boot]# echo $var
config-2.6.32-279.el6.i686 efi elf-memtest86+-4.10 grub initramfs-2.6.32-279.el6.i686.img lost+found memtest86+-4.10 symvers-2.6.32-279.el6.i686.gz System.map-2.6.32-279.el6.i686 vmlinuz-2.6.32-279.el6.i686
[root@CentOS6 boot]# ls
config-2.6.32-279.el6.i686  grub                               memtest86+-4.10                 vmlinuz-2.6.32-279.el6.i686
efi                         initramfs-2.6.32-279.el6.i686.img  symvers-2.6.32-279.el6.i686.gz
elf-memtest86+-4.10         lost+found                         System.map-2.6.32-279.el6.i686
[root@CentOS6 boot]# 

برگردیم سر حلقه ها. از حلقه for که قبلا هم در مثال ها استفاده کردیم. کد ساده زیر رو ببینید. برای نوشتن برنامه حتما لازم نیست توی یه فایل متنی نوشته بشن. توی خود ترمینال هم میتونید دستورات رو وارد کنید.

[root@CentOS6 ~]# for i in `seq 10`
> do
> echo $i
> sleep 1
> done
1
2
3
4
5
6
7
8
9
10
[root@CentOS6 ~]# 

دستور seq تا عدد مقابل آن میشمارد. در اینجا هر بار که دستور seq یک عدد تولید میکند، مقدار i برابر این مقدار میشود. دستورات حلقه for درون do و done نوشته میشود. دقت داشته باشید که seq 10 رو داخل back quotation نوشتم. بزارید یه مثال ساده دیگه هم ببینیم.

[root@CentOS6 /]# for i in $(ls)
> do
> echo -e "item: $i \n"
> done
item: bin 
item: boot 
item: dev 
item: etc 
item: file1 
item: file2 
item: home 
item: lib 
item: lost+found 
item: media 
item: misc 
item: mnt 
item: net 
item: opt 
item: proc 
item: root 
item: sbin 
item: selinux 
item: srv 
item: sys 
item: tmp 
item: usr 
item: var 
[root@CentOS6 /]#

حالا بریم سراغ حلقه while. مثال ساده زیر را ببینید. تا زمانی که شرط حلقه while برقرار باشد، دستورات داخل آن اجرا میشوند.

[root@CentOS6 /]# count=0
[root@CentOS6 /]# while [ $count -lt 10 ]
> do
> echo count is $count
> let count=count+1
> done
count is 0
count is 1
count is 2
count is 3
count is 4
count is 5
count is 6
count is 7
count is 8
count is 9
[root@CentOS6 /]# 

واسه اینکه یکم ذهنتون درگیر بشه برید سرچ کنید که چرا وقتی دستور for یا while رو میزنیم شکل prompt میشه < و اسم این حالتی که فعال میشه چیه و آیا میشه تغییرش داد یا نه. سر کاری نیستا !!!! :)))) شاید اینجوری یکی یه کامنتی بزاره زیر پستا !!!

دستور until هم بصورت زیره، فقط دقت داشته باشید که شرطی که به until میدهیم ، شرط اتمام حلقه است.

[root@CentOS6 /]# counter=1
[root@CentOS6 /]# until [ $counter -gt 10 ]
> do
> echo $counter
> ((counter++))
> done
1
2
3
4
5
6
7
8
9
10
[root@CentOS6 /]# 

حالا یه مدل دیگه هم for داریم که مث for توی خانواده c میمونه:

[root@CentOS6 /]# for ((i=0;i<10;i+=1))
> do
> echo $i
> done
0
1
2
3
4
5
6
7
8
9
[root@CentOS6 /]# 

اینم ببینید جالبه. یعنی از 0 شروع کن و تا 25 برو. قدم هاتم 5 تایی باشه

[root@CentOS6 /]# for i in {0..25..5}
> do
>     echo $i
> done
0
5
10
15
20
25
[root@CentOS6 /]# 

مثال یکم سخت تر: برنامه ای ینویسید که یک عدد از کاربر بگیرد و به همان تعداد عدد اول چاپ کند.

#!/bin/bash

read -p "How many prime numbers ?: " num

c=0
k=0
n=2

echo 1
numero=$[$num-1]

while [ $k -ne $num ]; do
     for i in `seq 1 $n`;do
        r=$[$n%$i]
                if [ $r -eq 0 ]; then
                        c=$[$c+1]
                fi
     done

      if [ $c -eq 2 ]; then
              echo "$i"
              k=$[$k+1]
        fi
        n=$[$n+1]
        c=0
done
[root@CentOS6 ~]# ./prime.sh
How many prime numbers ?: 3
1
2
3
5
[root@CentOS6 ~]# ./prime.sh
How many prime numbers ?: 5
1
2
3
5
7
11
[root@CentOS6 ~]# ./prime.sh
How many prime numbers ?: 15
1
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
[root@CentOS6 ~]# 

حلقه ها

در این جلسه در مورد حلقه ها در bash صحبت میکنیم. حلقه ها در برنامه نویسی بسیار پرکاربرد هستند. انواع مختلفی از حلقه ها در bash وجود دارد.

1- حلقه for

2- حلقه until

3- حلقه while

قبل از اینکه وارد مبحث حلقه ها بشیم به نکته کوچیک بگم. توی چند قسمت گذشته توی مثال ها دیدید که بعضی وقت ها خروجی یک دستور رو میریختیم توی یه متغیر. این کار به 2 صورت انجام میشه.

راه اول: گذاشتن دستور داخل back quotation و برابر یک مقدار قرار دادن. مثلا خروجی دستور ls را درون متغیر var ریختیم

[root@CentOS6 boot]# var=`ls`
[root@CentOS6 boot]# echo $var
config-2.6.32-279.el6.i686 efi elf-memtest86+-4.10 grub initramfs-2.6.32-279.el6.i686.img lost+found memtest86+-4.10 symvers-2.6.32-279.el6.i686.gz System.map-2.6.32-279.el6.i686 vmlinuz-2.6.32-279.el6.i686
[root@CentOS6 boot]# ls
config-2.6.32-279.el6.i686  grub                               memtest86+-4.10                 vmlinuz-2.6.32-279.el6.i686
efi                         initramfs-2.6.32-279.el6.i686.img  symvers-2.6.32-279.el6.i686.gz
elf-memtest86+-4.10         lost+found                         System.map-2.6.32-279.el6.i686
[root@CentOS6 boot]# 

راه دوم : دستور را داخل ()$ گذاشتن و برابر یک متغیر قرار دادن:

[root@CentOS6 boot]# var=$(ls)
[root@CentOS6 boot]# echo $var
config-2.6.32-279.el6.i686 efi elf-memtest86+-4.10 grub initramfs-2.6.32-279.el6.i686.img lost+found memtest86+-4.10 symvers-2.6.32-279.el6.i686.gz System.map-2.6.32-279.el6.i686 vmlinuz-2.6.32-279.el6.i686
[root@CentOS6 boot]# ls
config-2.6.32-279.el6.i686  grub                               memtest86+-4.10                 vmlinuz-2.6.32-279.el6.i686
efi                         initramfs-2.6.32-279.el6.i686.img  symvers-2.6.32-279.el6.i686.gz
elf-memtest86+-4.10         lost+found                         System.map-2.6.32-279.el6.i686
[root@CentOS6 boot]# 

برگردیم سر حلقه ها. از حلقه for که قبلا هم در مثال ها استفاده کردیم. کد ساده زیر رو ببینید. برای نوشتن برنامه حتما لازم نیست توی یه فایل متنی نوشته بشن. توی خود ترمینال هم میتونید دستورات رو وارد کنید.

[root@CentOS6 ~]# for i in `seq 10`
> do
> echo $i
> sleep 1
> done
1
2
3
4
5
6
7
8
9
10
[root@CentOS6 ~]# 

دستور seq تا عدد مقابل آن میشمارد. در اینجا هر بار که دستور seq یک عدد تولید میکند، مقدار i برابر این مقدار میشود. دستورات حلقه for درون do و done نوشته میشود. دقت داشته باشید که seq 10 رو داخل back quotation نوشتم. بزارید یه مثال ساده دیگه هم ببینیم.

[root@CentOS6 /]# for i in $(ls)
> do
> echo -e "item: $i \n"
> done
item: bin 
item: boot 
item: dev 
item: etc 
item: file1 
item: file2 
item: home 
item: lib 
item: lost+found 
item: media 
item: misc 
item: mnt 
item: net 
item: opt 
item: proc 
item: root 
item: sbin 
item: selinux 
item: srv 
item: sys 
item: tmp 
item: usr 
item: var 
[root@CentOS6 /]#

حالا بریم سراغ حلقه while. مثال ساده زیر را ببینید. تا زمانی که شرط حلقه while برقرار باشد، دستورات داخل آن اجرا میشوند.

[root@CentOS6 /]# count=0
[root@CentOS6 /]# while [ $count -lt 10 ]
> do
> echo count is $count
> let count=count+1
> done
count is 0
count is 1
count is 2
count is 3
count is 4
count is 5
count is 6
count is 7
count is 8
count is 9
[root@CentOS6 /]# 

واسه اینکه یکم ذهنتون درگیر بشه برید سرچ کنید که چرا وقتی دستور for یا while رو میزنیم شکل prompt میشه < و اسم این حالتی که فعال میشه چیه و آیا میشه تغییرش داد یا نه. سر کاری نیستا !!!! :)))) شاید اینجوری یکی یه کامنتی بزاره زیر پستا !!!

دستور until هم بصورت زیره، فقط دقت داشته باشید که شرطی که به until میدهیم ، شرط اتمام حلقه است.

[root@CentOS6 /]# counter=1
[root@CentOS6 /]# until [ $counter -gt 10 ]
> do
> echo $counter
> ((counter++))
> done
1
2
3
4
5
6
7
8
9
10
[root@CentOS6 /]# 

حالا یه مدل دیگه هم for داریم که مث for توی خانواده c میمونه:

[root@CentOS6 /]# for ((i=0;i<10;i+=1))
> do
> echo $i
> done
0
1
2
3
4
5
6
7
8
9
[root@CentOS6 /]# 

اینم ببینید جالبه. یعنی از 0 شروع کن و تا 25 برو. قدم هاتم 5 تایی باشه

[root@CentOS6 /]# for i in {0..25..5}
> do
>     echo $i
> done
0
5
10
15
20
25
[root@CentOS6 /]# 

مثال یکم سخت تر: برنامه ای ینویسید که یک عدد از کاربر بگیرد و به همان تعداد عدد اول چاپ کند.

#!/bin/bash

read -p "How many prime numbers ?: " num

c=0
k=0
n=2

echo 1
numero=$[$num-1]

while [ $k -ne $num ]; do
     for i in `seq 1 $n`;do
        r=$[$n%$i]
                if [ $r -eq 0 ]; then
                        c=$[$c+1]
                fi
     done

      if [ $c -eq 2 ]; then
              echo "$i"
              k=$[$k+1]
        fi
        n=$[$n+1]
        c=0
done
[root@CentOS6 ~]# ./prime.sh
How many prime numbers ?: 3
1
2
3
5
[root@CentOS6 ~]# ./prime.sh
How many prime numbers ?: 5
1
2
3
5
7
11
[root@CentOS6 ~]# ./prime.sh
How many prime numbers ?: 15
1
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
[root@CentOS6 ~]# 

مدیریت کاربران

در این قسمت درمورد مدیریت user ها و group ها در لینوکس صحبت میکنیم. درست کردن user ها در سیستم های لینوکسی یکی از کار های روتین مدیر سیستم است. ممکن است مدیر سیستم بخواهد یک یا چند کاربر را با مشخصاتی پیش فرض در سیستم درست کند. با حتی بخواهد یک یا چند کاربر با مشخصاتی غیر از پیش فرض در سیستم ایجاد کند. تنظیماتی پیش فرض در سیستم وجود دارد که اگر شما هنگام ایجاد یک کاربر، مشخصه خاصی تعیین نکنید، از این تنظیمات برای ایجاد کاربر استفاده میکند. مسیر این فایل تنظیمات بصورت زیر است.

[root@CentOS6 ~]# cat /etc/default/useradd 
# useradd defaults file
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE-MAIL-SPOOL=yes

[root@CentOS6 ~]# 

شاید اگر این فایل را تا بحال ندیده باشید باز هم حدس زدن معنی بعضی از عناصر آن کار راحتی باشد. ولی بگذارید تک تک آنها را بررسی کنیم.

GROUP=100 : هنگامی که کاربر ایجاد شد مقدار group id او را برابر 100 قرار بده. ( چرا 100 ؟ )

HOME=home : آدرس home directory کاربر را از home شروع کن.

INACTIVE=-1 : عدد 1- یعنی disable است. این مشخصه یعنی اگر پسورد کاربر منقضی شد، کاربر تا چند روز فرصت دارد پسورد خود را عوض کند. در این مدت همان پسورد قدیمی او قابل استفاده است ولی اگر مدت تعیین شده به پایان رسد، کاربر قادر به ورود به سیستم نخواهد بود. مثلا اگر این مقدار برابر 4 باشد یعنی کاربر 4 روز فرصت دارد و بعد از آن اگر رمز را عوض نکرده باشد دیگر اجازه ورود ندارد.

EXPIRE= : اگر میخواهید اکانت کاربر پس از مدت مشخصی از بین برود، به این مشخصه، مقدار زمان دلخواه خود را بدهید.

SHELL=binbash : آدرس شل پیش فرض کاربر را مشخص میکند.

SKEL=etcskel : مقدار محتویات پیش فرض داخل home directory کاربر را مشخص میکند.

CREATEMAILSPOOL=yes : برای کاربر صندوق میل درست کند یا نه.

حالا محتویات skel را ببینید.

[root@CentOS6 etc]# cd /etc/skel
[root@CentOS6 skel]# ls -a
.  ..  .bash_logout  .bash_profile  .bashrc  .gnome2  .mozilla
[root@CentOS6 skel]# 

به یک روش دیگر هم میتوان مقادیر پیش فرض ایجاد کاربر را دید. استفاده از سویچ D- دستور useradd :

[root@CentOS6 etc]# useradd -D
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes
[root@CentOS6 etc]# 

حال اطلاعات کاربران کجا ذخیره میشود ؟؟ احتمالا با فایل معروف passwd آشنا هستید. اطلاعات هویتی کاربران در این فایل به مسیر etcpasswd ذخیره میشود. اما در حالت عادی رمز کاربران در این فایل نیست. رمز hash شده کاربران در فایل etcshadow قرار دارد.

برای برگرداندن رمز ها از shadow به passwd از دستور pwunconv و برای دوباره برگرداندن رمز ها از passed به shadow از دستور pwconv استفاه کنید.

با دستور cat فایل passwd را باز کنید.

[root@CentOS6 etc]# 
[root@CentOS6 etc]# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
rtkit:x:499:496:RealtimeKit:/proc:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/cache/rpcbind:/sbin/nologin
saslauth:x:498:76:"Saslauthd user":/var/empty/saslauth:/sbin/nologin
haldaemon:x:68:68:HAL daemon:/:/sbin/nologin
pulse:x:497:495:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
gdm:x:42:42::/var/lib/gdm:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
mohammad:x:500:500:mohammad:/home/mohammad:/bin/bash
test:x:501:501::/home/test:/bin/bash
dhcpd:x:177:177:DHCP server:/:/sbin/nologin
named:x:25:25:Named:/var/named:/sbin/nologin
apache:x:48:48:Apache:/var/www:/sbin/nologin
[root@CentOS6 etc]# 

همانطور که مشخص است، این فایل 7 ستون دارد که با : از هم جدا شدند. حال هر کدام چیست ؟؟

1- نامی که کاربر با آن log in میکند

2- کاراکتر x به جای رمز hash شذه کاربر. اگر از دستور pwunconv استفاده کنیم، رمز ها جای x مینشینند.

3- مقدار user id

4- مقدار group id

5- مقدار کامل نام کاربر یا کامنت

6- آدرس home directory کاربر

7- آدرس شل تعیین شده برای کاربر

حال فایل shadow را با دستور cat باز کنید.

[root@CentOS6 etc]# cat /etc/shadow
root:$6$yUzDwtnycAln2hCt$Ut8TIzgr7PEIB.FYoqHR4PhKz7L3sG4wquDWlYRMZ42a0Gj7TI46xsv065.eCriDTFqqI.CiYOa0v.xpKamI7/:17034:0:99999:7:::
bin:*:17034:0:99999:7:::
daemon:*:17034:0:99999:7:::
adm:*:17034:0:99999:7:::
lp:*:17034:0:99999:7:::
sync:*:17034:0:99999:7:::
shutdown:*:17034:0:99999:7:::
halt:*:17034:0:99999:7:::
mail:*:17034:0:99999:7:::
uucp:*:17034:0:99999:7:::
operator:*:17034:0:99999:7:::
games:*:17034:0:99999:7:::
gopher:*:17034:0:99999:7:::
ftp:*:17034:0:99999:7:::
nobody:*:17034:0:99999:7:::
dbus:!!:17034:0:99999:7:::
avahi-autoipd:!!:17034:0:99999:7:::
vcsa:!!:17034:0:99999:7:::
rtkit:!!:17034:0:99999:7:::
rpc:!!:17034:0:99999:7:::
saslauth:!!:17034:0:99999:7:::
haldaemon:!!:17034:0:99999:7:::
pulse:!!:17034:0:99999:7:::
postfix:!!:17034:0:99999:7:::
avahi:!!:17034:0:99999:7:::
ntp:!!:17034:0:99999:7:::
rpcuser:!!:17034:0:99999:7:::
nfsnobody:!!:17034:0:99999:7:::
gdm:!!:17034:0:99999:7:::
sshd:!!:17034:0:99999:7:::
tcpdump:!!:17034:0:99999:7:::
mohammad:$6$5a9rY41dZwqTKB/0$FwfF54aZqol3QDqu.CAWkIKnW9F/RuNC28sMd.KvT4pUklTI9Q4nVax3rYwI.o7IIRd6bIs1G9.jpUmwzwM0M.:17034:0:99999:7:::
test:$6$AoyRySYi$HML82/iRkybJe1V8p9KGWiGAiU4Ha8SS7e4XeQaWmmh3BQcUY0jO3MZvblYyOXS5LqqwXHg/u2yaRp8PGNZqg0:17034:0:99999:7:::
dhcpd:!!:17034:0:99999:7:::
named:!!:17034:0:99999:7:::
apache:!!:17034:0:99999:7:::
[root@CentOS6 etc]# 

این فایل 8 ستون دارد که با : از هم جدا شدند.

1- نامی که کاربر با آن log in میکند

2- رمز hash شده کاربر. اگز !! است یعنی نمیتواند log in کند

3- تاریخ آخرین تغییر رمز ( تعداد روز های گذشته از یکم ژانوبه 1970 )

4- کوتاه ترین زمان عمر رمز

5- بیشترین زمان عمر زمر

6- چند روز قبل منقضی شدن رمز به کاربر هشدار دهد

7- مقدار password inactivity که در بالاتر در فایل default توضیح دادم

8- زمان منقضی شدن اکانت کاربر

برای خواندن جزئیات بیشتر، صفحات manual این دو فایل را بخوانید. با دستور man 5 passwd و man 5 shadow.

برای تنظیم جرئیات بیشتر در مورد زمان بندی رمز ها میتوانید از فایل etclogin.defs استفاده کنید.

با دستور id مقدار uid و gid کاربری که هستید را ببینید.

[root@CentOS6 /]# whoami
root
[root@CentOS6 /]# id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[root@CentOS6 /]# su - mohammad
[mohammad@CentOS6 ~]$ id
uid=500(mohammad) gid=500(mohammad) groups=500(mohammad) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[mohammad@CentOS6 ~]$ 
[mohammad@CentOS6 ~]$ 

بسیار خوب، حالا بریم یه چند تا مثال عملیاتی کار کنیم. به کد های زیر دقت کنید.

[root@CentOS6 ~]# useradd ali
[root@CentOS6 ~]# id ali
uid=502(ali) gid=502(ali) groups=502(ali)
[root@CentOS6 ~]# ls -l /home
total 12
drwx------.  4 ali      ali      4096 Aug 21 21:53 ali
drwx------. 28 mohammad mohammad 4096 Aug 21 21:49 mohammad
drwx------.  4 test     test     4096 Aug 29  2015 test
[root@CentOS6 ~]# useradd reza
[root@CentOS6 ~]# id reza
uid=503(reza) gid=503(reza) groups=503(reza)
[root@CentOS6 ~]# ls -l /home
total 16
drwx------.  4 ali      ali      4096 Aug 21 21:53 ali
drwx------. 28 mohammad mohammad 4096 Aug 21 21:49 mohammad
drwx------.  4 reza     reza     4096 Aug 21 21:53 reza
drwx------.  4 test     test     4096 Aug 29  2015 test

[root@CentOS6 ~]# useradd bob -c "sponge bob"
[root@CentOS6 ~]# ls -l /home
total 20
drwx------.  4 ali      ali      4096 Aug 21 21:53 ali
drwx------.  4 bob      bob      4096 Aug 21 22:10 bob
drwx------. 28 mohammad mohammad 4096 Aug 21 21:49 mohammad
drwx------.  4 reza     reza     4096 Aug 21 21:53 reza
drwx------.  4 test     test     4096 Aug 29  2015 test

[root@CentOS6 ~]# id bob
uid=504(bob) gid=504(bob) groups=504(bob)
[root@CentOS6 ~]# tail -3 /etc/passwd
ali:x:502:502::/home/ali:/bin/bash
reza:x:503:503::/home/reza:/bin/bash
bob:x:504:504:sponge bob:/home/bob:/bin/bash
[root@CentOS6 ~]# userdel -r bob
[root@CentOS6 ~]# ls -l /home
total 16
drwx------.  4 ali      ali      4096 Aug 21 21:53 ali
drwx------. 28 mohammad mohammad 4096 Aug 21 21:49 mohammad
drwx------.  4 reza     reza     4096 Aug 21 21:53 reza
drwx------.  4 test     test     4096 Aug 29  2015 test

[root@CentOS6 ~]# tail -3 /etc/shadow
apache:!!:17034:0:99999:7:::
ali:!!:17034:0:99999:7:::
reza:!!:17034:0:99999:7:::
[root@CentOS6 ~]# passwd ali
Changing password for user ali.
New password: 
BAD PASSWORD: it is WAY too short
BAD PASSWORD: is too simple
Retype new password: 
passwd: all authentication tokens updated successfully.
[root@CentOS6 ~]# tail -3 /etc/shadow
apache:!!:17034:0:99999:7:::
ali:$6$q.RMBAcT$oSMQGn.GJB7s2vdEtEFGMyfxqph3DVxK9yUkVSRkMiYzdyRhoOwPK8JYIVauW8uKip5CFjxl76HWfLrSRq1jW/:17034:0:99999:7:::
reza:!!:17034:0:99999:7:::

[root@CentOS6 ~]# usermod -L ali
[root@CentOS6 ~]# tail -3 /etc/shadow
apache:!!:17034:0:99999:7:::
ali:!$6$q.RMBAcT$oSMQGn.GJB7s2vdEtEFGMyfxqph3DVxK9yUkVSRkMiYzdyRhoOwPK8JYIVauW8uKip5CFjxl76HWfLrSRq1jW/:17034:0:99999:7:::
reza:!!:17034:0:99999:7:::

[root@CentOS6 ~]# usermod -U ali
[root@CentOS6 ~]# tail -3 /etc/shadow
apache:!!:17034:0:99999:7:::
ali:$6$q.RMBAcT$oSMQGn.GJB7s2vdEtEFGMyfxqph3DVxK9yUkVSRkMiYzdyRhoOwPK8JYIVauW8uKip5CFjxl76HWfLrSRq1jW/:17034:0:99999:7:::
reza:!!:17034:0:99999:7:::
[root@CentOS6 ~]# date --date "17034 days ago"
Thu Jan  1 20:49:23 IRST 1970
[root@CentOS6 ~]# 

همشو میگم !!! نگران نباشید !!!

با دستور useradd ali یک کاربر با نام ali درست کردم. اگر دستور id ali را بزنم ، مقدار uid و gid را برای او نشان میدهد. ( پس اون مقدار پیش فرض 100 چی بود ؟؟ برید سرچ کنید، بعدا میگم چرا اینجوریه. یکی کامنت بزاره چرا اینجوریه. ) اگر home/ را باز کنم، میبینم که برای ali پوشه هم درست کرده. ممکنه درست نکنه، نسخه من درست میکنه، اگر برای شما درست نکرد ، دستور useradd رو با m- بزنید. وقتی پوشه درست نمیکنه، تا اون کاربره log in نکنه، پوشه درست نمیشه. دستور useradd سویچ ها مختلف و مهمی داره. مثلا سویچ c- برای مشخص کردن نام کامل کاربر یا کامنت استفاده میشه ( بالاتر تو passwd گفتم ) . با دستور userdel هم کاربر را پاک کنید.

اگر با سویچ r- استفاده کنید home directory و mail box او را هم پاک میکند. حال فایل shadow رو نگاه کنید. اون !! چی میگه ؟؟ چون واسه کاربر پسورد نذاشتیم. کلا اول ستون پسورد ! باشه ینی کاربر قفله ( ینی نمیتونه log in کنه) حالا با دستور passwd برای ali پسورد میذارم. اگه دوباره فایل shadow رو ببینید، دیگه ali قفل نیست. ( اول ستون رمز ! نیست ) . حالا اگه بخوایم یه کاربر را قفل کنیم. ( مثلا تنبیهش کنیم، نتونه وارد بشه ) از دستور usermod با سویچ L- استفاده میکنیم. بعدش برید shadow رو ببینید، یه ! اول رمزش اضافه شده ( ینی رفت تو باقالیا !!! قفل شد !!! ) حالا ali توبه کرده میخوایم از قفلی درش یاریم، از دستور usermod با سویچ U- استفاده میکنیم. علامت ! از اول رمزش برداشته شد.

اون 17034 هم تعداد روز گذشته از آخرین تغییر پسورد رو میگه نسبت به اول ژانویه 1970... اگه باور نمیکنید، خروجی دستور date رو ببینید.ینی آخرین باری که پسورد عوض شد از اول ژانویه 1970 تعداد 17034 روز گرشته بود.کاربر بدون رمز هم نمیتونه log in کنه، یادتون باشه اینو.

مدیریت گروه ها

همانطور که گفتم، این جلسه در مورد گروه ها صحبت میکنیم. اصلی ترین فایل اطلاعات گروه ها، فایل group در زیر شاخه etc است. آن را باز کنید.

[root@CentOS6 ~]# cat /etc/group
root:x:0:
bin:x:1:bin,daemon
daemon:x:2:bin,daemon
sys:x:3:bin,adm
adm:x:4:adm,daemon
tty:x:5:
disk:x:6:
lp:x:7:daemon
mem:x:8:
kmem:x:9:
wheel:x:10:
mail:x:12:mail,postfix
uucp:x:14:
man:x:15:
games:x:20:
gopher:x:30:
video:x:39:
dip:x:40:
ftp:x:50:
lock:x:54:
audio:x:63:
nobody:x:99:
users:x:100:
dbus:x:81:
utmp:x:22:
utempter:x:35:
ctapiusers:x:499:
desktop_admin_r:x:498:
desktop_user_r:x:497:
avahi-autoipd:x:170:
floppy:x:19:
vcsa:x:69:
rtkit:x:496:
rpc:x:32:
cdrom:x:11:
tape:x:33:
dialout:x:18:
saslauth:x:76:
haldaemon:x:68:haldaemon
pulse:x:495:
pulse-access:x:494:
fuse:x:493:
postdrop:x:90:
postfix:x:89:
avahi:x:70:
ntp:x:38:
rpcuser:x:29:
nfsnobody:x:65534:
gdm:x:42:
stapusr:x:156:
stapsys:x:157:
stapdev:x:158:
sshd:x:74:
tcpdump:x:72:
slocate:x:21:
mohammad:x:500:
test:x:501:
dhcpd:x:177:
named:x:25:
apache:x:48:
ali:x:502:
reza:x:503:
[root@CentOS6 ~]# 

این فایل 4 ستون دارد که مانند فایل passwd با : جدا شده اند.

1- نام گروه

2- رمز گروه که یه جای آن x آمده

3- مقدار group id

4- لیست اعضا که با ، از هم جدا شده اند.

مثل فایل passwd که یک فایل shadow هم دارد، فایل group هم یک shadow دارد ولی اسم آن gshadow است. آن را در etc پیدا میکنید

[root@CentOS6 ~]# cat /etc/gshadow
root:::
bin:::bin,daemon
daemon:::bin,daemon
sys:::bin,adm
adm:::adm,daemon
tty:::
disk:::
lp:::daemon
mem:::
kmem:::
wheel:::
mail:::mail,postfix
uucp:::
man:::
games:::
gopher:::
video:::
dip:::
ftp:::
lock:::
audio:::
nobody:::
users:::
dbus:!::
utmp:!::
utempter:!::
ctapiusers:!::
desktop_admin_r:!::
desktop_user_r:!::
avahi-autoipd:!::
floppy:!::
vcsa:!::
rtkit:!::
rpc:!::
cdrom:!::
tape:!::
dialout:!::
saslauth:!::
haldaemon:!::haldaemon
pulse:!::
pulse-access:!::
fuse:!::
postdrop:!::
postfix:!::
avahi:!::
ntp:!::
rpcuser:!::
nfsnobody:!::
gdm:!::
stapusr:!::
stapsys:!::
stapdev:!::
sshd:!::
tcpdump:!::
slocate:!::
mohammad:!!::
test:!::
dhcpd:!::
named:!::
apache:!::
ali:!::
reza:!::
[root@CentOS6 ~]# 

این فابل هم 4 ستون دارد که با : از هم جدا شدند.

1- نام گروه

2- رمز hash شده گروه

3- اسامی ادمین های گروه که با ، حدا میشوند

4- اسامی اعضای گروه

فایل manula این دو تا فبلی که ذکر شد رو هم با دستور man 5 group و man 5 gshadow ببینید.

یادتونه جلسه قبل برای کاربران group id پیش فرض مشخص کردیم ولی وقتی کاربر ساختیم از اون پیش فرض تبعیت نکرد ؟؟ رفتید سرچ کنید ؟؟ نرفتید دیگه !!! هیچ کی نگفت چرا اینجوری شد... خودم میگم حالا... گوش کنید پس.

دیدید وقتی یه کاربر اضافه کردیم، عضو گروهی به اسم خودش شد. به این گروه هایی که اینجوری درست میشن میگن private groups. پس private group در حالت عادی فعال است و باعث میشود هر کاربر جدیدی عضو گروه خودش شود و از مقدار پیش فرض تبعیت نکند. اگر غیر فعالش کنیم از مقدار پیش فرض تبعیت میکند.

یه کد های زیر دقت کنید.

[root@CentOS6 ~]# useradd -m jim
[root@CentOS6 ~]# id jim
uid=502(jim) gid=502(jim) groups=502(jim)
[root@CentOS6 ~]# grep USERGROUP /etc/login.defs
USERGROUPS_ENAB yes
[root@CentOS6 ~]# useradd -g users -m jack
[root@CentOS6 ~]# id jack
uid=503(jack) gid=100(users) groups=100(users)
[root@CentOS6 ~]# 

با دستور useradd و سویچ m- یک کاربر درست کردم. اگر مقادیر id را برای اون چک کنم، میبینم که مقدار پیش فرض را نگرفته. حالت private groups در فایل login.defs تعریف میشود. در حالت عادی هم فعال است که مشاهده میکنید. حال اگر این بار یک کاربر دیگر اضافه کنم ولی با سویچ g- و کلمه user بعدش id را چک کنم میبینم که از مقدار پیش فرض تبعیت کرده. در این حالت با سویچ g- به معنی primary group این حالت فعال بودن private groups را موقتا نادیده گرفتیم.

دو مفهوم جدید اینجا بوجود می آید. g- برای primary groups و G- برای secondary groups. هر کدام به چه معناست ؟؟

یکم توضیحش ظریفه اینجا. دقت کنید. امیدوارم راحت متوجه بشید. وقتی یک کاربر یک فایل را باز میکنه یا برنامه ای را اجرا میکنه یا هر چی دیگه، به دسترسی های primary group اون بستگی داره. وقتی یک کاربر فایل درست میکنه، اونو با دسترسی و مالکیت primary group درست میکنه. هر کس دیگه ای هم که توی اون primary group باشه اگه دسترسی تعریف شده باشه، میتونه اون فایل رو ببینه یا بخونه یا اجرا کنه. مثلا یک primary group دارم به اسم admins... هر کی ادمین بخش های مختلف هستش رو عضو این گروه کردم. هر کس در چارچوب این گروه اجازه دسترسی به منابع مختلف رو توی این گروه داره و هر کسی تو این گروه فایلی درست کنه یا مسیری بسازه مالکیت اون مسیر یا فایل به primary group برمیگرده، یعنی مثلا این فابل متعلق به گروه ادمین هاست، چون یکی که عضو این گروه بوده اینو درست کرده. ولی حالا secondary group چیه؟ حالا برای هر کاربر یک یا چند secondary group هم میشه تعریف کرد.

[root@CentOS6 ~]# usermod -G mali,hr  jack
[root@CentOS6 ~]# id jack
uid=503(jack) gid=100(users) groups=100(users),12(mali),504(hr)
[root@CentOS6 ~]# 

برای کاربر دو گروه مالی و منابع انسانی رو به عنوان secondary groups مشخص کردم. در خروجی دستور id میبینیم که گروه user با شماره 100 به عنوان primary group برای jack تعریف شده، 2 گروه mali و hr هم به عنوان secondary group، علاوه بر خود گروه users. حالا jack دسترسی ها و امکانات گروه hr و mali را هم دارد و میتواند با سطح دسترسی آنها کاری انجام دهد، میتواند به فایل های در مالکیت این گروه ها دسترسی داشته باشد، ولی اگر فایلی درست کند با دسترسی primary group درست میشود. پس هر کاربر میتواند در یک لحظه فقط و فقط یک primary group ولی چندین secondary group داشته باشد. اصطلاحا secondary group ها باعث ایجاد addition access برای کاربر میشوند.

به دستورات زیر دقت کنید.

[root@CentOS6 ~]# useradd -N -m sally
[root@CentOS6 ~]# id sally
uid=504(sally) gid=100(users) groups=100(users)
[root@CentOS6 ~]# 

هنگام ایجاد کاربر با سویچ N- به معنی no user group میتوان از تنظیمات پیش فرض استفاده کرد.

به دستورات زیر دقت کنید.

[root@CentOS6 ~]# grep hr /etc/group
hr:x:504:jack
[root@CentOS6 ~]# grep mali /etc/group
mali:x:503:jack
[root@CentOS6 ~]# grep mali /etc/gshadow
mali:!::jack
[root@CentOS6 ~]# id sally
uid=504(sally) gid=100(users) groups=100(users)
[root@CentOS6 ~]# gpasswd -M sally mali
[root@CentOS6 ~]# id sally
uid=504(sally) gid=100(users) groups=100(users),503(mali)
[root@CentOS6 ~]# grep mali /etc/group
mali:x:503:sally
[root@CentOS6 ~]# usermod -G  mali jack
[root@CentOS6 ~]# grep mali /etc/group
mali:x:503:sally,jack
[root@CentOS6 ~]# gpasswd -M sally mali
[root@CentOS6 ~]# grep mali /etc/group
mali:x:503:sally
[root@CentOS6 ~]# usermod -G  mali jack
[root@CentOS6 ~]# grep mali /etc/group
mali:x:503:sally,jack
[root@CentOS6 ~]# 

حالا فایل های group و gshadow را نگاه کنید. برای گروه mali عضو جدیدی تعریف شده است ولی رمزی برای گروه تعذیف نشده. با دستور gpasswd هم میتوان برای کاربر secondary group تعریف کرد ولی با دستور usermod فرق دارد. تفاوت در کد بالا واضح است. انگار دستور gpasswd با سویچ M- به معنای member list لیست اعضای گروه ها overwrite میکند. با دقت استفاده کنید.

به کد های زیر دقت کنید. اگر میخواهیم که خود کاربر بتواند وارد گروهی شود، میتوانیم برای گروه رمز بگذاریم. البته این عضویت در گروه موقتی است و با خروج کاربر، به گروه قبلی خود بازمیگردد. برای عضویت دائمی میدانید چه باید بکنبم. یه مثال ساده پایین زدم.

[root@CentOS6 ~]# groupadd security
[root@CentOS6 ~]# gpasswd security
Changing the password for group security
New Password: 
Re-enter new password: 
[root@CentOS6 ~]# grep security /etc/gshadow
security:$6$ydWgczUOpFI0t/iB$Xzvy/j4vVYerZ53JBSH.UP3aOocMrQHdO7cCzhLfZarWVt80/MlA08z7..q17dbRptQMrOCepDxo4/saLn2Nr1::
[root@CentOS6 ~]# useradd -N testuser
[root@CentOS6 ~]# id testuser
uid=505(testuser) gid=100(users) groups=100(users)
[root@CentOS6 ~]# passwd testuser
Changing password for user testuser.
New password: 
BAD PASSWORD: it is WAY too short
BAD PASSWORD: is too simple
Retype new password: 
passwd: all authentication tokens updated successfully.
[root@CentOS6 ~]# su - testuser
[testuser@CentOS6 ~]$ 
[testuser@CentOS6 ~]$ whoami
testuser
[testuser@CentOS6 ~]$ pwd
/home/testuser
[testuser@CentOS6 ~]$ 
[testuser@CentOS6 ~]$ 
[testuser@CentOS6 ~]$ id
uid=505(testuser) gid=100(users) groups=100(users) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[testuser@CentOS6 ~]$ 
[testuser@CentOS6 ~]$ newgrp security
Password: 
[testuser@CentOS6 ~]$ id
uid=505(testuser) gid=505(security) groups=100(users),505(security) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[testuser@CentOS6 ~]$ 
[testuser@CentOS6 ~]$ exit
exit
[testuser@CentOS6 ~]$ id
uid=505(testuser) gid=100(users) groups=100(users) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[testuser@CentOS6 ~]$ 
[testuser@CentOS6 ~]$ 

ارتباط با اکتیودایرکتوری

در این جلسه به مبحث مدیریت کاربران Active Directory از طریق سیستم عامل لینوکسی خود میپردازیم. یکی از package هایی که میتوان برای این کار استفاده کرد pbis است. تا اونجایی که من میدونم در repository های پیش فرض centos وجود ندارد و باید یا repository را بروز رسانی کنیم یا فایل نصبی package را دانلود کرده و دستی نصبش کنیم. برای بروز رسانی repository خود از دستور زیر در centos استفاده کنید.

[root@CentOS6 ~]# wget -O /etc/yum.repos.d/pbiso.repo http://repo.pbis.beyondtrust.com/yum/pbiso.repo

چند ثانیه بیشتر بروز رسانی طول نمی کشد. پس از آن میتوانید pbis را نصب کنید.

[root@CentOS6 ~]# yum clean all
[root@CentOS6 ~]# yum install pbis-open

من یک windows server 2012 R2 دارم که روش Active Directory و DNS نصب شده. 2 نکته مهم این است که هر دو سیستم عامل centos و windows server باید از لحاظ زمانی با هم sync باشند. با vm tools این کار را میتوانید انجام دهید و دوم اینکه DNS سرور برای centos ، همون window server قرار داده شده. آی پی windows server رو دادم بهش به عنوان nameserver.پس از اینکه مطمئن شدید 2 تا سیستمتون به هم ارتباط دارن ( با یه پینگ ساده ) دستورات زیر رو توی ترمینال لینوکس وارد کنید. ( فایر وال ویندوز سرور رو خاموش کنید تا پینگ بده، آموزش ایجاد ارتباط بین لینوکس و ویندوز توی vmware تو نت ریخته )

[root@CentOS6 ~]# domainjoin-cli join winserver2012.ir Administrator
Joining to AD Domain:   winserver2012.ir
With Computer DNS Name: CentOS6.winserver2012.ir

Administrator@WINSERVER2012.IR's password: 
Warning: System restart required
Your system has been configured to authenticate to Active Directory for the first time.  It is recommended that you restart your system to ensure that all applications
recognize the new settings.

SUCCESS
[root@CentOS6 ~]# reboot

خط اول که یک دستور اتصال به دامینه، اسم دامین و اکانت ادمین رو باید وارد کنید. بعدش باید سیستم رو reboot کنید.

حالا اگر دستور زیر را در ترمینال وارد کنید، تمام کاربران سیستم لینوکسی و Domain را میبینید.

[root@centos6 ~]# getent passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
rtkit:x:499:496:RealtimeKit:/proc:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/cache/rpcbind:/sbin/nologin
saslauth:x:498:76:"Saslauthd user":/var/empty/saslauth:/sbin/nologin
haldaemon:x:68:68:HAL daemon:/:/sbin/nologin
pulse:x:497:495:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
gdm:x:42:42::/var/lib/gdm:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
mohammad:x:500:500:mohammad:/home/mohammad:/bin/bash
test:x:501:501::/home/test:/bin/bash
dhcpd:x:177:177:DHCP server:/:/sbin/nologin
named:x:25:25:Named:/var/named:/sbin/nologin
apache:x:48:48:Apache:/var/www:/sbin/nologin
jim:x:502:502::/home/jim:/bin/bash
jack:x:503:100::/home/jack:/bin/bash
sally:x:504:100::/home/sally:/bin/bash
testuser:x:505:100::/home/testuser:/bin/bash
WINSERVER2012\administrator:PBIS:1237844468:1237844481::/home/local/WINSERVER2012/administrator:/bin/sh
WINSERVER2012\guest:PBIS:1237844469:1237844482::/home/local/WINSERVER2012/guest:/bin/sh
WINSERVER2012\krbtgt:PBIS:1237844470:1237844481::/home/local/WINSERVER2012/krbtgt:/bin/sh
WINSERVER2012\user1:PBIS:1237845088:1237844481:user1:/home/local/WINSERVER2012/user1:/bin/sh
WINSERVER2012\user2:PBIS:1237845089:1237844481:user2:/home/local/WINSERVER2012/user2:/bin/sh
[root@centos6 ~]# 

اولاش که همه کاربرای سیستم لینوکسی خودمه، چند خط آخر کاربرانیه که نوی Active Directory درست کردم. فرمتش واضحه ... ولی این اطلاعات از کجا میاد ؟؟ اگر کلمه passwd رو از فایل زیر در مسیر etc جستجو کنیم، خروجی زیر را میبینیم:

[root@centos6 ~]# grep passwd /etc/nsswitch.conf
#passwd:    db files nisplus nis
passwd:     files lsass
[root@centos6 ~]# 

فایل nsswitch مشخص میکند که چه سرویسی و از کجا برای مشخص کردن مواردی مثل host name و password و group استفاده بشه. این فایل خیلی توضیخ داره. میتونید فایل رو باز کنید تا همشو ببینید. پارامتر های زیادی داره. حالا همین یه تیکه ای که ما کشیدیم بیرون. خط اول که کامنته مشخص میکنه که خط پایینیش که دستوره، از چه اجرایی تشکیل شده. مثلا برای مشخص کردن پسورد ها ، ائل نوشته files، یعنی ابتدا فایل های local سیستم رو بگرد ( یعنی برو توی فایل etcpasswd و etcpasswd بگرد دنبال چیزی که گفتم. ) بعدش گفته lsass. اصل کار ما اینه. این میره از توی Active Directory اطلاعات کاربرا رو میکشه بیرون. حروفش از local security authority sub systems میاد. این همون پروسه ایه که باهاش به Active Directory وصل شدیم. اگر شما دارید از centos 7 به بالا استفاده میکنید ( که من استفاده نمیکنم ) بعد از files یه sss هم میبینید به معنی system security services هستش که توی این نسخه های جدید centos استفاده شده و توی پیش فرض های سیستم عامله.

هر خط فایل nsswitch مشخص میکند که برای جمع آوری چه اطلاعاتی ، از چه منابعی استفاده کند. این فایل درمورد موارد زیر میتواند به جستجوی اطلاعات بپردازد:

automount Automount (/etc/auto.master and /etc/auto.misc)
bootparams Diskless and other booting options (See the bootparam man page.)
ethers MAC address
group Groups of users (/etc/group )
hosts System information (/etc/hosts )
netgroup Netgroup information (/etc/netgroup )
networks Network information (/etc/networks )
passwd User information (/etc/passwd )
protocols Protocol information (/etc/protocols )
publickey Used for NFS running in secure mode
rpc RPC names and numbers (/etc/rpc )
services Services information (/etc/services )
shadow Shadow password information (/etc/shadow )

بعد از مشخص کردن نوع اطلاعات، مشخص میکند که از چه طریقی آنها را پیدا کند.

files  = > Searches local files such as /etc/passwd and /etc/hosts
nis  => Searches the NIS database; yp is an alias for nis
dns => Queries the DNS (hosts queries only)
compat ± => syntax in passwd, group, and shadow files

پس به ترتیبی که مشخص کردیم، میرود از منابعی که مشخص کردیم، پرس و جو میکند. دیدیم بالاتر که اول نوشته بود files و سپس lsass. اول برو سراغ files بعدش lsass.

حالا بیاید بریم سر یه مبحث دیگه. مثلا کاربری که در Active Directory تعریف شده بتونه یه home directory توی سیستم لینوکسی ما داشته باشه.

به دستورات زیر دقت کنید.

[root@centos6 ~]# mkdir /home/user1

[root@centos6 ~]# chown winserver2012\\user1 /home/user1/

[root@centos6 ~]# ls -ld /home/user1/
drwxr-xr-x. 2 WINSERVER2012\user1 root 4096 Aug 23 21:18 /home/user1/

[root@centos6 ~]# su - winserver2012\\user1
-sh-4.1$ 
-sh-4.1$ 
-sh-4.1$ id
uid=1237845088(WINSERVER2012\user1) gid=1237844481(WINSERVER2012\domain^users) groups=1237844481(WINSERVER2012\domain^users) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
-sh-4.1$ 

یه پوشه پیش فرض واسه کاربران درست کرده بود که توی خروجی دستور getent دیدید. اگر اشتباه نکنم اون پوشه تا زمانی که کاربر log in نکنه ایجاد نمیشه. حالا علاوه بر اون یه پوشه اگر بخوایم درست کنید به ترتیب بالا انجامش میدیم. پس از درست کردن پوشه باید ماکیت اونو با دستور chown به معنی change ownership تغییر بدیم. به ساختار دستور دقت کنید چجوری نوشتم. بعدش با دستور su کاریری که هستم رو تغییر دادم. چون روت بودم ازم رمز نخواست. حالا با نام کاریری user1 که در AD تعریف شده، وارد سیستم شدم.

-sh-4.1$ 
-sh-4.1$ 
-sh-4.1$ whoami
WINSERVER2012\user1
-sh-4.1$ 
-sh-4.1$ pwd
/home/local/WINSERVER2012/user1
-sh-4.1$ 
-sh-4.1$ 
-sh-4.1$ echo $PATH
/usr/lib/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin
-sh-4.1$ 
-sh-4.1$ 

OpenLDAP

در این جلسه به یکی از مباحث مهم در شبکه یعنی ldap میپردازیم. اول از همه باید بفهمیم که چرا به ldap نیاز داریم و اصلا ldap چیست؟؟ ابتدا مقداری مقدمه میگم و بعدش میریم سراغ یک سناریوی عملی، نمیدونم حالا میشه تو یه قسمت جمعش کرد یا نه چیزی رو که میخوام بگم.

مفهوم Directory Service به چه معناست ؟؟

طبق تعریف directory service یک بانک اطلاعاتی است که قدرت آن در جستجو و خواندن اطلاعات با سرعت بالاست. نه اینکه در نوشتن ضعیف باشه، ولی در بعضی شرایط ما نیاز داریم که اطلاعاتی را با سرعت بالا از بانک اطلاعاتی بخوانیم. در چنین بانک های اطلاعاتی یک رکورد یا یک entry یک بار نوشته میشود ولی قرار است هزاران هزار بار خوانده شود، پس باید سرعت خواندن اطلاعات بالا یاشد. ساده ترین directory service یک دفترچه تلفن است. وقتی مثلا نام ali را ذخیره میکنیم، میرویم در قسمت حرف a نام او را ذخیره میکنیم. بعدا هم وقتی دنبال او بگردیم، میرویم فقط قسمت a را جستجو میکنیم، نه کل دفترچه. در اینجا ali یک object یا entry است. این object میتواند attribute هم داشته باشد مثل ایمیل و آدرس و ... . پس Directory Service یک سیستم درختی است. در حقیقت Directory Service یک سیستم جستجو گر است که میتوان نتیجه یک جستجو را trace کرد که از کجا آمده. یه شکل زیر دقت کنید.

سلام و وقت بخیر. در این جلسه به یکی از مباحث مهم در شبکه یعنی ldap میپردازیم. اول از همه باید بفهمیم که چرا به ldap نیاز داریم و اصلا ldap چیست؟؟ ابتدا مقداری مقدمه میگم و بعدش میریم سراغ یک سناریوی عملی، نمیدونم حالا میشه تو یه قسمت جمعش کرد یا نه چیزی رو که میخوام بگم.

*مفهوم Directory Service به چه معناست ؟؟ *
طبق تعریف directory service یک بانک اطلاعاتی است که قدرت آن در جستجو و خواندن اطلاعات با سرعت بالاست. نه اینکه در نوشتن ضعیف باشه، ولی در بعضی شرایط ما نیاز داریم که اطلاعاتی را با سرعت بالا از بانک اطلاعاتی بخوانیم. در چنین بانک های اطلاعاتی یک رکورد یا یک entry یک بار نوشته میشود ولی قرار است هزاران هزار بار خوانده شود، پس باید سرعت خواندن اطلاعات بالا یاشد. ساده ترین directory service یک دفترچه تلفن است. وقتی مثلا نام ali را ذخیره میکنیم، میرویم در قسمت حرف a نام او را ذخیره میکنیم. بعدا هم وقتی دنبال او بگردیم، میرویم فقط قسمت a را جستجو میکنیم، نه کل دفترچه. در اینجا ali یک object یا entry است. این object میتواند  attribute هم داشته باشد مثل ایمیل و آدرس و ... . پس Directory Service یک سیستم درختی است. در حقیقت Directory Service یک سیستم جستجو گر است که میتوان نتیجه یک جستجو را trace کرد که از کجا آمده. یه شکل زیر دقت کنید.
<center>
||http://tosinso.com/files/get/7e569dbb-0c88-448f-bb46-13f753994975||
<center>
فرض کنید یک پایگاه داده داریم که شامل تمام کمپانی های دنیا است. دنیال یک شخص خاص در این پایگاه داده میگردیم. بصورت درختی به جستجو میپردازیم. اول میپرسی که در کدام کشور است ؟ مثلا آمریکا، خوب بقیه کشور ها رو میزاریم کنار. در کدام ایالت است؟ کالیفورنیا، نام کمپانی او چیست؟ مثلا acme ، در کدام بخش کار میکند ؟ فروش، نامش چیست ؟ barbara jenson . این یک جستجوی درختی بود. در چنین سیستمی فقط قسمتی از پایگاه داده که لازم است رو جستجو میکنیم نه همشو. در ضمن سرعت جستجو هم باید بالا باشد. این یک سیستم میتنی بر Directory Service است. حال برای اینکه بتوان اطلاعات را در Directory Service ذخیره کرد و به این صورت که گفتیم قابل جستجو باشند، نیاز به یک استاندارد خاص دخیره سازی اطلاعات است. این استاندارد x500 نام دارد. به شکل نگاه کنید ( نخندید!!! با paint کشیدم !!! )
<center>
||http://tosinso.com/files/get/4d2b5ff1-0f43-4114-a6d3-8480166382c0||
<center>
اطلاعات با استاندارد x500 بصورت زیر درختی و زیر شاخه ای ذخیره میشود. حال برای دسترسی به این اطلاعات باید از یه پروتکلی استفاده کنیم. این پروتکل در قدیم dap نام داشت که نسخه بهبود یافته آن شد ldap. پروتکل dap سنگین بود و منابع زیادی مصرف میکرد ولی ldap که از اسمش هم مشخصه Lightweight Directory Access Protocol همون dap سبک شده است. پروتکل ldap محصول IBM و Microsoft است. به سروری که اطلاعات رو با استاندارد x500 ذخیره میکنه میگیم ldap server . پس ldap یک پروتکل دسترسی است. خود ldap server به تنهایی پایگاه داده ندارد. در آن یک پایگاه داده میسازیم. اگر ldap server بخواهیم داشته باشیم، در ویندوز، Active Directory و در لینوکس هم OpenLDAP نصب میکنیم. تمام این ها از استاندارد x500 استفاده میکنند. ماکروسافت بانک اطلاعاتی خودشو داره توی AD ولی نام پایگاه داده لینوکس BDB است. استفاده از ldap server  باید توجیه پذیر باشد. مثلا بانک ها از چنین سرویسی استفاده نمیکنند و به جای ldap server از oracle استفاده میکنند. البته ممکنه چیزای دیگه ای مثل آرشیوشون یا اطلاعات سازمانی رو روی ldap server نگه دارن ولی اطلاعات مالی و تراکنش مالی که هر روز انجام میشه رو نه ( چرا ؟؟؟ اینو دیگه خودم نمیگم، شما بگید !!! )
پس کلا اطلاعاتی رو روی ldap server میبریم که قراره یک بار نوشته بشه ولی هزاران بار توسط کاربران یا برنامه ها خونده بشه و استفاده بشه. کلا سرعت read بالا میخوایم نه write خیلی بالا.
بسیار خوب. فک میکنم واسه مقدمه کافیه چون بحث خیلی گستردس نمیشه جمعش کرد. بریم سراغ نصب ldap server روی  5.8 centos
فقط یادتون باشه object هایی که درست میکنیم لینوکسی نیستن، ینی اگه یه کاربر ساختیم نمیتونه تو سیستم log in کنه. اون بحثش یه چیز دیگس. اون میره توی بحثای مربوط به samba.

*Open LDAP* 
در ترمینال خود دستور زیر را برای نصب package های لازم وارد کنید.
<c#>
[root@localhost ~]# yum install openldap openldap-clients openldap-servers
<c#>
بعد از اینکه نصب شد میتونم چک کنم
<c#>
[root@localhost ~]# rpm -qa | grep openldap
openldap-clients-2.3.43-29.el5_11
openldap-2.3.43-29.el5_11
openldap-servers-2.3.43-29.el5_11
[root@localhost ~]# 
<c#>
دیدید که 3 تا package نیاز دارم. استاندارد x500 با نصب openldap server نصب شد. openldap client که ابزارهای وصل شذن به این پایگاه داده و مدیریتشه. openldap هم که لازمه جفتشه. 
حالا این openldap server یک فایل کانفیگ داره. بر خلاف انتظار، این فایلی که پایین نوشتم نیست !!! این کامفیگ فایل کاربره نه سرورو تنظیمات کاربر توی این وارد میشه
<c#>
/etc/openldap/ldap.conf
<c#>
تنظیمات مربوط به سرور توی slapd.conf قرار داره.
<c#>
[root@localhost ~]# cd /etc/openldap/
[root@localhost openldap]# ls
cacerts  DB_CONFIG.example  ldap.conf  schema  slapd.conf
[root@localhost openldap]# 
<c#>
فایل slapd.conf رو با یه ادیتور باز کنید. توی خط 86 و 87 و 93 اطلاعات رو مطابق شکل زیر تغییر بدبد. این شکلی بشه.
<center>
||http://tosinso.com/files/get/087798d5-f93c-4a38-81dd-f51fc518bb03||
<center>
حالا اینا چی هست ؟؟ اون فایل هایی که بالای سند include شدن schema هستن برای ldap server ... این schema ها ساختاری برای ایجاد همون پایگاه داده با استامدارد x500 هستن. اینا schema های پایه هستن. مثلا اگه میخوام samba رو هم با ldap ی که دارم integrate کنم ، بعد از اینکه samba رو نصب کردم، برم فایل های schema ی samba رو پیدا کنم، برم توی پوشه schema های ldap کپیش کنم و بعدش بیام توی این فایل include کنمش. هر برنامه ای که بخواد با ldap سرور integrate بشه باید object های برنامه واسه ldap تعریف شده باشه، object ها هم توی schema تعریف میشه. توی عکسی که از فایل slapd گذاشتم میبینید که نوشته پایگاه داده BDB باشه، suffix میگه این قراره کانفیگ فایل چه دامینی باشه؟ حالا مثلا سازمانمون tosinso.com باشه. این فرمت رو باید رعایت کنید. dc یعنی domain component . خط بعد میگه حالا کاربر ارشد این ldap server کیه ؟ کاربر ارشد اینجا manager نام داره. باز اون فرمت رو رعایت کنید. مدیر توی کدوم دامین قرار داره؟ cn یعنی common name . بعدشم دامین مدیر ارشد رو مشخص کردیم. خط بعدش رمز کاربر ارشد رو میخواد. میتونیم رمز رو بصورت clear text اینجا بنویسیم، میتونیم هش شده رمز رو خط بعد بنویسیم. فایل رو ذخیره کنید و سرویس رو روشن کنید. بعدش پورت هایی که listen میشن رو چک کنید. ldap روی پورت 389  در حالت پیش فرض کار میکنه.
<c#>
[root@localhost openldap]# /etc/init.d/ldap start
Starting slapd:                                            [  OK  ]
[root@localhost openldap]# netstat -antp | grep 389
tcp        0      0 0.0.0.0:389                 0.0.0.0:*                   LISTEN      8252/slapd          
tcp        0      0 :::389                      :::*                        LISTEN      8252/slapd          
[root@localhost openldap]# 
<c#>
سرویس ldap راه افتاد ولی هنوز بانک اطلاعاتیمون خالیه. باید توش اطلاعات وارد کنیم. با دستور ldapadd ما میتونیم object اضافه کنیم. این object میتونه سازمان باشه، میتونه بخش سازمانی باشه، میتونه کارمند باشه. دستور زیر رو وارد کنید تا همه پایگاه داده رو نشون بده.
<c#>
[root@localhost openldap]# ldapsearch -x -b dc=itpro,dc=com (objectclass=*)
# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# search result
search: 2
result: 32 No such object

# numResponses: 1
[root@localhost openldap]# 
<c#>
نوشتن objectclass برابر * یعنی همه رو نشون بده. محدوده جستجو رو گذاشتم از کل دامین ، با سویچ b- و دادن نام دامین. x-هم یعنی از سیستم simple authentication استفاده کن. حالا این چیزی برنگردوند چون پایگاه داده خالیه. حالا ما میخوایم ریشه سازمان رو تعریف کنیم، دپارتمان ها رو اضافه کنیم، بعدش کارمند ها رو اضافه کنیم. اطلاعاتی که میخوام وارد کنم رو توی یک فایل میریزم که باید با فرمت ldif نوشته شده باشن. ldap data interchange format .  دستور ldapadd خیلی سویچ داره. یه کوچولوشو میگیم اینجا. W- یعنی تقاضای رمز کن. با f- هم فایل ldif رو نشونش میدم. x- هم یعنی simple authentication بکن. D- یعنی با چه یوزری از کدوم دامین میخوای وارد بشی. یک فایل به اسم build-root-ou.ldif درست کنید. اطلاعات زیر رو واردش کنید.
<c#>
dn: dc=itpro,dc=com
objectclass: dcObject
objectclass: organization
o: itpro
dc: itpro
<c#>
یه dn درست کردم به همراه صفاتش . dn ریشه سازمان رو تو دل خودش داره. dn یعنی distinguished name . ریشه سازمان رو ساختم. هر object که اضافه میکینم باید dn یکتا داشته باشه. خط پایین dc:itpro یک صفته. خط آخر هم o یک صفنه یعنی organization. برای هر object حداقل یک objectclass باشد تعریف بشه. معمولا برای تعریف سازمان، 2 تا objectclass که نوشتم رو استفاده میکنن. اینا صفات رو تعریف میکنن. یعنی من اگه خواستم صفات تعریف کنم واسه سازمانم، از صفات تعریف شد توی objectclass میتونم استفاده کنم نه هر صفنی.
حالا این فایل رو باید به پایگاه داده اضافه کنم.
<c#>
[root@localhost openldap]# ldapadd -D cn=Manager,dc=itpro,dc=com  -W -x -f build_root_ou.ldif
<c#>
اگه همه چی رو درست وارد کرده باشید، entry به درستی در پتیگاه داده وارد میشه.
برای تست کردن اینکه فایل slap.d رو درست کانفیگ کردید یا نه دستور زیر رو بزنید
<c#>
[root@localhost openldap]# ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
# extended LDIF
#
# LDAPv3
# base <> with scope baseObject
# filter: (objectclass=*)
# requesting: namingContexts 
#

#
dn:
namingContexts: dc=itpro,dc=com

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
[root@localhost openldap]# 
<c#>
حالا اگه دوباره از پایگاه داده query بگیریم
<c#>
[root@localhost openldap]# ldapsearch -x -b dc=itpro,dc=com (objectclass=*)
# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# itpro.com
dn: dc=itpro,dc=com
objectClass: dcObject
objectClass: organization
o: itpro
dc: itpro

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
[root@localhost openldap]# 
<c#>
حالا میخوام مدیر سازمان رو اضافه کنم. یک فایل به اسم add-manager.ldif درست میکنم
<c#>
dn: cn=Manager,dc=itpro,dc=com
objectclass: organizationalRole
cn: Manager
<c#>
اینطوری هم اضافش میکنم به پایگاه داده
<c#>
[root@localhost openldap]# ldapadd -D cn=Manager,dc=itpro,dc=com -h localhost -W -x -f build_manager.ldif
Enter LDAP Password: 
adding new entry cn=Manager,dc=itpro,dc=com

[root@localhost openldap]#
<c#>
حالا اگه دوباره از پایگاه داده query بگیرم، مدیر اضافه شده
<c#>
[root@localhost openldap]# ldapsearch -x -b dc=itpro,dc=com (objectclass=*)# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# itpro.com
dn: dc=itpro,dc=com
objectClass: dcObject
objectClass: organization
o: itpro
dc: itpro

# Manager, itpro.com
dn: cn=Manager,dc=itpro,dc=com
objectClass: organizationalRole
cn: Manager

# search result
search: 2
result: 0 Success

# numResponses: 3
# numEntries: 2
[root@localhost openldap]# 
<c#>
حالا که سازمان درست شد، میخوام بخش های مختلف سازمان رو اضافه کنم. مثلا سازمان 3 تا دپارتمان داره.
<c#>
dn: ou=linux,dc=itpro,dc=com
ou: linux
objectclass: organizationalunit

dn: ou=software,dc=itpro,dc=com
ou: software
objectclass: organizationalunit

dn: ou=hardware,dc=itpro,dc=com
ou: hardware
objectclass: organizationalunit
<c#>
اگه space نذارید بین خط ها کار نمیکنه، آخر خط ها هم space بزنید بازم کار نمیکنه !!! کلا ldap خیلی گیره سر این چیزا. میبینید سر یه space توی کانفیگ فایل، کلا سرور آپ نمیشه !!!
حالا دپارتمان ها رو اضافه میکنم
<c#>
[root@localhost openldap]# ldapadd -D cn=Manager,dc=itpro,dc=com -h localhost -W -x -f build_dep.ldif
Enter LDAP Password: 
adding new entry ou=linux,dc=itpro,dc=com

adding new entry ou=software,dc=itpro,dc=com

adding new entry ou=hardware,dc=itpro,dc=com

[root@localhost openldap]#
<c#>
پایگاه دادم اینجوری شد
<c#>
[root@localhost openldap]# ldapsearch -x -b dc=itpro,dc=com (objectclass=*)
# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# itpro.com
dn: dc=itpro,dc=com
objectClass: dcObject
objectClass: organization
o: itpro
dc: itpro

# Manager, itpro.com
dn: cn=Manager,dc=itpro,dc=com
objectClass: organizationalRole
cn: Manager

# linux, itpro.com
dn: ou=linux,dc=itpro,dc=com
ou: linux
objectClass: organizationalUnit

# software, itpro.com
dn: ou=software,dc=itpro,dc=com
ou: software
objectClass: organizationalUnit

# hardware, itpro.com
dn: ou=hardware,dc=itpro,dc=com
ou: hardware
objectClass: organizationalUnit

# search result
search: 2
result: 0 Success

# numResponses: 6
# numEntries: 5
[root@localhost openldap]# 
<c#>
حالا میخوام یک کارمند اضافه کنم. یک فایل جدید با ldif درست میکنم.
<c#>
dn: cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com
cn: Mohammad Nasiri
sn: UNITY
mail: unity@itpro.com
departmentNumber: software
telephoneNumber: 203-543-8958
objectclass: inetOrgPerson
<c#>
حالا اضافه میکنیم به پایگاه داده:
<c#>
[root@localhost openldap]# ldapadd -D cn=Manager,dc=itpro,dc=com -h localhost -W -x -f build_worker.ldif
Enter LDAP Password: 
adding new entry cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com

[root@localhost openldap]# 
<c#>
محمد نصیری اضافه شد !!!  :))) این یه تیکه از خروجی دستور ldapsearch هستش. دقت کنید که هر object یک cn منحصر به فرد داره.
<c#>
# Mohammad Nasiri, software, itpro.com
dn: cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com
cn: Mohammad Nasiri
sn: UNITY
mail: unity@itpro.com
departmentNumber: software
telephoneNumber: 203-543-8958
objectClass: inetOrgPerson
<c#>
دقت کنید که برای یک شخص در سازمان و یک بخش از سازمان از objectclass های متفاوتی استفاده کردم. پس هر برنامه ای نصب کردید یا خواستیذ کلا چیزی به پایگاه داده اضافه کنید باید بدونید objectclass اون چیه.
حالا قراره یک نفر رو از سازمان خارج کنیم!!!
<c#>
[root@localhost openldap]# ldapdelete -D cn=Manager,dc=itpro,dc=com -W -x -v cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com

Enter LDAP Password: 
deleting entry cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com

[root@localhost openldap]#
<c#>
با دستور ldapmodify هم میتونید اطلاعات یک object  رو تغییر بدید. دستور ldapsearch رو هم میشه محدودش کرد که کجا رو جستجو کنه. از regex و wildcard و این جور چیزا میشه توش استفاده کرد. به عهده خودتون اینا. بحث ldap خیلی گستردس، اینجا فقط در حد اینکه یه ذهنیتی ایجاد بشه صحبت کردیم. اگر بخوایم ldap server رو با Active Directory و یا خود کاربران لینوکسی ترکیب کنیم و یا از سیستم های احراز هویت و این جور چیزا استفاده کنیم، وارد یکی از حوزه های بزرگ لینوکس به نام mix environment میشیم که موضوعش درمورد integrate کردن سیستم های لینوکسی و ماکروسافته.
خسته نباشید. این بخش تمام شد. تا بخش بعدی.
پایان قسمت چهارم ( آخر) از بخش سوم

نویسنده : سید محمد باقر موسوی
منبع : |جزیره لینوکس و سیستم های متن باز وب سایت توسینسو::https://linux.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی است

فرض کنید یک پایگاه داده داریم که شامل تمام کمپانی های دنیا است. دنیال یک شخص خاص در این پایگاه داده میگردیم. بصورت درختی به جستجو میپردازیم. اول میپرسی که در کدام کشور است ؟ مثلا آمریکا، خوب بقیه کشور ها رو میزاریم کنار. در کدام ایالت است؟ کالیفورنیا، نام کمپانی او چیست؟ مثلا acme ، در کدام بخش کار میکند ؟ فروش، نامش چیست ؟ barbara jenson . این یک جستجوی درختی بود. در چنین سیستمی فقط قسمتی از پایگاه داده که لازم است رو جستجو میکنیم نه همشو. در ضمن سرعت جستجو هم باید بالا باشد. این یک سیستم میتنی بر Directory Service است. حال برای اینکه بتوان اطلاعات را در Directory Service ذخیره کرد و به این صورت که گفتیم قابل جستجو باشند، نیاز به یک استاندارد خاص دخیره سازی اطلاعات است. این استاندارد x500 نام دارد. به شکل نگاه کنید ( نخندید!!! با paint کشیدم !!! )

سلام و وقت بخیر. در این جلسه به یکی از مباحث مهم در شبکه یعنی ldap میپردازیم. اول از همه باید بفهمیم که چرا به ldap نیاز داریم و اصلا ldap چیست؟؟ ابتدا مقداری مقدمه میگم و بعدش میریم سراغ یک سناریوی عملی، نمیدونم حالا میشه تو یه قسمت جمعش کرد یا نه چیزی رو که میخوام بگم.

*مفهوم Directory Service به چه معناست ؟؟ *
طبق تعریف directory service یک بانک اطلاعاتی است که قدرت آن در جستجو و خواندن اطلاعات با سرعت بالاست. نه اینکه در نوشتن ضعیف باشه، ولی در بعضی شرایط ما نیاز داریم که اطلاعاتی را با سرعت بالا از بانک اطلاعاتی بخوانیم. در چنین بانک های اطلاعاتی یک رکورد یا یک entry یک بار نوشته میشود ولی قرار است هزاران هزار بار خوانده شود، پس باید سرعت خواندن اطلاعات بالا یاشد. ساده ترین directory service یک دفترچه تلفن است. وقتی مثلا نام ali را ذخیره میکنیم، میرویم در قسمت حرف a نام او را ذخیره میکنیم. بعدا هم وقتی دنبال او بگردیم، میرویم فقط قسمت a را جستجو میکنیم، نه کل دفترچه. در اینجا ali یک object یا entry است. این object میتواند  attribute هم داشته باشد مثل ایمیل و آدرس و ... . پس Directory Service یک سیستم درختی است. در حقیقت Directory Service یک سیستم جستجو گر است که میتوان نتیجه یک جستجو را trace کرد که از کجا آمده. یه شکل زیر دقت کنید.
<center>
||http://tosinso.com/files/get/7e569dbb-0c88-448f-bb46-13f753994975||
<center>
فرض کنید یک پایگاه داده داریم که شامل تمام کمپانی های دنیا است. دنیال یک شخص خاص در این پایگاه داده میگردیم. بصورت درختی به جستجو میپردازیم. اول میپرسی که در کدام کشور است ؟ مثلا آمریکا، خوب بقیه کشور ها رو میزاریم کنار. در کدام ایالت است؟ کالیفورنیا، نام کمپانی او چیست؟ مثلا acme ، در کدام بخش کار میکند ؟ فروش، نامش چیست ؟ barbara jenson . این یک جستجوی درختی بود. در چنین سیستمی فقط قسمتی از پایگاه داده که لازم است رو جستجو میکنیم نه همشو. در ضمن سرعت جستجو هم باید بالا باشد. این یک سیستم میتنی بر Directory Service است. حال برای اینکه بتوان اطلاعات را در Directory Service ذخیره کرد و به این صورت که گفتیم قابل جستجو باشند، نیاز به یک استاندارد خاص دخیره سازی اطلاعات است. این استاندارد x500 نام دارد. به شکل نگاه کنید ( نخندید!!! با paint کشیدم !!! )
<center>
||http://tosinso.com/files/get/4d2b5ff1-0f43-4114-a6d3-8480166382c0||
<center>
اطلاعات با استاندارد x500 بصورت زیر درختی و زیر شاخه ای ذخیره میشود. حال برای دسترسی به این اطلاعات باید از یه پروتکلی استفاده کنیم. این پروتکل در قدیم dap نام داشت که نسخه بهبود یافته آن شد ldap. پروتکل dap سنگین بود و منابع زیادی مصرف میکرد ولی ldap که از اسمش هم مشخصه Lightweight Directory Access Protocol همون dap سبک شده است. پروتکل ldap محصول IBM و Microsoft است. به سروری که اطلاعات رو با استاندارد x500 ذخیره میکنه میگیم ldap server . پس ldap یک پروتکل دسترسی است. خود ldap server به تنهایی پایگاه داده ندارد. در آن یک پایگاه داده میسازیم. اگر ldap server بخواهیم داشته باشیم، در ویندوز، Active Directory و در لینوکس هم OpenLDAP نصب میکنیم. تمام این ها از استاندارد x500 استفاده میکنند. ماکروسافت بانک اطلاعاتی خودشو داره توی AD ولی نام پایگاه داده لینوکس BDB است. استفاده از ldap server  باید توجیه پذیر باشد. مثلا بانک ها از چنین سرویسی استفاده نمیکنند و به جای ldap server از oracle استفاده میکنند. البته ممکنه چیزای دیگه ای مثل آرشیوشون یا اطلاعات سازمانی رو روی ldap server نگه دارن ولی اطلاعات مالی و تراکنش مالی که هر روز انجام میشه رو نه ( چرا ؟؟؟ اینو دیگه خودم نمیگم، شما بگید !!! )
پس کلا اطلاعاتی رو روی ldap server میبریم که قراره یک بار نوشته بشه ولی هزاران بار توسط کاربران یا برنامه ها خونده بشه و استفاده بشه. کلا سرعت read بالا میخوایم نه write خیلی بالا.
بسیار خوب. فک میکنم واسه مقدمه کافیه چون بحث خیلی گستردس نمیشه جمعش کرد. بریم سراغ نصب ldap server روی  5.8 centos
فقط یادتون باشه object هایی که درست میکنیم لینوکسی نیستن، ینی اگه یه کاربر ساختیم نمیتونه تو سیستم log in کنه. اون بحثش یه چیز دیگس. اون میره توی بحثای مربوط به samba.

*Open LDAP* 
در ترمینال خود دستور زیر را برای نصب package های لازم وارد کنید.
<c#>
[root@localhost ~]# yum install openldap openldap-clients openldap-servers
<c#>
بعد از اینکه نصب شد میتونم چک کنم
<c#>
[root@localhost ~]# rpm -qa | grep openldap
openldap-clients-2.3.43-29.el5_11
openldap-2.3.43-29.el5_11
openldap-servers-2.3.43-29.el5_11
[root@localhost ~]# 
<c#>
دیدید که 3 تا package نیاز دارم. استاندارد x500 با نصب openldap server نصب شد. openldap client که ابزارهای وصل شذن به این پایگاه داده و مدیریتشه. openldap هم که لازمه جفتشه. 
حالا این openldap server یک فایل کانفیگ داره. بر خلاف انتظار، این فایلی که پایین نوشتم نیست !!! این کامفیگ فایل کاربره نه سرورو تنظیمات کاربر توی این وارد میشه
<c#>
/etc/openldap/ldap.conf
<c#>
تنظیمات مربوط به سرور توی slapd.conf قرار داره.
<c#>
[root@localhost ~]# cd /etc/openldap/
[root@localhost openldap]# ls
cacerts  DB_CONFIG.example  ldap.conf  schema  slapd.conf
[root@localhost openldap]# 
<c#>
فایل slapd.conf رو با یه ادیتور باز کنید. توی خط 86 و 87 و 93 اطلاعات رو مطابق شکل زیر تغییر بدبد. این شکلی بشه.
<center>
||http://tosinso.com/files/get/087798d5-f93c-4a38-81dd-f51fc518bb03||
<center>
حالا اینا چی هست ؟؟ اون فایل هایی که بالای سند include شدن schema هستن برای ldap server ... این schema ها ساختاری برای ایجاد همون پایگاه داده با استامدارد x500 هستن. اینا schema های پایه هستن. مثلا اگه میخوام samba رو هم با ldap ی که دارم integrate کنم ، بعد از اینکه samba رو نصب کردم، برم فایل های schema ی samba رو پیدا کنم، برم توی پوشه schema های ldap کپیش کنم و بعدش بیام توی این فایل include کنمش. هر برنامه ای که بخواد با ldap سرور integrate بشه باید object های برنامه واسه ldap تعریف شده باشه، object ها هم توی schema تعریف میشه. توی عکسی که از فایل slapd گذاشتم میبینید که نوشته پایگاه داده BDB باشه، suffix میگه این قراره کانفیگ فایل چه دامینی باشه؟ حالا مثلا سازمانمون tosinso.com باشه. این فرمت رو باید رعایت کنید. dc یعنی domain component . خط بعد میگه حالا کاربر ارشد این ldap server کیه ؟ کاربر ارشد اینجا manager نام داره. باز اون فرمت رو رعایت کنید. مدیر توی کدوم دامین قرار داره؟ cn یعنی common name . بعدشم دامین مدیر ارشد رو مشخص کردیم. خط بعدش رمز کاربر ارشد رو میخواد. میتونیم رمز رو بصورت clear text اینجا بنویسیم، میتونیم هش شده رمز رو خط بعد بنویسیم. فایل رو ذخیره کنید و سرویس رو روشن کنید. بعدش پورت هایی که listen میشن رو چک کنید. ldap روی پورت 389  در حالت پیش فرض کار میکنه.
<c#>
[root@localhost openldap]# /etc/init.d/ldap start
Starting slapd:                                            [  OK  ]
[root@localhost openldap]# netstat -antp | grep 389
tcp        0      0 0.0.0.0:389                 0.0.0.0:*                   LISTEN      8252/slapd          
tcp        0      0 :::389                      :::*                        LISTEN      8252/slapd          
[root@localhost openldap]# 
<c#>
سرویس ldap راه افتاد ولی هنوز بانک اطلاعاتیمون خالیه. باید توش اطلاعات وارد کنیم. با دستور ldapadd ما میتونیم object اضافه کنیم. این object میتونه سازمان باشه، میتونه بخش سازمانی باشه، میتونه کارمند باشه. دستور زیر رو وارد کنید تا همه پایگاه داده رو نشون بده.
<c#>
[root@localhost openldap]# ldapsearch -x -b dc=itpro,dc=com (objectclass=*)
# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# search result
search: 2
result: 32 No such object

# numResponses: 1
[root@localhost openldap]# 
<c#>
نوشتن objectclass برابر * یعنی همه رو نشون بده. محدوده جستجو رو گذاشتم از کل دامین ، با سویچ b- و دادن نام دامین. x-هم یعنی از سیستم simple authentication استفاده کن. حالا این چیزی برنگردوند چون پایگاه داده خالیه. حالا ما میخوایم ریشه سازمان رو تعریف کنیم، دپارتمان ها رو اضافه کنیم، بعدش کارمند ها رو اضافه کنیم. اطلاعاتی که میخوام وارد کنم رو توی یک فایل میریزم که باید با فرمت ldif نوشته شده باشن. ldap data interchange format .  دستور ldapadd خیلی سویچ داره. یه کوچولوشو میگیم اینجا. W- یعنی تقاضای رمز کن. با f- هم فایل ldif رو نشونش میدم. x- هم یعنی simple authentication بکن. D- یعنی با چه یوزری از کدوم دامین میخوای وارد بشی. یک فایل به اسم build-root-ou.ldif درست کنید. اطلاعات زیر رو واردش کنید.
<c#>
dn: dc=itpro,dc=com
objectclass: dcObject
objectclass: organization
o: itpro
dc: itpro
<c#>
یه dn درست کردم به همراه صفاتش . dn ریشه سازمان رو تو دل خودش داره. dn یعنی distinguished name . ریشه سازمان رو ساختم. هر object که اضافه میکینم باید dn یکتا داشته باشه. خط پایین dc:itpro یک صفته. خط آخر هم o یک صفنه یعنی organization. برای هر object حداقل یک objectclass باشد تعریف بشه. معمولا برای تعریف سازمان، 2 تا objectclass که نوشتم رو استفاده میکنن. اینا صفات رو تعریف میکنن. یعنی من اگه خواستم صفات تعریف کنم واسه سازمانم، از صفات تعریف شد توی objectclass میتونم استفاده کنم نه هر صفنی.
حالا این فایل رو باید به پایگاه داده اضافه کنم.
<c#>
[root@localhost openldap]# ldapadd -D cn=Manager,dc=itpro,dc=com  -W -x -f build_root_ou.ldif
<c#>
اگه همه چی رو درست وارد کرده باشید، entry به درستی در پتیگاه داده وارد میشه.
برای تست کردن اینکه فایل slap.d رو درست کانفیگ کردید یا نه دستور زیر رو بزنید
<c#>
[root@localhost openldap]# ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
# extended LDIF
#
# LDAPv3
# base <> with scope baseObject
# filter: (objectclass=*)
# requesting: namingContexts 
#

#
dn:
namingContexts: dc=itpro,dc=com

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
[root@localhost openldap]# 
<c#>
حالا اگه دوباره از پایگاه داده query بگیریم
<c#>
[root@localhost openldap]# ldapsearch -x -b dc=itpro,dc=com (objectclass=*)
# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# itpro.com
dn: dc=itpro,dc=com
objectClass: dcObject
objectClass: organization
o: itpro
dc: itpro

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
[root@localhost openldap]# 
<c#>
حالا میخوام مدیر سازمان رو اضافه کنم. یک فایل به اسم add-manager.ldif درست میکنم
<c#>
dn: cn=Manager,dc=itpro,dc=com
objectclass: organizationalRole
cn: Manager
<c#>
اینطوری هم اضافش میکنم به پایگاه داده
<c#>
[root@localhost openldap]# ldapadd -D cn=Manager,dc=itpro,dc=com -h localhost -W -x -f build_manager.ldif
Enter LDAP Password: 
adding new entry cn=Manager,dc=itpro,dc=com

[root@localhost openldap]#
<c#>
حالا اگه دوباره از پایگاه داده query بگیرم، مدیر اضافه شده
<c#>
[root@localhost openldap]# ldapsearch -x -b dc=itpro,dc=com (objectclass=*)# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# itpro.com
dn: dc=itpro,dc=com
objectClass: dcObject
objectClass: organization
o: itpro
dc: itpro

# Manager, itpro.com
dn: cn=Manager,dc=itpro,dc=com
objectClass: organizationalRole
cn: Manager

# search result
search: 2
result: 0 Success

# numResponses: 3
# numEntries: 2
[root@localhost openldap]# 
<c#>
حالا که سازمان درست شد، میخوام بخش های مختلف سازمان رو اضافه کنم. مثلا سازمان 3 تا دپارتمان داره.
<c#>
dn: ou=linux,dc=itpro,dc=com
ou: linux
objectclass: organizationalunit

dn: ou=software,dc=itpro,dc=com
ou: software
objectclass: organizationalunit

dn: ou=hardware,dc=itpro,dc=com
ou: hardware
objectclass: organizationalunit
<c#>
اگه space نذارید بین خط ها کار نمیکنه، آخر خط ها هم space بزنید بازم کار نمیکنه !!! کلا ldap خیلی گیره سر این چیزا. میبینید سر یه space توی کانفیگ فایل، کلا سرور آپ نمیشه !!!
حالا دپارتمان ها رو اضافه میکنم
<c#>
[root@localhost openldap]# ldapadd -D cn=Manager,dc=itpro,dc=com -h localhost -W -x -f build_dep.ldif
Enter LDAP Password: 
adding new entry ou=linux,dc=itpro,dc=com

adding new entry ou=software,dc=itpro,dc=com

adding new entry ou=hardware,dc=itpro,dc=com

[root@localhost openldap]#
<c#>
پایگاه دادم اینجوری شد
<c#>
[root@localhost openldap]# ldapsearch -x -b dc=itpro,dc=com (objectclass=*)
# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# itpro.com
dn: dc=itpro,dc=com
objectClass: dcObject
objectClass: organization
o: itpro
dc: itpro

# Manager, itpro.com
dn: cn=Manager,dc=itpro,dc=com
objectClass: organizationalRole
cn: Manager

# linux, itpro.com
dn: ou=linux,dc=itpro,dc=com
ou: linux
objectClass: organizationalUnit

# software, itpro.com
dn: ou=software,dc=itpro,dc=com
ou: software
objectClass: organizationalUnit

# hardware, itpro.com
dn: ou=hardware,dc=itpro,dc=com
ou: hardware
objectClass: organizationalUnit

# search result
search: 2
result: 0 Success

# numResponses: 6
# numEntries: 5
[root@localhost openldap]# 
<c#>
حالا میخوام یک کارمند اضافه کنم. یک فایل جدید با ldif درست میکنم.
<c#>
dn: cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com
cn: Mohammad Nasiri
sn: UNITY
mail: unity@itpro.com
departmentNumber: software
telephoneNumber: 203-543-8958
objectclass: inetOrgPerson
<c#>
حالا اضافه میکنیم به پایگاه داده:
<c#>
[root@localhost openldap]# ldapadd -D cn=Manager,dc=itpro,dc=com -h localhost -W -x -f build_worker.ldif
Enter LDAP Password: 
adding new entry cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com

[root@localhost openldap]# 
<c#>
محمد نصیری اضافه شد !!!  :))) این یه تیکه از خروجی دستور ldapsearch هستش. دقت کنید که هر object یک cn منحصر به فرد داره.
<c#>
# Mohammad Nasiri, software, itpro.com
dn: cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com
cn: Mohammad Nasiri
sn: UNITY
mail: unity@itpro.com
departmentNumber: software
telephoneNumber: 203-543-8958
objectClass: inetOrgPerson
<c#>
دقت کنید که برای یک شخص در سازمان و یک بخش از سازمان از objectclass های متفاوتی استفاده کردم. پس هر برنامه ای نصب کردید یا خواستیذ کلا چیزی به پایگاه داده اضافه کنید باید بدونید objectclass اون چیه.
حالا قراره یک نفر رو از سازمان خارج کنیم!!!
<c#>
[root@localhost openldap]# ldapdelete -D cn=Manager,dc=itpro,dc=com -W -x -v cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com

Enter LDAP Password: 
deleting entry cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com

[root@localhost openldap]#
<c#>
با دستور ldapmodify هم میتونید اطلاعات یک object  رو تغییر بدید. دستور ldapsearch رو هم میشه محدودش کرد که کجا رو جستجو کنه. از regex و wildcard و این جور چیزا میشه توش استفاده کرد. به عهده خودتون اینا. بحث ldap خیلی گستردس، اینجا فقط در حد اینکه یه ذهنیتی ایجاد بشه صحبت کردیم. اگر بخوایم ldap server رو با Active Directory و یا خود کاربران لینوکسی ترکیب کنیم و یا از سیستم های احراز هویت و این جور چیزا استفاده کنیم، وارد یکی از حوزه های بزرگ لینوکس به نام mix environment میشیم که موضوعش درمورد integrate کردن سیستم های لینوکسی و ماکروسافته.
خسته نباشید. این بخش تمام شد. تا بخش بعدی.
پایان قسمت چهارم ( آخر) از بخش سوم

نویسنده : سید محمد باقر موسوی
منبع : |جزیره لینوکس و سیستم های متن باز وب سایت توسینسو::https://linux.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی است

اطلاعات با استاندارد x500 بصورت زیر درختی و زیر شاخه ای ذخیره میشود. حال برای دسترسی به این اطلاعات باید از یه پروتکلی استفاده کنیم. این پروتکل در قدیم dap نام داشت که نسخه بهبود یافته آن شد ldap. پروتکل dap سنگین بود و منابع زیادی مصرف میکرد ولی ldap که از اسمش هم مشخصه Lightweight Directory Access Protocol همون dap سبک شده است. پروتکل ldap محصول IBM و Microsoft است. به سروری که اطلاعات رو با استاندارد x500 ذخیره میکنه میگیم ldap server . پس ldap یک پروتکل دسترسی است. خود ldap server به تنهایی پایگاه داده ندارد. در آن یک پایگاه داده میسازیم. اگر ldap server بخواهیم داشته باشیم، در ویندوز، Active Directory و در لینوکس هم OpenLDAP نصب میکنیم. تمام این ها از استاندارد x500 استفاده میکنند. ماکروسافت بانک اطلاعاتی خودشو داره توی AD ولی نام پایگاه داده لینوکس BDB است. استفاده از ldap server باید توجیه پذیر باشد. مثلا بانک ها از چنین سرویسی استفاده نمیکنند و به جای ldap server از oracle استفاده میکنند. البته ممکنه چیزای دیگه ای مثل آرشیوشون یا اطلاعات سازمانی رو روی ldap server نگه دارن ولی اطلاعات مالی و تراکنش مالی که هر روز انجام میشه رو نه ( چرا ؟؟؟ اینو دیگه خودم نمیگم، شما بگید !!! )

پس کلا اطلاعاتی رو روی ldap server میبریم که قراره یک بار نوشته بشه ولی هزاران بار توسط کاربران یا برنامه ها خونده بشه و استفاده بشه. کلا سرعت read بالا میخوایم نه write خیلی بالا.

بسیار خوب. فک میکنم واسه مقدمه کافیه چون بحث خیلی گستردس نمیشه جمعش کرد. بریم سراغ نصب ldap server روی 5.8 centos

فقط یادتون باشه object هایی که درست میکنیم لینوکسی نیستن، ینی اگه یه کاربر ساختیم نمیتونه تو سیستم log in کنه. اون بحثش یه چیز دیگس. اون میره توی بحثای مربوط به samba.

Open LDAP

در ترمینال خود دستور زیر را برای نصب package های لازم وارد کنید.

[root@localhost ~]# yum install openldap openldap-clients openldap-servers

بعد از اینکه نصب شد میتونم چک کنم

[root@localhost ~]# rpm -qa | grep openldap
openldap-clients-2.3.43-29.el5_11
openldap-2.3.43-29.el5_11
openldap-servers-2.3.43-29.el5_11
[root@localhost ~]# 

دیدید که 3 تا package نیاز دارم. استاندارد x500 با نصب openldap server نصب شد. openldap client که ابزارهای وصل شذن به این پایگاه داده و مدیریتشه. openldap هم که لازمه جفتشه.

حالا این openldap server یک فایل کانفیگ داره. بر خلاف انتظار، این فایلی که پایین نوشتم نیست !!! این کامفیگ فایل کاربره نه سرورو تنظیمات کاربر توی این وارد میشه

/etc/openldap/ldap.conf

تنظیمات مربوط به سرور توی slapd.conf قرار داره.

[root@localhost ~]# cd /etc/openldap/
[root@localhost openldap]# ls
cacerts  DB_CONFIG.example  ldap.conf  schema  slapd.conf
[root@localhost openldap]# 

فایل slapd.conf رو با یه ادیتور باز کنید. توی خط 86 و 87 و 93 اطلاعات رو مطابق شکل زیر تغییر بدبد. این شکلی بشه.

سلام و وقت بخیر. در این جلسه به یکی از مباحث مهم در شبکه یعنی ldap میپردازیم. اول از همه باید بفهمیم که چرا به ldap نیاز داریم و اصلا ldap چیست؟؟ ابتدا مقداری مقدمه میگم و بعدش میریم سراغ یک سناریوی عملی، نمیدونم حالا میشه تو یه قسمت جمعش کرد یا نه چیزی رو که میخوام بگم.

*مفهوم Directory Service به چه معناست ؟؟ *
طبق تعریف directory service یک بانک اطلاعاتی است که قدرت آن در جستجو و خواندن اطلاعات با سرعت بالاست. نه اینکه در نوشتن ضعیف باشه، ولی در بعضی شرایط ما نیاز داریم که اطلاعاتی را با سرعت بالا از بانک اطلاعاتی بخوانیم. در چنین بانک های اطلاعاتی یک رکورد یا یک entry یک بار نوشته میشود ولی قرار است هزاران هزار بار خوانده شود، پس باید سرعت خواندن اطلاعات بالا یاشد. ساده ترین directory service یک دفترچه تلفن است. وقتی مثلا نام ali را ذخیره میکنیم، میرویم در قسمت حرف a نام او را ذخیره میکنیم. بعدا هم وقتی دنبال او بگردیم، میرویم فقط قسمت a را جستجو میکنیم، نه کل دفترچه. در اینجا ali یک object یا entry است. این object میتواند  attribute هم داشته باشد مثل ایمیل و آدرس و ... . پس Directory Service یک سیستم درختی است. در حقیقت Directory Service یک سیستم جستجو گر است که میتوان نتیجه یک جستجو را trace کرد که از کجا آمده. یه شکل زیر دقت کنید.
<center>
||http://tosinso.com/files/get/7e569dbb-0c88-448f-bb46-13f753994975||
<center>
فرض کنید یک پایگاه داده داریم که شامل تمام کمپانی های دنیا است. دنیال یک شخص خاص در این پایگاه داده میگردیم. بصورت درختی به جستجو میپردازیم. اول میپرسی که در کدام کشور است ؟ مثلا آمریکا، خوب بقیه کشور ها رو میزاریم کنار. در کدام ایالت است؟ کالیفورنیا، نام کمپانی او چیست؟ مثلا acme ، در کدام بخش کار میکند ؟ فروش، نامش چیست ؟ barbara jenson . این یک جستجوی درختی بود. در چنین سیستمی فقط قسمتی از پایگاه داده که لازم است رو جستجو میکنیم نه همشو. در ضمن سرعت جستجو هم باید بالا باشد. این یک سیستم میتنی بر Directory Service است. حال برای اینکه بتوان اطلاعات را در Directory Service ذخیره کرد و به این صورت که گفتیم قابل جستجو باشند، نیاز به یک استاندارد خاص دخیره سازی اطلاعات است. این استاندارد x500 نام دارد. به شکل نگاه کنید ( نخندید!!! با paint کشیدم !!! )
<center>
||http://tosinso.com/files/get/4d2b5ff1-0f43-4114-a6d3-8480166382c0||
<center>
اطلاعات با استاندارد x500 بصورت زیر درختی و زیر شاخه ای ذخیره میشود. حال برای دسترسی به این اطلاعات باید از یه پروتکلی استفاده کنیم. این پروتکل در قدیم dap نام داشت که نسخه بهبود یافته آن شد ldap. پروتکل dap سنگین بود و منابع زیادی مصرف میکرد ولی ldap که از اسمش هم مشخصه Lightweight Directory Access Protocol همون dap سبک شده است. پروتکل ldap محصول IBM و Microsoft است. به سروری که اطلاعات رو با استاندارد x500 ذخیره میکنه میگیم ldap server . پس ldap یک پروتکل دسترسی است. خود ldap server به تنهایی پایگاه داده ندارد. در آن یک پایگاه داده میسازیم. اگر ldap server بخواهیم داشته باشیم، در ویندوز، Active Directory و در لینوکس هم OpenLDAP نصب میکنیم. تمام این ها از استاندارد x500 استفاده میکنند. ماکروسافت بانک اطلاعاتی خودشو داره توی AD ولی نام پایگاه داده لینوکس BDB است. استفاده از ldap server  باید توجیه پذیر باشد. مثلا بانک ها از چنین سرویسی استفاده نمیکنند و به جای ldap server از oracle استفاده میکنند. البته ممکنه چیزای دیگه ای مثل آرشیوشون یا اطلاعات سازمانی رو روی ldap server نگه دارن ولی اطلاعات مالی و تراکنش مالی که هر روز انجام میشه رو نه ( چرا ؟؟؟ اینو دیگه خودم نمیگم، شما بگید !!! )
پس کلا اطلاعاتی رو روی ldap server میبریم که قراره یک بار نوشته بشه ولی هزاران بار توسط کاربران یا برنامه ها خونده بشه و استفاده بشه. کلا سرعت read بالا میخوایم نه write خیلی بالا.
بسیار خوب. فک میکنم واسه مقدمه کافیه چون بحث خیلی گستردس نمیشه جمعش کرد. بریم سراغ نصب ldap server روی  5.8 centos
فقط یادتون باشه object هایی که درست میکنیم لینوکسی نیستن، ینی اگه یه کاربر ساختیم نمیتونه تو سیستم log in کنه. اون بحثش یه چیز دیگس. اون میره توی بحثای مربوط به samba.

*Open LDAP* 
در ترمینال خود دستور زیر را برای نصب package های لازم وارد کنید.
<c#>
[root@localhost ~]# yum install openldap openldap-clients openldap-servers
<c#>
بعد از اینکه نصب شد میتونم چک کنم
<c#>
[root@localhost ~]# rpm -qa | grep openldap
openldap-clients-2.3.43-29.el5_11
openldap-2.3.43-29.el5_11
openldap-servers-2.3.43-29.el5_11
[root@localhost ~]# 
<c#>
دیدید که 3 تا package نیاز دارم. استاندارد x500 با نصب openldap server نصب شد. openldap client که ابزارهای وصل شذن به این پایگاه داده و مدیریتشه. openldap هم که لازمه جفتشه. 
حالا این openldap server یک فایل کانفیگ داره. بر خلاف انتظار، این فایلی که پایین نوشتم نیست !!! این کامفیگ فایل کاربره نه سرورو تنظیمات کاربر توی این وارد میشه
<c#>
/etc/openldap/ldap.conf
<c#>
تنظیمات مربوط به سرور توی slapd.conf قرار داره.
<c#>
[root@localhost ~]# cd /etc/openldap/
[root@localhost openldap]# ls
cacerts  DB_CONFIG.example  ldap.conf  schema  slapd.conf
[root@localhost openldap]# 
<c#>
فایل slapd.conf رو با یه ادیتور باز کنید. توی خط 86 و 87 و 93 اطلاعات رو مطابق شکل زیر تغییر بدبد. این شکلی بشه.
<center>
||http://tosinso.com/files/get/087798d5-f93c-4a38-81dd-f51fc518bb03||
<center>
حالا اینا چی هست ؟؟ اون فایل هایی که بالای سند include شدن schema هستن برای ldap server ... این schema ها ساختاری برای ایجاد همون پایگاه داده با استامدارد x500 هستن. اینا schema های پایه هستن. مثلا اگه میخوام samba رو هم با ldap ی که دارم integrate کنم ، بعد از اینکه samba رو نصب کردم، برم فایل های schema ی samba رو پیدا کنم، برم توی پوشه schema های ldap کپیش کنم و بعدش بیام توی این فایل include کنمش. هر برنامه ای که بخواد با ldap سرور integrate بشه باید object های برنامه واسه ldap تعریف شده باشه، object ها هم توی schema تعریف میشه. توی عکسی که از فایل slapd گذاشتم میبینید که نوشته پایگاه داده BDB باشه، suffix میگه این قراره کانفیگ فایل چه دامینی باشه؟ حالا مثلا سازمانمون tosinso.com باشه. این فرمت رو باید رعایت کنید. dc یعنی domain component . خط بعد میگه حالا کاربر ارشد این ldap server کیه ؟ کاربر ارشد اینجا manager نام داره. باز اون فرمت رو رعایت کنید. مدیر توی کدوم دامین قرار داره؟ cn یعنی common name . بعدشم دامین مدیر ارشد رو مشخص کردیم. خط بعدش رمز کاربر ارشد رو میخواد. میتونیم رمز رو بصورت clear text اینجا بنویسیم، میتونیم هش شده رمز رو خط بعد بنویسیم. فایل رو ذخیره کنید و سرویس رو روشن کنید. بعدش پورت هایی که listen میشن رو چک کنید. ldap روی پورت 389  در حالت پیش فرض کار میکنه.
<c#>
[root@localhost openldap]# /etc/init.d/ldap start
Starting slapd:                                            [  OK  ]
[root@localhost openldap]# netstat -antp | grep 389
tcp        0      0 0.0.0.0:389                 0.0.0.0:*                   LISTEN      8252/slapd          
tcp        0      0 :::389                      :::*                        LISTEN      8252/slapd          
[root@localhost openldap]# 
<c#>
سرویس ldap راه افتاد ولی هنوز بانک اطلاعاتیمون خالیه. باید توش اطلاعات وارد کنیم. با دستور ldapadd ما میتونیم object اضافه کنیم. این object میتونه سازمان باشه، میتونه بخش سازمانی باشه، میتونه کارمند باشه. دستور زیر رو وارد کنید تا همه پایگاه داده رو نشون بده.
<c#>
[root@localhost openldap]# ldapsearch -x -b dc=itpro,dc=com (objectclass=*)
# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# search result
search: 2
result: 32 No such object

# numResponses: 1
[root@localhost openldap]# 
<c#>
نوشتن objectclass برابر * یعنی همه رو نشون بده. محدوده جستجو رو گذاشتم از کل دامین ، با سویچ b- و دادن نام دامین. x-هم یعنی از سیستم simple authentication استفاده کن. حالا این چیزی برنگردوند چون پایگاه داده خالیه. حالا ما میخوایم ریشه سازمان رو تعریف کنیم، دپارتمان ها رو اضافه کنیم، بعدش کارمند ها رو اضافه کنیم. اطلاعاتی که میخوام وارد کنم رو توی یک فایل میریزم که باید با فرمت ldif نوشته شده باشن. ldap data interchange format .  دستور ldapadd خیلی سویچ داره. یه کوچولوشو میگیم اینجا. W- یعنی تقاضای رمز کن. با f- هم فایل ldif رو نشونش میدم. x- هم یعنی simple authentication بکن. D- یعنی با چه یوزری از کدوم دامین میخوای وارد بشی. یک فایل به اسم build-root-ou.ldif درست کنید. اطلاعات زیر رو واردش کنید.
<c#>
dn: dc=itpro,dc=com
objectclass: dcObject
objectclass: organization
o: itpro
dc: itpro
<c#>
یه dn درست کردم به همراه صفاتش . dn ریشه سازمان رو تو دل خودش داره. dn یعنی distinguished name . ریشه سازمان رو ساختم. هر object که اضافه میکینم باید dn یکتا داشته باشه. خط پایین dc:itpro یک صفته. خط آخر هم o یک صفنه یعنی organization. برای هر object حداقل یک objectclass باشد تعریف بشه. معمولا برای تعریف سازمان، 2 تا objectclass که نوشتم رو استفاده میکنن. اینا صفات رو تعریف میکنن. یعنی من اگه خواستم صفات تعریف کنم واسه سازمانم، از صفات تعریف شد توی objectclass میتونم استفاده کنم نه هر صفنی.
حالا این فایل رو باید به پایگاه داده اضافه کنم.
<c#>
[root@localhost openldap]# ldapadd -D cn=Manager,dc=itpro,dc=com  -W -x -f build_root_ou.ldif
<c#>
اگه همه چی رو درست وارد کرده باشید، entry به درستی در پتیگاه داده وارد میشه.
برای تست کردن اینکه فایل slap.d رو درست کانفیگ کردید یا نه دستور زیر رو بزنید
<c#>
[root@localhost openldap]# ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
# extended LDIF
#
# LDAPv3
# base <> with scope baseObject
# filter: (objectclass=*)
# requesting: namingContexts 
#

#
dn:
namingContexts: dc=itpro,dc=com

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
[root@localhost openldap]# 
<c#>
حالا اگه دوباره از پایگاه داده query بگیریم
<c#>
[root@localhost openldap]# ldapsearch -x -b dc=itpro,dc=com (objectclass=*)
# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# itpro.com
dn: dc=itpro,dc=com
objectClass: dcObject
objectClass: organization
o: itpro
dc: itpro

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
[root@localhost openldap]# 
<c#>
حالا میخوام مدیر سازمان رو اضافه کنم. یک فایل به اسم add-manager.ldif درست میکنم
<c#>
dn: cn=Manager,dc=itpro,dc=com
objectclass: organizationalRole
cn: Manager
<c#>
اینطوری هم اضافش میکنم به پایگاه داده
<c#>
[root@localhost openldap]# ldapadd -D cn=Manager,dc=itpro,dc=com -h localhost -W -x -f build_manager.ldif
Enter LDAP Password: 
adding new entry cn=Manager,dc=itpro,dc=com

[root@localhost openldap]#
<c#>
حالا اگه دوباره از پایگاه داده query بگیرم، مدیر اضافه شده
<c#>
[root@localhost openldap]# ldapsearch -x -b dc=itpro,dc=com (objectclass=*)# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# itpro.com
dn: dc=itpro,dc=com
objectClass: dcObject
objectClass: organization
o: itpro
dc: itpro

# Manager, itpro.com
dn: cn=Manager,dc=itpro,dc=com
objectClass: organizationalRole
cn: Manager

# search result
search: 2
result: 0 Success

# numResponses: 3
# numEntries: 2
[root@localhost openldap]# 
<c#>
حالا که سازمان درست شد، میخوام بخش های مختلف سازمان رو اضافه کنم. مثلا سازمان 3 تا دپارتمان داره.
<c#>
dn: ou=linux,dc=itpro,dc=com
ou: linux
objectclass: organizationalunit

dn: ou=software,dc=itpro,dc=com
ou: software
objectclass: organizationalunit

dn: ou=hardware,dc=itpro,dc=com
ou: hardware
objectclass: organizationalunit
<c#>
اگه space نذارید بین خط ها کار نمیکنه، آخر خط ها هم space بزنید بازم کار نمیکنه !!! کلا ldap خیلی گیره سر این چیزا. میبینید سر یه space توی کانفیگ فایل، کلا سرور آپ نمیشه !!!
حالا دپارتمان ها رو اضافه میکنم
<c#>
[root@localhost openldap]# ldapadd -D cn=Manager,dc=itpro,dc=com -h localhost -W -x -f build_dep.ldif
Enter LDAP Password: 
adding new entry ou=linux,dc=itpro,dc=com

adding new entry ou=software,dc=itpro,dc=com

adding new entry ou=hardware,dc=itpro,dc=com

[root@localhost openldap]#
<c#>
پایگاه دادم اینجوری شد
<c#>
[root@localhost openldap]# ldapsearch -x -b dc=itpro,dc=com (objectclass=*)
# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# itpro.com
dn: dc=itpro,dc=com
objectClass: dcObject
objectClass: organization
o: itpro
dc: itpro

# Manager, itpro.com
dn: cn=Manager,dc=itpro,dc=com
objectClass: organizationalRole
cn: Manager

# linux, itpro.com
dn: ou=linux,dc=itpro,dc=com
ou: linux
objectClass: organizationalUnit

# software, itpro.com
dn: ou=software,dc=itpro,dc=com
ou: software
objectClass: organizationalUnit

# hardware, itpro.com
dn: ou=hardware,dc=itpro,dc=com
ou: hardware
objectClass: organizationalUnit

# search result
search: 2
result: 0 Success

# numResponses: 6
# numEntries: 5
[root@localhost openldap]# 
<c#>
حالا میخوام یک کارمند اضافه کنم. یک فایل جدید با ldif درست میکنم.
<c#>
dn: cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com
cn: Mohammad Nasiri
sn: UNITY
mail: unity@itpro.com
departmentNumber: software
telephoneNumber: 203-543-8958
objectclass: inetOrgPerson
<c#>
حالا اضافه میکنیم به پایگاه داده:
<c#>
[root@localhost openldap]# ldapadd -D cn=Manager,dc=itpro,dc=com -h localhost -W -x -f build_worker.ldif
Enter LDAP Password: 
adding new entry cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com

[root@localhost openldap]# 
<c#>
محمد نصیری اضافه شد !!!  :))) این یه تیکه از خروجی دستور ldapsearch هستش. دقت کنید که هر object یک cn منحصر به فرد داره.
<c#>
# Mohammad Nasiri, software, itpro.com
dn: cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com
cn: Mohammad Nasiri
sn: UNITY
mail: unity@itpro.com
departmentNumber: software
telephoneNumber: 203-543-8958
objectClass: inetOrgPerson
<c#>
دقت کنید که برای یک شخص در سازمان و یک بخش از سازمان از objectclass های متفاوتی استفاده کردم. پس هر برنامه ای نصب کردید یا خواستیذ کلا چیزی به پایگاه داده اضافه کنید باید بدونید objectclass اون چیه.
حالا قراره یک نفر رو از سازمان خارج کنیم!!!
<c#>
[root@localhost openldap]# ldapdelete -D cn=Manager,dc=itpro,dc=com -W -x -v cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com

Enter LDAP Password: 
deleting entry cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com

[root@localhost openldap]#
<c#>
با دستور ldapmodify هم میتونید اطلاعات یک object  رو تغییر بدید. دستور ldapsearch رو هم میشه محدودش کرد که کجا رو جستجو کنه. از regex و wildcard و این جور چیزا میشه توش استفاده کرد. به عهده خودتون اینا. بحث ldap خیلی گستردس، اینجا فقط در حد اینکه یه ذهنیتی ایجاد بشه صحبت کردیم. اگر بخوایم ldap server رو با Active Directory و یا خود کاربران لینوکسی ترکیب کنیم و یا از سیستم های احراز هویت و این جور چیزا استفاده کنیم، وارد یکی از حوزه های بزرگ لینوکس به نام mix environment میشیم که موضوعش درمورد integrate کردن سیستم های لینوکسی و ماکروسافته.
خسته نباشید. این بخش تمام شد. تا بخش بعدی.
پایان قسمت چهارم ( آخر) از بخش سوم

نویسنده : سید محمد باقر موسوی
منبع : |جزیره لینوکس و سیستم های متن باز وب سایت توسینسو::https://linux.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی است

حالا اینا چی هست ؟؟ اون فایل هایی که بالای سند include شدن schema هستن برای ldap server ... این schema ها ساختاری برای ایجاد همون پایگاه داده با استامدارد x500 هستن. اینا schema های پایه هستن. مثلا اگه میخوام samba رو هم با ldap ی که دارم integrate کنم ، بعد از اینکه samba رو نصب کردم، برم فایل های schema ی samba رو پیدا کنم، برم توی پوشه schema های ldap کپیش کنم و بعدش بیام توی این فایل include کنمش. هر برنامه ای که بخواد با ldap سرور integrate بشه باید object های برنامه واسه ldap تعریف شده باشه، object ها هم توی schema تعریف میشه. توی عکسی که از فایل slapd گذاشتم میبینید که نوشته پایگاه داده BDB باشه، suffix میگه این قراره کانفیگ فایل چه دامینی باشه؟ حالا مثلا سازمانمون tosinso.com باشه. این فرمت رو باید رعایت کنید. dc یعنی domain component . خط بعد میگه حالا کاربر ارشد این ldap server کیه ؟ کاربر ارشد اینجا manager نام داره. باز اون فرمت رو رعایت کنید. مدیر توی کدوم دامین قرار داره؟ cn یعنی common name . بعدشم دامین مدیر ارشد رو مشخص کردیم. خط بعدش رمز کاربر ارشد رو میخواد. میتونیم رمز رو بصورت clear text اینجا بنویسیم، میتونیم هش شده رمز رو خط بعد بنویسیم. فایل رو ذخیره کنید و سرویس رو روشن کنید. بعدش پورت هایی که listen میشن رو چک کنید. ldap روی پورت 389 در حالت پیش فرض کار میکنه.

[root@localhost openldap]# /etc/init.d/ldap start
Starting slapd:                                            [  OK  ]
[root@localhost openldap]# netstat -antp | grep 389
tcp        0      0 0.0.0.0:389                 0.0.0.0:*                   LISTEN      8252/slapd          
tcp        0      0 :::389                      :::*                        LISTEN      8252/slapd          
[root@localhost openldap]# 

سرویس ldap راه افتاد ولی هنوز بانک اطلاعاتیمون خالیه. باید توش اطلاعات وارد کنیم. با دستور ldapadd ما میتونیم object اضافه کنیم. این object میتونه سازمان باشه، میتونه بخش سازمانی باشه، میتونه کارمند باشه. دستور زیر رو وارد کنید تا همه پایگاه داده رو نشون بده.

[root@localhost openldap]# ldapsearch -x -b "dc=itpro,dc=com" "(objectclass=*)"
# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# search result
search: 2
result: 32 No such object

# numResponses: 1
[root@localhost openldap]# 

نوشتن objectclass برابر * یعنی همه رو نشون بده. محدوده جستجو رو گذاشتم از کل دامین ، با سویچ b- و دادن نام دامین. x-هم یعنی از سیستم simple authentication استفاده کن. حالا این چیزی برنگردوند چون پایگاه داده خالیه. حالا ما میخوایم ریشه سازمان رو تعریف کنیم، دپارتمان ها رو اضافه کنیم، بعدش کارمند ها رو اضافه کنیم. اطلاعاتی که میخوام وارد کنم رو توی یک فایل میریزم که باید با فرمت ldif نوشته شده باشن. ldap data interchange format . دستور ldapadd خیلی سویچ داره. یه کوچولوشو میگیم اینجا. W- یعنی تقاضای رمز کن. با f- هم فایل ldif رو نشونش میدم. x- هم یعنی simple authentication بکن. D- یعنی با چه یوزری از کدوم دامین میخوای وارد بشی. یک فایل به اسم build-root-ou.ldif درست کنید. اطلاعات زیر رو واردش کنید.

dn: dc=itpro,dc=com
objectclass: dcObject
objectclass: organization
o: itpro
dc: itpro

یه dn درست کردم به همراه صفاتش . dn ریشه سازمان رو تو دل خودش داره. dn یعنی distinguished name . ریشه سازمان رو ساختم. هر object که اضافه میکینم باید dn یکتا داشته باشه. خط پایین dc:itpro یک صفته. خط آخر هم o یک صفنه یعنی organization. برای هر object حداقل یک objectclass باشد تعریف بشه. معمولا برای تعریف سازمان، 2 تا objectclass که نوشتم رو استفاده میکنن. اینا صفات رو تعریف میکنن. یعنی من اگه خواستم صفات تعریف کنم واسه سازمانم، از صفات تعریف شد توی objectclass میتونم استفاده کنم نه هر صفنی.

حالا این فایل رو باید به پایگاه داده اضافه کنم.

[root@localhost openldap]# ldapadd -D "cn=Manager,dc=itpro,dc=com"  -W -x -f build_root_ou.ldif

اگه همه چی رو درست وارد کرده باشید، entry به درستی در پتیگاه داده وارد میشه.

برای تست کردن اینکه فایل slap.d رو درست کانفیگ کردید یا نه دستور زیر رو بزنید

[root@localhost openldap]# ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
# extended LDIF
#
# LDAPv3
# base <> with scope baseObject
# filter: (objectclass=*)
# requesting: namingContexts 
#

#
dn:
namingContexts: dc=itpro,dc=com

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
[root@localhost openldap]# 

حالا اگه دوباره از پایگاه داده query بگیریم

[root@localhost openldap]# ldapsearch -x -b "dc=itpro,dc=com" "(objectclass=*)"
# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# itpro.com
dn: dc=itpro,dc=com
objectClass: dcObject
objectClass: organization
o: itpro
dc: itpro

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
[root@localhost openldap]# 

حالا میخوام مدیر سازمان رو اضافه کنم. یک فایل به اسم add-manager.ldif درست میکنم

dn: cn=Manager,dc=itpro,dc=com
objectclass: organizationalRole
cn: Manager

اینطوری هم اضافش میکنم به پایگاه داده

[root@localhost openldap]# ldapadd -D "cn=Manager,dc=itpro,dc=com" -h localhost -W -x -f build_manager.ldif
Enter LDAP Password: 
adding new entry "cn=Manager,dc=itpro,dc=com"

[root@localhost openldap]#

حالا اگه دوباره از پایگاه داده query بگیرم، مدیر اضافه شده

[root@localhost openldap]# ldapsearch -x -b "dc=itpro,dc=com" "(objectclass=*)"# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# itpro.com
dn: dc=itpro,dc=com
objectClass: dcObject
objectClass: organization
o: itpro
dc: itpro

# Manager, itpro.com
dn: cn=Manager,dc=itpro,dc=com
objectClass: organizationalRole
cn: Manager

# search result
search: 2
result: 0 Success

# numResponses: 3
# numEntries: 2
[root@localhost openldap]# 

حالا که سازمان درست شد، میخوام بخش های مختلف سازمان رو اضافه کنم. مثلا سازمان 3 تا دپارتمان داره.

dn: ou=linux,dc=itpro,dc=com
ou: linux
objectclass: organizationalunit

dn: ou=software,dc=itpro,dc=com
ou: software
objectclass: organizationalunit

dn: ou=hardware,dc=itpro,dc=com
ou: hardware
objectclass: organizationalunit

اگه space نذارید بین خط ها کار نمیکنه، آخر خط ها هم space بزنید بازم کار نمیکنه !!! کلا ldap خیلی گیره سر این چیزا. میبینید سر یه space توی کانفیگ فایل، کلا سرور آپ نمیشه !!!

حالا دپارتمان ها رو اضافه میکنم

[root@localhost openldap]# ldapadd -D "cn=Manager,dc=itpro,dc=com" -h localhost -W -x -f build_dep.ldif
Enter LDAP Password: 
adding new entry "ou=linux,dc=itpro,dc=com"

adding new entry "ou=software,dc=itpro,dc=com"

adding new entry "ou=hardware,dc=itpro,dc=com"

[root@localhost openldap]#

پایگاه دادم اینجوری شد

[root@localhost openldap]# ldapsearch -x -b "dc=itpro,dc=com" "(objectclass=*)"
# extended LDIF
#
# LDAPv3
# base <dc=itpro,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# itpro.com
dn: dc=itpro,dc=com
objectClass: dcObject
objectClass: organization
o: itpro
dc: itpro

# Manager, itpro.com
dn: cn=Manager,dc=itpro,dc=com
objectClass: organizationalRole
cn: Manager

# linux, itpro.com
dn: ou=linux,dc=itpro,dc=com
ou: linux
objectClass: organizationalUnit

# software, itpro.com
dn: ou=software,dc=itpro,dc=com
ou: software
objectClass: organizationalUnit

# hardware, itpro.com
dn: ou=hardware,dc=itpro,dc=com
ou: hardware
objectClass: organizationalUnit

# search result
search: 2
result: 0 Success

# numResponses: 6
# numEntries: 5
[root@localhost openldap]# 

حالا میخوام یک کارمند اضافه کنم. یک فایل جدید با ldif درست میکنم.

dn: cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com
cn: Mohammad Nasiri
sn: UNITY
mail: unity@itpro.com
departmentNumber: software
telephoneNumber: 203-543-8958
objectclass: inetOrgPerson

حالا اضافه میکنیم به پایگاه داده:

[root@localhost openldap]# ldapadd -D "cn=Manager,dc=itpro,dc=com" -h localhost -W -x -f build_worker.ldif
Enter LDAP Password: 
adding new entry "cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com"

[root@localhost openldap]# 

محمد نصیری اضافه شد !!! :))) این یه تیکه از خروجی دستور ldapsearch هستش. دقت کنید که هر object یک cn منحصر به فرد داره.

# Mohammad Nasiri, software, itpro.com
dn: cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com
cn: Mohammad Nasiri
sn: UNITY
mail: unity@itpro.com
departmentNumber: software
telephoneNumber: 203-543-8958
objectClass: inetOrgPerson

دقت کنید که برای یک شخص در سازمان و یک بخش از سازمان از objectclass های متفاوتی استفاده کردم. پس هر برنامه ای نصب کردید یا خواستیذ کلا چیزی به پایگاه داده اضافه کنید باید بدونید objectclass اون چیه.

حالا قراره یک نفر رو از سازمان خارج کنیم!!!

[root@localhost openldap]# ldapdelete -D "cn=Manager,dc=itpro,dc=com" -W -x -v "cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com"

Enter LDAP Password: 
deleting entry "cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com"

[root@localhost openldap]#

با دستور ldapmodify هم میتونید اطلاعات یک object رو تغییر بدید. دستور ldapsearch رو هم میشه محدودش کرد که کجا رو جستجو کنه. از regex و wildcard و این جور چیزا میشه توش استفاده کرد. به عهده خودتون اینا. بحث ldap خیلی گستردس، اینجا فقط در حد اینکه یه ذهنیتی ایجاد بشه صحبت کردیم. اگر بخوایم ldap server رو با Active Directory و یا خود کاربران لینوکسی ترکیب کنیم و یا از سیستم های احراز هویت و این جور چیزا استفاده کنیم، وارد یکی از حوزه های بزرگ لینوکس به نام mix environment میشیم که موضوعش درمورد integrate کردن سیستم های لینوکسی و ماکروسافته.

Cron AnaCron و Batch

بعضی اوقات میخواهیم که یک کار در زمان مشخص انجام شود و یا برنامه ای سر زمان بندی خاص اجرا شود. به این کار automate کردن یک برنامه یا کار گقته میشود. ابزار های مختلفی برای این کار که هر ابزار ویژگی خاص خود را دارد، وجود دارد.

1- استفاده از cron

2- استفاده از at

3- استفاده از Anacron

4- استفاده از batch

System Cron Jobs

هم کاربران عادی سیستم میتوانند برنامه ای تنظیم کنند تا دستورات و کارهایشان طبق یک زمان بندی انجام شود، و هم مدیر سیستم میتواند کارهای سیستم را زمان بندی کند. مدیر سیستم با استفاده از فایل etccrontab و مسیر etccron.d که فایل های درون آن طبق فرمت crontab اجرا میشوند، کارهای سیستم را زمان بندی میکند. 4 پوشه مهم دیگر هم در etc وجود دارد به نام های cron.daily و cron.weekly و cron.monthly و cron.hourly که اسکریپت های داخل آنها در زمان های مشخص شده اجرا میشوند.

فایل crontab را باز کنید و به محتویات درون آن دقت کنید.

[root@centos6 ~]# cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed

[root@centos6 ~]# 

این فایل 7 ستون دارد که هر کدام معنی خاصی دارد. ستون اول دقیقه را مشخص میکند. مثلا اگر 5 باشد یعنی 5 دقیقه از سر ساعت گذشته. ستون دوم ساعت را مشخص میکند. مثلا 20 یعنی ساعت 8 شب. ستون سوم روز را مشخص میکند. مثلا 10 یعنی روز دهم از ماه. ستون چهارم هم ماه را مشخص میکند. مثلا 2 باشد یعنی فوریه. ستون پنجم هم هم روز هفته را مشخص میکند. روز های هفته از دوشنبه شروع میشوند. به معنی همه است. مثلا اگر ستون ماه بود یعنی هر ماه. ستون بعدی نام کاربری است که این برنامه را اجرا میکند. ستون آخر هم مسیر فایلی است که میخواهیم اجرا شود.

برای کاربران عادی فایل های cron در مسیر varspoolcroncrontabs قرار دارند. کاربر با دستور crontab -e میتواند یک job جدید درست کند. بعد از وارد کردن دستور صفحه ای مانند vim باز میشود. این صفحه خالی باید با فرمت فایل crontab پر شود ولی 6 ستون دارد نه 7 تا. دیگه نام کاربر لازم نیست. چون مشخص دیگه. هر کاربر این دستور رو بزنه مشخص برای کی داره نوشته میشه. مثلا اطلاعات زیر رو وارد میکنیم.

*/5 8-16 8 8 1 ls /tmp

ستون اول 2 تا کاراکتر رو ترکیب کردم یعنی هر 5 دقیقه. اگه 5 خالی میذاشتم فقط سر 5 دقیقه از ساعت گذشته اجرا میشد. این خاصیت رو با استفاده از * ایجاد کردم. ستون بعدی یعنی از ساعن 8 صبح تا 4 بعد از ظهر. ستون بعدی یه ستاره گذاشتم یعنی هر روز از ماه . ستون بعدش هم ستاره یعنی هر ماه. ستون بعدش هم 1 یعنی روز اول هفته یعنی دوشنیه. پس هر 5 دقیقیه ساعت 8 تا 16 روز دوشنبه توی کل سال این برنامه اجرا میشه. حالا آدرس برنامه ندادم. گفتم واسه مسیر tmp/ دستور ls رو اجرا کن.

با دستور crontab و سویچ l- لیست job ها رو میبینید و با سویچ r- میتونید پاکشون کنید.

[mohammad@centos6 ~]$ crontab -l
*/5 8-16 * * 1 ls /tmp
[mohammad@centos6 ~]$ crontab -r
[mohammad@centos6 ~]$ crontab -l
no crontab for mohammad
[mohammad@centos6 ~]$ 

میتونید دستوراتی که میخواین اجرا بشن رو توی یک فایل بنویسید و آدرسشو در ستون آخر وارد کنید، که معمولا همین کار رو میکنن.

برای مثال اگر بخوام از سیستم backup بگیرم میشه بصورت زیر انجامش داد.

[root@centos6 ~]# cd /etc/cron.d/
[root@centos6 cron.d]# vim daily-backup
[root@centos6 cron.d]# cat daily-backup
30 20 * * 1-5 root /root/backup.sh
[root@centos6 cron.d]# ls
0hourly  daily-backup  raid-check  sysstat
[root@centos6 cron.d]# 
[root@centos6 cron.d]# 

توی فایل backup.sh دستورات مربوط به پشتیبان گیری نوشته میشه. حالا این مثال فقط با دسترسی کاربر ارشد بود. با کاربر معمولی میتونید دستورات رو توی یه فایل مثلا در home directory خودتون ذخیره کنید و بعدش با دستور crontab و سویچ e- زمان بندی دلخواهتون رو تنظیم کنید و در ستون آخر آدرس اون فایل برنامتون رو بدید.

Anacron

دیدیم که با cron میتوان طبق یک زمان بندی دستورانی را اجرا کرد. اما اگر سیستم خاموش شود، دیگر سیستمی برای چک کردن کارهایی که باید انجام میشد ولی انجام نشده ، وجود ندارد و سیستم تا زمان مقرر بعدی صبر میکند تا دوباره طبق زمان بعدی کار ها را انجام دهد. در صورتی که با Anacron میتوان مشخص کرد که چند دقیقه بعد از روشن شدن سیستم بررسی کند چه تعداد از کار هایی که باید انجام میشد، انجام شده یا نشده.

فایل کانفیگ Anacron در مسیر زیر وجود دارد.

[root@centos6 ~]# cat /etc/anacrontab
# /etc/anacrontab: configuration file for anacron

# See anacron(8) and anacrontab(5) for details.

SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22

#period in days   delay in minutes   job-identifier   command
1	5	cron.daily		nice run-parts /etc/cron.daily
7	25	cron.weekly		nice run-parts /etc/cron.weekly
@monthly 45	cron.monthly		nice run-parts /etc/cron.monthly
[root@centos6 ~]# 

ستون اول period نام دارد. اگر عدد 1 باشد ینی هر روز، اگر عدد 7 باشد یعنی هقتگی و اگر 30 باشد یعنی ماهانه. میتوان از کلماتی مثل monthly@ هم استفاده کرد. سوت دوم delay نام دارد یعنی چند دقیقه بعد از روشن شدن سیستم صبر کند. ستون سوم job identifier است. این ستون اصطلاحا آدرس فایل timestamp را مشخص میکند که در مسیر varspool قرار دارد. برای هر job این فایل باید یکتا باشد. درون این فایل های timestamp رشته ای وجود دارد که نشان میدهد آخرین بار چه موقع job انجام شده. ستون چهارم هم مسیر فایل که باید اجرا شود را مشخص میکند.

[root@centos6 ~]# ls /var/spool/anacron/
cron.daily  cron.monthly  cron.weekly
[root@centos6 ~]# cat /var/spool/anacron/cron.daily 
20160826
[root@centos6 ~]# cat /var/spool/anacron/cron.monthly 
20160727
[root@centos6 ~]# cat /var/spool/anacron/cron.weekly 
20160825
[root@centos6 ~]#

برای مثال اگر خط زیر را در anacrontab وارد کنیم یعنی هر هفته برنامه ای که بهت دادم رو اجرا کن و اگر سیستم خاموش بود و اجرا نشد 15 دقیقه بعد از روشن شدن سیستم چک کن ببین اجرا شده یا نه اگر اجرا نشذه بود همین الان اجراش کن.

7       15      test.daily      /home/mohammad/backup.sh

خوب حالا اگه سیستم روشن باشه چی ؟؟ کی باید این برنامه اجرا بشه ؟؟

[root@centos6 ~]# grep START /etc/anacrontab
START_HOURS_RANGE=3-22
[root@centos6 ~]# 

اینکه کی برنامه اجرا بشه توسط متغیر بالا در فایل کانفیگ anacron مشخص میشه. معنی این خط میشه از 3 بامداد تا 10 شب. میتونید زمان دلخواه خودتون رو بهش بدبد. شکل زیر رو از یه سایت خارجی پیدا کردم. تفاوت cron و Anacron رو گفته. خیلی قشنگ نوشته. فک نمیکنم احتیاج به ترجمه و یا توضیح اضافه من باشه.

سلام و وقت بخیر. بعضی اوقات میخواهیم که یک کار در زمان مشخص انجام شود و یا برنامه ای سر زمان بندی خاص اجرا شود. به این کار automate کردن یک برنامه یا کار گقته میشود. ابزار های مختلفی برای این کار که هر ابزار ویژگی خاص خود را دارد، وجود دارد.
1- استفاده از cron
2- استفاده از at
3- استفاده از Anacron
4- استفاده از batch

*System Cron Jobs*
هم کاربران عادی سیستم میتوانند برنامه ای تنظیم کنند تا دستورات و کارهایشان طبق یک زمان بندی انجام شود، و هم مدیر سیستم میتواند کارهای سیستم را زمان بندی کند. مدیر سیستم با استفاده از فایل etc/crontab/ و  مسیر etc/cron.d/ که فایل های درون آن طبق فرمت crontab اجرا میشوند، کارهای سیستم را زمان بندی میکند. 4 پوشه مهم دیگر هم در etc وجود دارد به نام  های cron.daily و cron.weekly و cron.monthly و cron.hourly که اسکریپت های داخل آنها در زمان های مشخص شده اجرا میشوند. 
فایل crontab را باز کنید و به محتویات درون آن دقت کنید.
<c#>
[root@centos6 ~]# cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed

[root@centos6 ~]# 
<c#>
این فایل 7 ستون دارد که هر کدام معنی خاصی دارد. ستون اول دقیقه را مشخص میکند. مثلا اگر 5 باشد یعنی 5 دقیقه از سر ساعت گذشته. ستون دوم ساعت را مشخص میکند. مثلا 20 یعنی ساعت 8 شب. ستون سوم روز را مشخص میکند. مثلا 10 یعنی روز دهم از ماه. ستون چهارم هم ماه را مشخص میکند. مثلا 2 باشد یعنی فوریه. ستون پنجم هم هم روز هفته را مشخص میکند. روز های هفته از دوشنبه شروع میشوند. * به معنی همه است. مثلا اگر ستون ماه * بود یعنی هر ماه. ستون بعدی نام کاربری است که این برنامه را اجرا میکند.  ستون آخر هم مسیر فایلی است که میخواهیم اجرا شود.
برای کاربران عادی فایل های cron در مسیر var/spool/cron/crontabs/ قرار دارند. کاربر با دستور crontab -e میتواند یک job  جدید درست کند. بعد از وارد کردن دستور صفحه ای مانند vim باز میشود. این صفحه خالی باید با فرمت فایل crontab پر شود ولی 6 ستون دارد نه 7 تا. دیگه نام کاربر لازم نیست. چون مشخص دیگه. هر کاربر این دستور رو بزنه مشخص برای کی داره نوشته میشه. مثلا اطلاعات زیر رو وارد میکنیم.
<c#>
*/5 8-16 8 8 1 ls /tmp
<c#>
ستون اول 2 تا کاراکتر رو ترکیب کردم یعنی هر 5 دقیقه. اگه 5 خالی میذاشتم فقط سر 5 دقیقه از ساعت گذشته اجرا میشد. این خاصیت رو با استفاده از * ایجاد کردم. ستون بعدی یعنی از ساعن  8 صبح تا 4 بعد از ظهر. ستون بعدی یه ستاره گذاشتم یعنی هر روز از ماه . ستون بعدش هم ستاره یعنی هر ماه. ستون بعدش هم 1 یعنی روز اول هفته یعنی دوشنیه. پس هر 5 دقیقیه ساعت 8 تا 16 روز دوشنبه توی کل سال این برنامه اجرا میشه. حالا آدرس برنامه ندادم. گفتم واسه مسیر tmp/ دستور ls رو اجرا کن.
با دستور crontab و سویچ l- لیست job ها رو میبینید و با سویچ r- میتونید پاکشون کنید.
<c#>
[mohammad@centos6 ~]$ crontab -l
*/5 8-16 * * 1 ls /tmp
[mohammad@centos6 ~]$ crontab -r
[mohammad@centos6 ~]$ crontab -l
no crontab for mohammad
[mohammad@centos6 ~]$ 
<c#>
میتونید دستوراتی که میخواین اجرا بشن رو توی یک فایل بنویسید و آدرسشو در ستون آخر وارد کنید، که معمولا همین کار رو میکنن. 
برای مثال اگر بخوام از سیستم backup بگیرم میشه بصورت زیر انجامش داد.
<c#>
[root@centos6 ~]# cd /etc/cron.d/
[root@centos6 cron.d]# vim daily-backup
[root@centos6 cron.d]# cat daily-backup
30 20 * * 1-5 root /root/backup.sh
[root@centos6 cron.d]# ls
0hourly  daily-backup  raid-check  sysstat
[root@centos6 cron.d]# 
[root@centos6 cron.d]# 
<c#>
توی فایل backup.sh دستورات مربوط به پشتیبان گیری نوشته میشه. حالا این مثال فقط با دسترسی کاربر ارشد بود. با کاربر معمولی میتونید دستورات رو توی یه فایل مثلا در home directory خودتون ذخیره کنید و بعدش با دستور crontab و سویچ e- زمان بندی دلخواهتون رو تنظیم کنید و در ستون آخر آدرس اون فایل برنامتون رو بدید.

*Anacron*
دیدیم که با cron میتوان طبق یک زمان بندی دستورانی را اجرا کرد. اما اگر سیستم خاموش شود، دیگر سیستمی برای چک کردن کارهایی که باید انجام میشد ولی انجام نشده ، وجود ندارد و سیستم تا زمان مقرر بعدی صبر میکند تا دوباره طبق زمان بعدی کار ها را انجام دهد. در صورتی که با Anacron میتوان مشخص کرد که چند دقیقه بعد از روشن شدن سیستم بررسی کند چه تعداد از کار هایی که باید انجام میشد، انجام شده یا نشده.
فایل کانفیگ Anacron در مسیر زیر وجود دارد.
<c#>
[root@centos6 ~]# cat /etc/anacrontab
# /etc/anacrontab: configuration file for anacron

# See anacron(8) and anacrontab(5) for details.

SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22

#period in days   delay in minutes   job-identifier   command
1	5	cron.daily		nice run-parts /etc/cron.daily
7	25	cron.weekly		nice run-parts /etc/cron.weekly
@monthly 45	cron.monthly		nice run-parts /etc/cron.monthly
[root@centos6 ~]# 
<c#>
ستون اول period نام دارد. اگر عدد 1 باشد ینی هر روز، اگر عدد 7 باشد یعنی هقتگی و اگر 30 باشد یعنی ماهانه. میتوان از کلماتی مثل monthly@ هم استفاده کرد. سوت دوم delay نام دارد یعنی چند دقیقه بعد از روشن شدن سیستم صبر کند. ستون سوم job identifier است. این ستون اصطلاحا آدرس فایل timestamp را مشخص میکند که در مسیر var/spool/ قرار دارد. برای هر job این فایل باید یکتا باشد. درون این فایل های timestamp رشته ای وجود دارد که نشان میدهد آخرین بار چه موقع job انجام شده. ستون چهارم هم مسیر فایل که باید اجرا شود را مشخص میکند. 
<c#>
[root@centos6 ~]# ls /var/spool/anacron/
cron.daily  cron.monthly  cron.weekly
[root@centos6 ~]# cat /var/spool/anacron/cron.daily 
20160826
[root@centos6 ~]# cat /var/spool/anacron/cron.monthly 
20160727
[root@centos6 ~]# cat /var/spool/anacron/cron.weekly 
20160825
[root@centos6 ~]#
<c#>
برای مثال اگر خط زیر را در anacrontab وارد کنیم یعنی هر هفته برنامه ای که بهت دادم رو اجرا کن و اگر سیستم خاموش بود و اجرا نشد 15 دقیقه بعد از روشن شدن سیستم چک کن ببین اجرا شده یا نه اگر اجرا نشذه بود همین الان اجراش کن.
<c#>
7       15      test.daily      /home/mohammad/backup.sh
<c#>
خوب حالا اگه سیستم روشن باشه چی ؟؟ کی باید این برنامه اجرا بشه ؟؟
<c#>
[root@centos6 ~]# grep START /etc/anacrontab
START_HOURS_RANGE=3-22
[root@centos6 ~]# 
<c#>
اینکه کی برنامه اجرا بشه توسط متغیر بالا در فایل کانفیگ anacron مشخص میشه. معنی این خط میشه از 3 بامداد تا 10 شب. میتونید زمان دلخواه خودتون رو بهش بدبد. شکل زیر رو از یه سایت خارجی پیدا کردم. تفاوت cron و Anacron رو گفته. خیلی قشنگ نوشته. فک نمیکنم احتیاج به ترجمه و یا توضیح اضافه من باشه.
<center>
||http://tosinso.com/files/get/3a53190f-5844-4b94-a934-05a282dd364c||
<center>

*At و Batch*
این دو دستور خیلی جالبن. بصورت پیش فرض at نصب نیست. ( واسه من که نبود ) با دستور yum install at نصبش کنید. کار کردن با این 2 تا دستور خیلی راحته. فقط مینویسید at سپس زمان مورد نظر. بعدش شکل prompt عوض میشه و میتونید دستورات رو وارد کنید. آخرش هم با کنترل d خارج میشه. با دستور atq لیست job هایی که قراره اجرا بشه رو میشه دید. اون عدد اولش شماره شناسایی اون job هستش. اولش هیچی توی job نبود. بعدش یه خط دستور نوشتم. واسه دستور at حتی چیزی مثل at noon tomorrow هم قابل قبوله. با دستور atrm و شماره job میتونید پاکش کنید.
<c#>
[root@centos6 ~]# 
[root@centos6 ~]# atq
[root@centos6 ~]# at 11 am tomorrow
at> ls /etc/ > ~/file_at
at> <EOT>
job 1 at 2016-08-27 11:00
[root@centos6 ~]# atq
1	2016-08-27 11:00 a root
[root@centos6 ~]# at 3 pm 23 dec
at> rm -rf ~/sile.txt
at> <EOT>
job 2 at 2016-12-23 15:00
[root@centos6 ~]# atq
2	2016-12-23 15:00 a root
1	2016-08-27 11:00 a root
[root@centos6 ~]# atrm 1
[root@centos6 ~]# atrm 2
[root@centos6 ~]# atq
[root@centos6 ~]# 
[root@centos6 ~]# 
<c#>
دستور batch هم دقیقا مث at میمونه فقط با یک تفاوت. زمانی اجرا میشه که load average سیستم کمتر از 0.8 باشه. برای دستور batch دیگه زمان و تاریخ مشخص نمیکنیم. به محض اینکه load average سیستم کمتر از 0.8 بشه دستورات اجرا میشن.  
<c#>
[root@centos6 ~]# batch
at> ls /boot > ~/boot_file
at> <EOT>
job 3 at 2016-08-26 21:26
[root@centos6 ~]# atq
[root@centos6 ~]# 
[root@centos6 ~]# cat ~/boot_file
config-2.6.32-279.el6.i686
efi
elf-memtest86+-4.10
grub
initramfs-2.6.32-279.el6.i686.img
lost+found
memtest86+-4.10
symvers-2.6.32-279.el6.i686.gz
System.map-2.6.32-279.el6.i686
vmlinuz-2.6.32-279.el6.i686
[root@centos6 ~]# 
[root@centos6 ~]# 
[root@centos6 ~]# uptime
 21:27:49 up 1 day,  1:16,  3 users,  load average: 0.00, 0.00, 0.00
[root@centos6 ~]# 
[root@centos6 ~]# 
<c#>
با توضیحاتی که گفتیم دستورات بالا کاملا واضحن !! چون تقریبا ، تقریبا که نه ، دقیقا انگار هیچ لودی روی سیستم من نیست، دستوری که به batch دادم اجرا شد بلافاصله. دستورات batch هم مثل at با atq و atrm مدیریت میشن.

*ضمیمه*
در حالت عادی هر کسی میتونه برای خودش از دستورات at و cron استفاده کنه. برای اینکه این دستورات رو برای کاربران محدود کنیم میتونیم 2 دسته فایل به اسم های زیر درست کنیم.
<c#>
/etc/cron.allow or /etc/at.allow

/etc/cron.deny or /etc/at.deny
<c#>
اگر فایل های نوع اول رو درست کنیم، فقط کسانی که اسمشون توی لیسته میتونن از دستورات استفاده کنن و بقیه نمیتونن.
اگر فایل های نوع دوم رو درست کنیم، فقط کسانی که اسمشون توی لیسته نمیتونن از دستورات استفاده کنن و بقیه میتونن.

بسیار خوب. این بخش هم به پایان رسید. اولش میخواستم این 4 تا package رو تو 4 قسمت بگم ولی گغتم تو یه قسمت جمش کنم بهتره. امیدوارم خسته نشده باشید و مفید بوده باشه. اگر نظری، پیشنهادی یا انتقادی دارید کامنت بذارید یا پیام خصوصی بفرستید، خوشحال میشم. تا قسمت بعدی.

نویسنده : سید محمد باقر موسوی
منبع : |جزیره لینوکس و سیستم های متن باز وب سایت توسینسو::https://linux.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی است

At و Batch

این دو دستور خیلی جالبن. بصورت پیش فرض at نصب نیست. ( واسه من که نبود ) با دستور yum install at نصبش کنید. کار کردن با این 2 تا دستور خیلی راحته. فقط مینویسید at سپس زمان مورد نظر. بعدش شکل prompt عوض میشه و میتونید دستورات رو وارد کنید. آخرش هم با کنترل d خارج میشه. با دستور atq لیست job هایی که قراره اجرا بشه رو میشه دید. اون عدد اولش شماره شناسایی اون job هستش. اولش هیچی توی job نبود. بعدش یه خط دستور نوشتم. واسه دستور at حتی چیزی مثل at noon tomorrow هم قابل قبوله. با دستور atrm و شماره job میتونید پاکش کنید.

[root@centos6 ~]# 
[root@centos6 ~]# atq
[root@centos6 ~]# at 11 am tomorrow
at> ls /etc/ > ~/file_at
at> <EOT>
job 1 at 2016-08-27 11:00
[root@centos6 ~]# atq
1	2016-08-27 11:00 a root
[root@centos6 ~]# at 3 pm 23 dec
at> rm -rf ~/sile.txt
at> <EOT>
job 2 at 2016-12-23 15:00
[root@centos6 ~]# atq
2	2016-12-23 15:00 a root
1	2016-08-27 11:00 a root
[root@centos6 ~]# atrm 1
[root@centos6 ~]# atrm 2
[root@centos6 ~]# atq
[root@centos6 ~]# 
[root@centos6 ~]# 

دستور batch هم دقیقا مث at میمونه فقط با یک تفاوت. زمانی اجرا میشه که load average سیستم کمتر از 0.8 باشه. برای دستور batch دیگه زمان و تاریخ مشخص نمیکنیم. به محض اینکه load average سیستم کمتر از 0.8 بشه دستورات اجرا میشن.

[root@centos6 ~]# batch
at> ls /boot > ~/boot_file
at> <EOT>
job 3 at 2016-08-26 21:26
[root@centos6 ~]# atq
[root@centos6 ~]# 
[root@centos6 ~]# cat ~/boot_file
config-2.6.32-279.el6.i686
efi
elf-memtest86+-4.10
grub
initramfs-2.6.32-279.el6.i686.img
lost+found
memtest86+-4.10
symvers-2.6.32-279.el6.i686.gz
System.map-2.6.32-279.el6.i686
vmlinuz-2.6.32-279.el6.i686
[root@centos6 ~]# 
[root@centos6 ~]# 
[root@centos6 ~]# uptime
 21:27:49 up 1 day,  1:16,  3 users,  load average: 0.00, 0.00, 0.00
[root@centos6 ~]# 
[root@centos6 ~]# 

با توضیحاتی که گفتیم دستورات بالا کاملا واضحن !! چون تقریبا ، تقریبا که نه ، دقیقا انگار هیچ لودی روی سیستم من نیست، دستوری که به batch دادم اجرا شد بلافاصله. دستورات batch هم مثل at با atq و atrm مدیریت میشن.

ضمیمه

در حالت عادی هر کسی میتونه برای خودش از دستورات at و cron استفاده کنه. برای اینکه این دستورات رو برای کاربران محدود کنیم میتونیم 2 دسته فایل به اسم های زیر درست کنیم.

/etc/cron.allow or /etc/at.allow

/etc/cron.deny or /etc/at.deny

اگر فایل های نوع اول رو درست کنیم، فقط کسانی که اسمشون توی لیسته میتونن از دستورات استفاده کنن و بقیه نمیتونن.اگر فایل های نوع دوم رو درست کنیم، فقط کسانی که اسمشون توی لیسته نمیتونن از دستورات استفاده کنن و بقیه میتونن.

آشنایی با IPTables

در این جلسه میخوایم کانفیگ فایروال لینوکس یعنی iptable رو یاد بگیریم. در کل میتوان کارهایی که فایروال انجام میدهد را در 5 دست کلی تقسیم بندی کرد.

1- NAT

2- PAT

3- Filtering

4- QOS

5- Mangling

تو مورد فیلترینگ مثلا میگیم فلان آی پی به فلان پورت دسترسی نداشته باشه، یا توی nat آی پی ها به هم تبدیل میشن. pat هم شبیه nat هستش تا حدودی، فقط با پورت کار میکنه. توی فوروارد کردن پورت ها کاربرد داره، مثلا توی کشینگ. qos هم برای بررسی لود سیستم استفاده میشه، مثلا چند درصد پکت های وب سرورم دراپ شده یا چند درصد پکت های فلان آی پی دراپ شده. mangling هم فقط به درد حال گیری از خود شاخ پندارایی میخوره که هیچی از لینوکس و شبکه بلد نیستن، بعد میرن چهار تا تریک کالی یاد میگیرن و اسم خودشونو میذارن هکر. این mangling میاد اتک هایی که به سیستم زده میشه رو میگیره، به خود حمله کننده برمیگردونه و اگه سیستم حمله کننده در برابر اتک خودش مقاوم نباشه، میره رو هوا.

برای اینکه ببینید iptable در چه وضعیتی قرار داره دستور زیر را وارد کنید.

[root@centos6 ~]# service iptables status
Table: filter
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination         

[root@centos6 ~]# 

اگه iptables روشن نبود با دستور service iptables start روشنش کنید. اگر سیستمتون آموزشیه و چیزی به غیر از خروجی بالا میبینید، دستور iptables -F رو بزنید تا تمام rules های فایروال پاک بشه. میخوایم از صفر شروع کنیم فایروال رو کانفیگ کنیم. به خروجی دستورات زیر دقت کنید

[root@centos6 ~]# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

[root@centos6 ~]# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

[root@centos6 ~]# iptables -L -t mangle
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         

[root@centos6 ~]# iptables -L -t filter
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
[root@centos6 ~]# 

اگر دستور iptables رو با سویچ L- بزنم بصورت پیش فرض جدول filtering رو نشون میده. بعدش با سویچ t- جدول های دیگه رو چاپ کردم. اینا جداول پیش فرض iptable هستن که نمیتونید پاکشون کنید ولی میتونید در موارد خاص برای خودتون جدول هم بسازید ولی در بیشتر موارد با همین جدولا کارمون راه میفته. بیشتر در محیط های enterprise که لود خیلی زیاده توجیه داره جدول جدا نوشتن که سرعت پاسخ گویی سیستم پایین نیاد و یا بخوایم برای یک شرایط خاص تدابیر خاصی درنظر بگیریم.

هر کذوم از این جدول ها chain دارن. توی chain ها rule ها رو مینویسبم. chain ها یه جور طبق بندی محسوب میشه. الان جدول filter من 3 تا chain داره به نام های input و output و forwarding . توی این chain ها policy های دسترسی نوشته میشه. هر پکتی وارد سیستم میشه از این policy ها عبور میکنه. در کل 2 استراتژیک کلی برای کانفیگ فایروال داریم. اول اینکه همه چی بسته باشه، چیزایی که میخوام رو باز میکنم. دوم اینکه همه چی باز باشه و چیزایی که نمیخوام رو میبیندم. مورد اول معمولا استغاده میشه. کلا همه چی رو جلوشو میگریم، بعدش تک تک به سرویس هایی که راه اندازی میکنم، اجازه دسترسی میدم.

این 3 تا chain که گفتم از اسمش مشخصه که روی چی حساسن. حالا میام استراتژی مورد اول رو پیاده سازی میکنم. همه چی رو میبندم. خود جلوی جیزی رو گرفتن 2 حالت داره، reject کردن و drop کردن. فرقشون اینه که drop انجام بشه log نمیندازه ولی reject اتفاق بیفته log میندازه.الان policy پیش فرض accept هست، ینی همه چی بازه. حالا با دستور زیر policy رو drop میکنم.

[root@centos6 ~]# iptables -P INPUT DROP
[root@centos6 ~]# iptables -P OUTPUT DROP
[root@centos6 ~]# iptables -P FORWARD DROP
[root@centos6 ~]# iptables -L -t filter
Chain INPUT (policy DROP)
target     prot opt source               destination         

Chain FORWARD (policy DROP)
target     prot opt source               destination         

Chain OUTPUT (policy DROP)
target     prot opt source               destination         
[root@centos6 ~]# 

الان دیگه حتی پینگ هم نمیشه کرد. گفتم اگر خواستیم میتونیم chain درست کنیم علاوه بر chain های پیش فرض. حالا اگه 1000 خط rule نوشته باشم، بیخود همه هزار خط خونده میشه تا برسه مثلا به خطی که ssh رو اجازه عبور میده. در این مورد میام یه chain درست میکنم واسه ssh و به جای اینکه اون هزار خط چک بشه، میگم اگه مثلا پورت مقصدت 22 هستش jump کن توی chain مربوط به ssh. حالا میخوام همین کار رو بکنم. ابتدا یک chain درست میکنم و میگم هر چی مربوط به پورت 22 بود jump کنه توی این chain. توی chain میگم چه کار کنه باهاش، مثلا اجازه بده یا هرچی.

SSH

@centos6 ~]# iptables -N SSH_RULES
[root@centos6 ~]# iptables -A INPUT -p tcp --dport 22 -j SSH_RULES
[root@centos6 ~]# iptables -A OUTPUT -p tcp --sport 22 -j SSH_RULES
[root@centos6 ~]# iptables -A SSH_RULES -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
[root@centos6 ~]# iptables -A SSH_RULES -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
[root@centos6 ~]# iptables -L -t filter
Chain INPUT (policy DROP)
target     prot opt source               destination         
SSH_RULES  tcp  --  anywhere             anywhere            tcp dpt:ssh 

Chain FORWARD (policy DROP)
target     prot opt source               destination         

Chain OUTPUT (policy DROP)
target     prot opt source               destination         
SSH_RULES  tcp  --  anywhere             anywhere            tcp spt:ssh 

Chain SSH_RULES (2 references)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:ssh state NEW,ESTABLISHED 
ACCEPT     tcp  --  anywhere             anywhere            tcp spt:ssh state ESTABLISHED 
[root@centos6 ~]# 

خط اول یک chain درست کردم. اسمش هر چی میتونه باشه. خط دوم توی جدول input گفتم که هر چی اومد و پورت مقصدش 22 بود، به ssh-rules مراجعه کن. خط بعد هم همینکار واسه جدول output یعنی هر چی خواست خارج بشه که پورت مبداش 22 بود به ssh-rules مراجعه کن. سویچ A- یعنی append و j- یعنی jump و p- یعنی پروتکل. خط سوم و چهارم توی ssh-rules اضافه شده. یکی برای ورود و یکی برای خروج. میتونستم interface رو هم محدود کنم مثلا برای ورود مینوشتم i- eth1 یعنی فقط از eth1 و برای خروج هم مث همین فقط با سویچ o-. اینطوری دیگه از هیچ اینترفیس دیگه ای نمیشد ssh زد. اگر هم میخواستید که از یک شبکه خاص فقط بشه ssh زد، با سویچ s- و رنج آی پی، اون شبکه رو مجاز میکردیم.

حالا هر چی کد نوشتیم توی حافظه جاری سیستم قرار داره و اگه سیستم ریست بشه یا سرویس رو restart کنیم، همه چی پاک میشه. برای ذخیره دستور زیر را وارد کنید. به مسیر کانفیگ فایل پیش فرض دقت کنید.

[root@centos6 ~]# /etc/init.d/iptables save
iptables:    Saving firewall rules to  /etc/sysconfig/iptables:         [  OK  ]
[root@centos6 ~]# 

HTTP HTTPS

حالا میخوام دسترسی به وب سرور رو باز کنم. اینو متفاوت با قبلی مینویسیم. دیگه براش chain جدا ننوشتم.

[root@centos6 ~]# iptables -A INPUT -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
[root@centos6 ~]# iptables -A OUTPUT -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
[root@centos6 ~]# iptables -L -t filter
Chain INPUT (policy DROP)
target     prot opt source               destination         
SSH_RULES  tcp  --  anywhere             anywhere            tcp dpt:ssh 
ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:http state NEW,ESTABLISHED 

Chain FORWARD (policy DROP)
target     prot opt source               destination         

Chain OUTPUT (policy DROP)
target     prot opt source               destination         
SSH_RULES  tcp  --  anywhere             anywhere            tcp spt:ssh 
ACCEPT     tcp  --  anywhere             anywhere            tcp spt:http state ESTABLISHED 

Chain SSH_RULES (2 references)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:ssh state NEW,ESTABLISHED 
ACCEPT     tcp  --  anywhere             anywhere            tcp spt:ssh state ESTABLISHED 
[root@centos6 ~]# 

حالا یکم سویچ هاشو هم یاد بگیریم، با سویچ R- میشه یک خط رو جایگزین کرد. میتونید insert هم بکنید با سویچ I-

[root@centos6 ~]# iptables -R OUTPUT 2 -p tcp -m multiport --sports 80,443 -m state --state ESTABLISHED -j ACCEPT
[root@centos6 ~]# iptables -R INPUT 2 -p tcp -m multiport --dports 80,443 -m state --state NEW,ESTABLISHED -j ACCEPT
[root@centos6 ~]# 
[root@centos6 ~]# iptables -L -t filter
Chain INPUT (policy DROP)
target     prot opt source               destination         
SSH_RULES  tcp  --  anywhere             anywhere            tcp dpt:ssh 
ACCEPT     tcp  --  anywhere             anywhere            multiport dports http,https state NEW,ESTABLISHED 

Chain FORWARD (policy DROP)
target     prot opt source               destination         

Chain OUTPUT (policy DROP)
target     prot opt source               destination         
SSH_RULES  tcp  --  anywhere             anywhere            tcp spt:ssh 
ACCEPT     tcp  --  anywhere             anywhere            multiport sports http,https state ESTABLISHED 

Chain SSH_RULES (2 references)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:ssh state NEW,ESTABLISHED 
ACCEPT     tcp  --  anywhere             anywhere            tcp spt:ssh state ESTABLISHED 
[root@centos6 ~]# 

ICMP

حالا میخوام ما بتونیم بقیه رو پینگ کنیم ولی بقیه نتونن ما رو پینگ کنن.

[root@centos6 ~]# iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
[root@centos6 ~]# iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
[root@centos6 ~]# ping 192.168.1.33
PING 192.168.1.33 (192.168.1.33) 56(84) bytes of data.
64 bytes from 192.168.1.33: icmp_seq=1 ttl=128 time=1.61 ms
64 bytes from 192.168.1.33: icmp_seq=2 ttl=128 time=0.544 ms
64 bytes from 192.168.1.33: icmp_seq=3 ttl=128 time=0.450 ms
^C
--- 192.168.1.33 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2871ms
rtt min/avg/max/mdev = 0.450/0.870/1.618/0.530 ms
[root@centos6 ~]# 

میتونم از توی centos که روی vm نصبه ویندوزم رو پینگ کنم ولی از روی ویندوزم نمیتونم centos رو پینگ کنم.

سلام و وقت بخیر. در این جلسه میخوایم کانفیگ فایروال لینوکس یعنی iptable رو یاد بگیریم. در کل میتوان کارهایی که فایروال انجام میدهد را در 5 دست کلی تقسیم بندی کرد.
1- NAT
2- PAT
3- Filtering
4- QOS
5- Mangling
تو مورد فیلترینگ مثلا میگیم فلان آی پی به فلان پورت دسترسی نداشته باشه، یا توی nat آی پی ها به هم تبدیل میشن. pat هم شبیه nat هستش تا حدودی، فقط با پورت کار میکنه. توی فوروارد کردن پورت ها کاربرد داره، مثلا توی کشینگ. qos هم برای بررسی لود سیستم استفاده میشه، مثلا چند درصد پکت های وب سرورم دراپ شده یا چند درصد پکت های فلان آی پی دراپ شده. mangling هم فقط به درد حال گیری از خود شاخ پندارایی میخوره که هیچی از لینوکس و شبکه بلد نیستن، بعد میرن چهار تا تریک کالی یاد میگیرن و اسم خودشونو میذارن هکر. این mangling میاد اتک هایی که به سیستم زده میشه رو میگیره، به خود حمله کننده برمیگردونه و اگه سیستم حمله کننده در برابر اتک خودش مقاوم نباشه، میره رو هوا.
برای اینکه ببینید iptable در چه وضعیتی قرار داره دستور زیر را وارد کنید.
<c#>
[root@centos6 ~]# service iptables status
Table: filter
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination         

[root@centos6 ~]# 
<c#>
اگه iptables روشن نبود با دستور service iptables start روشنش کنید. اگر سیستمتون آموزشیه و چیزی به غیر از خروجی بالا میبینید، دستور iptables -F رو بزنید تا تمام rules های فایروال پاک بشه. میخوایم از صفر شروع کنیم فایروال رو کانفیگ کنیم. به خروجی دستورات زیر دقت کنید
<c#>
[root@centos6 ~]# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

[root@centos6 ~]# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

[root@centos6 ~]# iptables -L -t mangle
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         

[root@centos6 ~]# iptables -L -t filter
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
[root@centos6 ~]# 
<c#>
اگر دستور iptables رو با سویچ L- بزنم بصورت پیش فرض جدول filtering رو نشون میده. بعدش با سویچ t- جدول های دیگه رو چاپ کردم. اینا جداول پیش فرض iptable هستن که نمیتونید پاکشون کنید ولی میتونید در موارد خاص برای خودتون جدول هم بسازید ولی در بیشتر موارد با همین جدولا کارمون راه میفته. بیشتر در محیط های enterprise که لود خیلی زیاده توجیه داره جدول جدا نوشتن که سرعت پاسخ گویی سیستم پایین نیاد و یا بخوایم برای یک شرایط خاص تدابیر خاصی درنظر بگیریم.
هر کذوم از این جدول ها chain دارن. توی chain ها rule ها رو مینویسبم. chain ها یه جور طبق بندی محسوب میشه. الان جدول filter من 3 تا chain داره به نام های input و output و forwarding . توی این chain ها policy های دسترسی نوشته میشه. هر پکتی وارد سیستم میشه از این policy ها عبور میکنه. در کل 2 استراتژیک کلی برای کانفیگ فایروال داریم. اول اینکه همه چی بسته باشه، چیزایی که میخوام رو باز میکنم. دوم اینکه همه چی باز باشه و چیزایی که نمیخوام رو میبیندم. مورد اول معمولا استغاده میشه. کلا همه چی رو جلوشو میگریم، بعدش تک تک به سرویس هایی که راه اندازی میکنم، اجازه دسترسی میدم.  
این 3 تا chain که گفتم از اسمش مشخصه که روی چی حساسن. حالا میام استراتژی مورد اول رو پیاده سازی میکنم. همه چی رو میبندم. خود جلوی جیزی رو گرفتن 2 حالت داره، reject کردن و drop کردن. فرقشون اینه که drop انجام بشه log نمیندازه ولی reject اتفاق بیفته log میندازه.الان policy پیش فرض accept هست، ینی همه چی بازه. حالا با دستور زیر policy رو drop میکنم.
<c#>
[root@centos6 ~]# iptables -P INPUT DROP
[root@centos6 ~]# iptables -P OUTPUT DROP
[root@centos6 ~]# iptables -P FORWARD DROP
[root@centos6 ~]# iptables -L -t filter
Chain INPUT (policy DROP)
target     prot opt source               destination         

Chain FORWARD (policy DROP)
target     prot opt source               destination         

Chain OUTPUT (policy DROP)
target     prot opt source               destination         
[root@centos6 ~]# 
<c#>
الان دیگه حتی پینگ هم نمیشه کرد. گفتم اگر خواستیم میتونیم chain درست کنیم علاوه بر chain های پیش فرض. حالا اگه 1000 خط rule نوشته باشم، بیخود همه هزار خط خونده میشه تا برسه مثلا به خطی که ssh رو اجازه عبور میده. در این مورد میام یه chain درست میکنم واسه ssh و به جای اینکه اون هزار خط چک بشه، میگم اگه مثلا پورت مقصدت 22 هستش jump کن توی chain مربوط به ssh. حالا میخوام همین کار رو بکنم. ابتدا یک chain درست میکنم و میگم هر چی مربوط به پورت 22 بود jump کنه توی این chain. توی chain میگم چه کار کنه باهاش، مثلا اجازه بده یا هرچی.

*SSH*
<c#>
@centos6 ~]# iptables -N SSH_RULES
[root@centos6 ~]# iptables -A INPUT -p tcp --dport 22 -j SSH_RULES
[root@centos6 ~]# iptables -A OUTPUT -p tcp --sport 22 -j SSH_RULES
[root@centos6 ~]# iptables -A SSH_RULES -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
[root@centos6 ~]# iptables -A SSH_RULES -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
[root@centos6 ~]# iptables -L -t filter
Chain INPUT (policy DROP)
target     prot opt source               destination         
SSH_RULES  tcp  --  anywhere             anywhere            tcp dpt:ssh 

Chain FORWARD (policy DROP)
target     prot opt source               destination         

Chain OUTPUT (policy DROP)
target     prot opt source               destination         
SSH_RULES  tcp  --  anywhere             anywhere            tcp spt:ssh 

Chain SSH_RULES (2 references)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:ssh state NEW,ESTABLISHED 
ACCEPT     tcp  --  anywhere             anywhere            tcp spt:ssh state ESTABLISHED 
[root@centos6 ~]# 
<c#>
خط اول یک chain درست کردم. اسمش هر چی میتونه باشه. خط دوم توی جدول input گفتم که هر چی اومد و پورت مقصدش 22 بود، به ssh-rules مراجعه کن. خط بعد هم همینکار واسه جدول output یعنی هر چی خواست خارج بشه که پورت مبداش 22 بود به ssh-rules مراجعه کن. سویچ A- یعنی append و j- یعنی jump و p- یعنی پروتکل. خط سوم و چهارم توی ssh-rules اضافه شده. یکی برای ورود و یکی برای خروج. میتونستم interface رو هم محدود کنم مثلا برای ورود مینوشتم i- eth1 یعنی فقط از eth1 و برای خروج هم مث همین فقط با سویچ o-. اینطوری دیگه از هیچ اینترفیس دیگه ای نمیشد ssh زد. اگر هم میخواستید که از یک شبکه خاص فقط بشه ssh زد، با سویچ s- و رنج آی پی، اون شبکه رو مجاز میکردیم.
حالا هر چی کد نوشتیم توی حافظه جاری سیستم قرار داره و اگه سیستم ریست بشه یا سرویس رو restart کنیم، همه چی پاک میشه. برای ذخیره دستور زیر را وارد کنید. به مسیر کانفیگ فایل پیش فرض دقت کنید.
<c#>
[root@centos6 ~]# /etc/init.d/iptables save
iptables:    Saving firewall rules to  /etc/sysconfig/iptables:         [  OK  ]
[root@centos6 ~]# 
<c#>

*HTTP HTTPS*

حالا میخوام دسترسی به وب سرور رو باز کنم. اینو متفاوت با قبلی مینویسیم. دیگه براش chain جدا ننوشتم.
<c#>
[root@centos6 ~]# iptables -A INPUT -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
[root@centos6 ~]# iptables -A OUTPUT -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
[root@centos6 ~]# iptables -L -t filter
Chain INPUT (policy DROP)
target     prot opt source               destination         
SSH_RULES  tcp  --  anywhere             anywhere            tcp dpt:ssh 
ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:http state NEW,ESTABLISHED 

Chain FORWARD (policy DROP)
target     prot opt source               destination         

Chain OUTPUT (policy DROP)
target     prot opt source               destination         
SSH_RULES  tcp  --  anywhere             anywhere            tcp spt:ssh 
ACCEPT     tcp  --  anywhere             anywhere            tcp spt:http state ESTABLISHED 

Chain SSH_RULES (2 references)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:ssh state NEW,ESTABLISHED 
ACCEPT     tcp  --  anywhere             anywhere            tcp spt:ssh state ESTABLISHED 
[root@centos6 ~]# 
<c#>

حالا یکم سویچ هاشو هم یاد بگیریم، با سویچ R- میشه یک خط رو جایگزین کرد. میتونید insert هم بکنید با سویچ I-

<c#>
[root@centos6 ~]# iptables -R OUTPUT 2 -p tcp -m multiport --sports 80,443 -m state --state ESTABLISHED -j ACCEPT
[root@centos6 ~]# iptables -R INPUT 2 -p tcp -m multiport --dports 80,443 -m state --state NEW,ESTABLISHED -j ACCEPT
[root@centos6 ~]# 
[root@centos6 ~]# iptables -L -t filter
Chain INPUT (policy DROP)
target     prot opt source               destination         
SSH_RULES  tcp  --  anywhere             anywhere            tcp dpt:ssh 
ACCEPT     tcp  --  anywhere             anywhere            multiport dports http,https state NEW,ESTABLISHED 

Chain FORWARD (policy DROP)
target     prot opt source               destination         

Chain OUTPUT (policy DROP)
target     prot opt source               destination         
SSH_RULES  tcp  --  anywhere             anywhere            tcp spt:ssh 
ACCEPT     tcp  --  anywhere             anywhere            multiport sports http,https state ESTABLISHED 

Chain SSH_RULES (2 references)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:ssh state NEW,ESTABLISHED 
ACCEPT     tcp  --  anywhere             anywhere            tcp spt:ssh state ESTABLISHED 
[root@centos6 ~]# 
<c#>

*ICMP*
حالا میخوام ما بتونیم بقیه رو پینگ کنیم ولی بقیه نتونن ما رو پینگ کنن.
<c#>
[root@centos6 ~]# iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
[root@centos6 ~]# iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
[root@centos6 ~]# ping 192.168.1.33
PING 192.168.1.33 (192.168.1.33) 56(84) bytes of data.
64 bytes from 192.168.1.33: icmp_seq=1 ttl=128 time=1.61 ms
64 bytes from 192.168.1.33: icmp_seq=2 ttl=128 time=0.544 ms
64 bytes from 192.168.1.33: icmp_seq=3 ttl=128 time=0.450 ms
^C
--- 192.168.1.33 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2871ms
rtt min/avg/max/mdev = 0.450/0.870/1.618/0.530 ms
[root@centos6 ~]# 
<c#>
میتونم از توی centos که روی vm نصبه ویندوزم رو پینگ کنم ولی از روی ویندوزم نمیتونم centos رو پینگ کنم.
<center>
||http://tosinso.com/files/get/3a61cf22-0569-41bb-9b51-443935b6f636||
<center>
اگه خواستید پینگ از بیرون باز باشه:
<c#>
[root@centos6 ~]# iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
[root@centos6 ~]# iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
<c#>
عکس اینو دیگه نمیزارم جا میگیره!!!
گفتم چطوری تنظیمات iptable رو باید ذخیره کنید تا با راه اندازی محدد ، تنظیمات حفظ بشن. مسیر جایی که ذخیره میشد رو هم دیدید در خروجی دستور. حالا اگه خواستم یه backup برای خودم بگیرم دستور زیر رو میزنم و اگه خواستم از backup برای restore کردن iptable استفاده کنم، دستور بعدیشو.
<c#>
[root@centos6 ~]# iptables-save > ~/iptable.backup
[root@centos6 ~]# iptables-restore ~/iptable.backup 
[root@centos6 ~]# 
<c#>
صفحه manual رو حتما بخونید. تمام سویچ ها برای insert و delete و flush کردن و  ... رو کامل نوشته. یادتون باشه که با دستور iptable و سویچ F- تمام تنظیمات پاک میشه و از کانفیگ پیش فرض بالا میاد. در ادامه یک سری از دستورات مهم iptable رو نوشتم.
<c#>
1. Delete Existing Rules

iptables -F  (or)  iptables --flush

2. Set Custome Chain Policies

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

3. Block a Specific ip-address

BLOCK_THIS_IP=x.x.x.x
iptables -A INPUT -s $BLOCK_THIS_IP -j DROP

iptables -A INPUT -i eth0 -s $BLOCK_THIS_IP -j DROP
iptables -A INPUT -i eth0 -p tcp -s $BLOCK_THIS_IP -j DROP

4. Allow ALL Incoming SSH

iptables -A INPUT -i eth0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

5. Allow Incoming SSH only from a Sepcific Network

iptables -A INPUT -i eth0 -p tcp -s 192.168.100.0/24 --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

6. Allow Incoming HTTP and HTTPS

iptables -A INPUT -i eth0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT

iptables -A INPUT -i eth0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT

7. Combine Multiple Rules Together using MultiPorts

iptables -A INPUT -i eth0 -p tcp -m multiport --dports 22,80,443 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp -m multiport --sports 22,80,443 -m state --state ESTABLISHED -j ACCEPT

8. Allow Outgoing SSH

iptables -A OUTPUT -o eth0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

9. Allow Outgoing SSH only to a Specific Network

iptables -A OUTPUT -o eth0 -p tcp -d 192.168.100.0/24 --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

10. Allow Outgoing HTTPS

iptables -A OUTPUT -o eth0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT

11. Load Balance Incoming Web Traffic

iptables -A PREROUTING -i eth0 -p tcp --dport 443 -m state --state NEW -m nth --counter 0 --every 3 --packet 0 -j DNAT --to-destination 192.168.1.101:443
iptables -A PREROUTING -i eth0 -p tcp --dport 443 -m state --state NEW -m nth --counter 0 --every 3 --packet 1 -j DNAT --to-destination 192.168.1.102:443
iptables -A PREROUTING -i eth0 -p tcp --dport 443 -m state --state NEW -m nth --counter 0 --every 3 --packet 2 -j DNAT --to-destination 192.168.1.103:443

12. Allow Ping from Outside to Inside

iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT

13. Allow Ping from Inside to Outside

iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT

14. Allow Loopback Access

iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

15. Allow Internal Network to External network.

iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT

16. Allow outbound DNS

iptables -A OUTPUT -p udp -o eth0 --dport 53 -j ACCEPT
iptables -A INPUT -p udp -i eth0 --sport 53 -j ACCEPT

17. Allow NIS Connections

iptables -A INPUT -p tcp --dport 111 -j ACCEPT
iptables -A INPUT -p udp --dport 111 -j ACCEPT
iptables -A INPUT -p tcp --dport 853 -j ACCEPT
iptables -A INPUT -p udp --dport 853 -j ACCEPT
iptables -A INPUT -p tcp --dport 850 -j ACCEPT
iptables -A INPUT -p udp --dport 850 -j ACCEPT

iptables -A INPUT -i eth0 -p tcp -s 192.168.101.0/24 --dport 873 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 873 -m state --state ESTABLISHED -j ACCEPT

19. Allow MySQL connection only from a specific network

iptables -A INPUT -i eth0 -p tcp -s 192.168.100.0/24 --dport 3306 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 3306 -m state --state ESTABLISHED -j ACCEPT

20. Allow Sendmail or Postfix Traffic

iptables -A INPUT -i eth0 -p tcp --dport 25 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 25 -m state --state ESTABLISHED -j ACCEPT

21. Allow IMAP and IMAPS

iptables -A INPUT -i eth0 -p tcp --dport 143 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 143 -m state --state ESTABLISHED -j ACCEPT

iptables -A INPUT -i eth0 -p tcp --dport 993 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 993 -m state --state ESTABLISHED -j ACCEPT

22. Allow POP3 and POP3S

iptables -A INPUT -i eth0 -p tcp --dport 110 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 110 -m state --state ESTABLISHED -j ACCEPT

The following rules allow POP3S access.

iptables -A INPUT -i eth0 -p tcp --dport 995 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 995 -m state --state ESTABLISHED -j ACCEPT

23. Prevent DoS Attack

iptables -A INPUT -p tcp --dport 80 -m limit --limit 25/minute --limit-burst 100 -j ACCEPT

24. Port Forwarding

iptables -t nat -A PREROUTING -p tcp -d 192.168.102.37 --dport 422 -j DNAT --to 192.168.102.37:22

iptables -A INPUT -i eth0 -p tcp --dport 422 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 422 -m state --state ESTABLISHED -j ACCEPT

25. Log Dropped Packets

iptables -N LOGGING
iptables -A INPUT -j LOGGING
iptables -A LOGGING -m limit --limit 2/min -j LOG --log-prefix IPTables Packet Dropped:  --log-level 7

iptables -A LOGGING -j DROP
<c#>
بسیار خوب. این دوره آموزشی هم تمام شد. امیدوارم مفید بوده باشه. تا دوره بعد خدانگهدار.
پایان
نویسنده : سید محمد باقر موسوی
منبع : |جزیره لینوکس و سیستم های متن باز وب سایت توسینسو::https://linux.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی است

اگه خواستید پینگ از بیرون باز باشه:

[root@centos6 ~]# iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
[root@centos6 ~]# iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT

عکس اینو دیگه نمیزارم جا میگیره!!!

گفتم چطوری تنظیمات iptable رو باید ذخیره کنید تا با راه اندازی محدد ، تنظیمات حفظ بشن. مسیر جایی که ذخیره میشد رو هم دیدید در خروجی دستور. حالا اگه خواستم یه backup برای خودم بگیرم دستور زیر رو میزنم و اگه خواستم از backup برای restore کردن iptable استفاده کنم، دستور بعدیشو.

[root@centos6 ~]# iptables-save > ~/iptable.backup
[root@centos6 ~]# iptables-restore ~/iptable.backup 
[root@centos6 ~]# 

صفحه manual رو حتما بخونید. تمام سویچ ها برای insert و delete و flush کردن و ... رو کامل نوشته. یادتون باشه که با دستور iptable و سویچ F- تمام تنظیمات پاک میشه و از کانفیگ پیش فرض بالا میاد. در ادامه یک سری از دستورات مهم iptable رو نوشتم.

1. Delete Existing Rules

iptables -F  (or)  iptables --flush

2. Set Custome Chain Policies

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

3. Block a Specific ip-address

BLOCK_THIS_IP="x.x.x.x"
iptables -A INPUT -s "$BLOCK_THIS_IP" -j DROP

iptables -A INPUT -i eth0 -s "$BLOCK_THIS_IP" -j DROP
iptables -A INPUT -i eth0 -p tcp -s "$BLOCK_THIS_IP" -j DROP

4. Allow ALL Incoming SSH

iptables -A INPUT -i eth0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

5. Allow Incoming SSH only from a Sepcific Network

iptables -A INPUT -i eth0 -p tcp -s 192.168.100.0/24 --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

6. Allow Incoming HTTP and HTTPS

iptables -A INPUT -i eth0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT

iptables -A INPUT -i eth0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT

7. Combine Multiple Rules Together using MultiPorts

iptables -A INPUT -i eth0 -p tcp -m multiport --dports 22,80,443 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp -m multiport --sports 22,80,443 -m state --state ESTABLISHED -j ACCEPT

8. Allow Outgoing SSH

iptables -A OUTPUT -o eth0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

9. Allow Outgoing SSH only to a Specific Network

iptables -A OUTPUT -o eth0 -p tcp -d 192.168.100.0/24 --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

10. Allow Outgoing HTTPS

iptables -A OUTPUT -o eth0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT

11. Load Balance Incoming Web Traffic

iptables -A PREROUTING -i eth0 -p tcp --dport 443 -m state --state NEW -m nth --counter 0 --every 3 --packet 0 -j DNAT --to-destination 192.168.1.101:443
iptables -A PREROUTING -i eth0 -p tcp --dport 443 -m state --state NEW -m nth --counter 0 --every 3 --packet 1 -j DNAT --to-destination 192.168.1.102:443
iptables -A PREROUTING -i eth0 -p tcp --dport 443 -m state --state NEW -m nth --counter 0 --every 3 --packet 2 -j DNAT --to-destination 192.168.1.103:443

12. Allow Ping from Outside to Inside

iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT

13. Allow Ping from Inside to Outside

iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT

14. Allow Loopback Access

iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

15. Allow Internal Network to External network.

iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT

16. Allow outbound DNS

iptables -A OUTPUT -p udp -o eth0 --dport 53 -j ACCEPT
iptables -A INPUT -p udp -i eth0 --sport 53 -j ACCEPT

17. Allow NIS Connections

iptables -A INPUT -p tcp --dport 111 -j ACCEPT
iptables -A INPUT -p udp --dport 111 -j ACCEPT
iptables -A INPUT -p tcp --dport 853 -j ACCEPT
iptables -A INPUT -p udp --dport 853 -j ACCEPT
iptables -A INPUT -p tcp --dport 850 -j ACCEPT
iptables -A INPUT -p udp --dport 850 -j ACCEPT

iptables -A INPUT -i eth0 -p tcp -s 192.168.101.0/24 --dport 873 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 873 -m state --state ESTABLISHED -j ACCEPT

19. Allow MySQL connection only from a specific network

iptables -A INPUT -i eth0 -p tcp -s 192.168.100.0/24 --dport 3306 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 3306 -m state --state ESTABLISHED -j ACCEPT

20. Allow Sendmail or Postfix Traffic

iptables -A INPUT -i eth0 -p tcp --dport 25 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 25 -m state --state ESTABLISHED -j ACCEPT

21. Allow IMAP and IMAPS

iptables -A INPUT -i eth0 -p tcp --dport 143 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 143 -m state --state ESTABLISHED -j ACCEPT

iptables -A INPUT -i eth0 -p tcp --dport 993 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 993 -m state --state ESTABLISHED -j ACCEPT

22. Allow POP3 and POP3S

iptables -A INPUT -i eth0 -p tcp --dport 110 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 110 -m state --state ESTABLISHED -j ACCEPT

The following rules allow POP3S access.

iptables -A INPUT -i eth0 -p tcp --dport 995 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 995 -m state --state ESTABLISHED -j ACCEPT

23. Prevent DoS Attack

iptables -A INPUT -p tcp --dport 80 -m limit --limit 25/minute --limit-burst 100 -j ACCEPT

24. Port Forwarding

iptables -t nat -A PREROUTING -p tcp -d 192.168.102.37 --dport 422 -j DNAT --to 192.168.102.37:22

iptables -A INPUT -i eth0 -p tcp --dport 422 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 422 -m state --state ESTABLISHED -j ACCEPT

25. Log Dropped Packets

iptables -N LOGGING
iptables -A INPUT -j LOGGING
iptables -A LOGGING -m limit --limit 2/min -j LOG --log-prefix "IPTables Packet Dropped: " --log-level 7

iptables -A LOGGING -j DROP

نظرات