리눅스/유닉스 기본 환경에서는 1024 이하 포트(privileged ports)는 root만 사용할 수가 있다. OS별로 각각 다음 기능을 사용하면 일반유저가 1024이하 포트를 사용할 수 있다.
1) FreeBSD : MAC 인증 매커니즘 (FreeBSD 5.x 이상) 2) Linux : capabilities 설정 (File capabilities를 설정하기 위해서는 커널 2.6.24 이상) 3) Solaris : RBAC로 권한 부여 (Solaris 8 이상)
1. FreeBSD에서 MAC 모듈 로딩
FreeBSD에서는 커널의 MAC(Mandatory Access Control) 인증 매커니즘을 사용하면 일반유저가 1024이하 포트 bind를 쉽게 처리할 수 있다. 먼저 MAC portacl 모듈을 로딩한다.
# kldload mac_portacl # kldstat Id Refs Address Size Name 1 4 0xc0400000 b7ffe8 kernel 2 1 0xca62f000 3000 mac_portacl.ko
부팅때 자동으로 로딩되도록 /boot/loader.conf에 mac_portacl_load="YES" 를 추가한다. 모듈 로딩시 syslog에는 다음과 같은 로그가 남는다.
[ UID 1005 일반 유저로 실행 ] % nc -l 999 (테스트를 위해 nc명령을 사용했다. CentOS는 동일한 옵션이고, 데비안 또는 우분투는 nc -l -p 999) nc: Operation not permitted
그런데, 권한이 없다고 한다. 그렇다. 기존의 유닉스 bind 제한 설정을 해제해야 한다. reserved port 최대치를 0으로 바꾸거나 998(999포트를 일반 유저가 오픈할 것이므로 998임)로 바꾼다. 998로 설정했다면, 998까지는 기존의 유닉스 bind 제한 설정을 따르겠다는 것이다.
리눅스의 capabilities 설정을 통해서 일반 유저가 1024이하 포트 사용이 가능하다. capabilities란 무엇일까? 전통적인 유닉스/리눅스에서는 root가 모든 권한을 가진다. 일반유저가 root의 일부 권한을 갖기 위해서는 SetUID/SetGID나 sudo 등 기초적인 방법으로 권한을 부여할 수 밖에 없었다. 하지만 capabilities는 root의 권한을 세분화(커널 모듈 load/remove, 파일 소유자/소유그룹 변경, kill권한, ping 허용(ICMP허용), 리부팅 등)하여, 일반 유저도 root의 다양한 권한을 갖도록 만든 보안 모델이다. 일반 유저에게 패킷 모니터링툴을 사용할 수 있도록 허용할 수 있다. PAM 모듈을 사용하면 user를 지정하여 권한 부여도 할 수 있다.
capabilities은 커널에서 지원해야 하며, File capabilities를 위해서는 2.6.24이상을 사용하면 된다. 설정은 setcap, getcap 명령을 사용한다.
capabilities 맨페이지를 보면, CAP_NET_BIND_SERVICE이 1024이하 포트(privileged ports)에 대해 권한 부여 역할을 한다.
CAP_NET_BIND_SERVICE Bind a socket to Internet domain privileged ports (port numbers less than 1024).
1) capabilities 설정을 위해 libcap2가 패키지가 필요하다. ① 데비안/우분투는 libcap2-bin 패키지(setcap, getcap 등의 명령을 갖고 있음)를 설치한다. ② CentOS는 http://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/ 에서 소스를 받는다. 이 소스 컴파일을 위해서는 libattr-devel 패키지가 설치되어 있어야 한다. 2) setcap명령으로 CAP_NET_BIND_SERVICE를 1024이하 포트를 사용할 파일명에 설정을 해주면 된다. 심볼릭 링크 파일은 지정할 수가 없다. 3) 설정을 확인하려면 getcap을, 그리고 설정을 다시 빼려면 -r 옵션을 사용하면 된다.
capabilities 이름인 cap_net_bind_service은 대소문자 구별이 없지만, set 해당하는 ep는 소문자만 사용해야 한다. 연산자는 +, -, = 3가지로, chmod의 연산자와 동일한 의미를 갖는다. 각각 추가(+), 삭제(-), 지정한 권한으로 동일(=)하게 변경한다. file capabilities set에는 다음 3가지가 있다.
- e : effective -> 효력부여 - p : Permitted -> 허용 - i : Inheritable -> exec 할 때 권한 상속 여부
capabilities manpage에서 각 set에 대한 자세한 설명있다. 파일에 cap_net_bind_service 권한을 부여하려면 ep 또는 eip를 셋팅하면 된다는 것만 알고 있으면 된다.
다음은 999포트를 오픈한 예이다. 일반 유저로 실행된 것을 확인할 수 있다.
[ 일반 유저가 999포트 바인딩 ] $ nc -l 999 (데비안 또는 우분투에서는 nc -l -p 999)
[ root로 확인 ] # netstat -anp Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:999 0.0.0.0:* LISTEN 18021/nc <--- 999포트를 18021 PID가 ... 생략 ... # ps auxww|grep "[n]c " coffeenix 18021 0.0 0.0 1728 612 pts/15 S+ 18:59 0:00 nc -l 999 <--- 18021 PID 실행유저는 coffeenix
libjli.so 오류가 발생 시
1. etc/ld.so.conf.d/java.conf 파일에 libjli.so 파일의 절대 경로를 입력 (단 파일이 위치하고 있는 상위 디렉토리까지만, 예를 들어 jdk설치경로/lib/amd64/jli) 2. /sbin/ldconfig 실행
조치후 구동하면 된다.
4. Linux에서 capabilities 좀 더 알기
1) PAM 모듈
pam_cap.so PAM 모듈도 제공하므로, 로긴을 하거나 su 이용시 '유저별'로 다른 권한을 부여할 수 있다. /etc/security/capability.conf 에 capabilities를 설정한다. CentOS에서 libcap2 소스를 가져다 PAM 모듈을 설치할 경우 먼저 pam-devel 패키지가 설치되어 있어야 한다.
2) 프로세스의 capabilities set 상태 확인
capabilities의 Effective/Inheritable/Permitted set(집합)은 각각 32bit로 이뤄져 있다. 그리고, 각 bit별로 어떤 권한(자격)을 갖는지 지정되어 있다. CAP_NET_BIND_SERVICE 은 11번째 bit(0100 0000 0000 => hex 0400)에 해당한다. 나머지 권한들이 몇 번째 bit인지는 /usr/include/linux/capability.h에 자세히 나와있으니 생략한다.
프로세스의 capabilities set 상태 확인해보자. setcap으로 설정해둔 프로그램을 실행한다. 그리고 해당 프로세스의 PID를 확인한다. cat /proc/<pid style="font-family: 돋움체, 굴림, seoul, arial, verdana; line-height: normal;">/status|grep Cap 명령으로 bitmap 결과를 확인할 수 있다.
</pid>
# cat /proc/26494/status|grep cap CapInh: 0000000000000000 <-- Inheritable capabilities CapPrm: 0000000000000400 <-- Effective capabilities (Hex 0400. 즉, CAP_NET_BIND_SERVICE이 set되었음을 확인할수 있다.) CapEff: 0000000000000400 <-- Permitted capabilities (Hex 0400) CapBnd: ffffffffffffffff
전통적인 유닉스 시스템에서는 root가 모든 권한을 갖는다. 그러나 이 root의 권한 일부를 다른 유저에게 할당하는 것이 쉽지 않았다. RBAC(Role Based Access Control, 롤 기반 접근 제어)는 root가 갖는 권한 중 일부를 묶은 후, 그 권한 묶음을 유저에게 부여할 수가 있는 보안모델이다. 권한의 묶음을 '롤(Role)'이라는 부른다.
① 롤을 생성(roleadd)하고, (roleadd) ② 그 롤이 어떤 권한을 갖는 롤인지를 정의를 한다. (roleadd, rolemod) ③ 그리고, 그 롤에 속하는 유저를 설정하면 된다. (usermod)
이런 롤 기반 접근 제어는 업무 역할별로 권한 묶음을 만들어 유저에게 권한을 분산할 수가 있다. 예를 들어, 파일시스템 mount를 할 수 있는 권한을 'disk'라는 롤명(롤명은 ID처럼 임의로 만들면 됨)으로 만들었다고 하자. 그리고 이 롤에 유저를 할당하면 해당 유저는 mount 권한을 부여받게 된다.
자세한 권한 목록은 privileges man page 또는 /etc/security/priv_names에서 확인할 수 있다. 다음은 coffeenix유저가 1024이하 포트를 열수 있는 권한(권한명 : PRIV_NET_PRIVADDR)을 갖는 예이다. 롤 생성 방법으로 시도해봤지만 쉽게 되지 않아서, 롤 생성없이 유저에게 직접 권한을 부여하는 방법으로 처리를 했다. 설정 후 재로긴하면 권한을 갖는다.
How do I use bash for loop to repeat certain task under Linux / UNIX operating system? How do I set infinite loops using for statement? How do I use three-parameter for loop control expression?
A 'for loop' is a bash programming language statement which allows code to be repeatedly executed. A for loop is classified as an iteration statement i.e. it is the repetition of a process within a bash script.
For example, you can run UNIX command or task 5 times or read and process list of files using a for loop. A for loop can be used at a shell prompt or within a shell script itself.
for loop syntax
Numeric ranges for syntax is as follows:
for VARIABLE in12345 .. N
do
command1
command2
commandN
done
OR
for VARIABLE in file1 file2 file3
do
command1 on $VARIABLE
command2
commandN
done
OR
for OUTPUT in $(Linux-Or-Unix-Command-Here)do
command1 on $OUTPUT
command2 on $OUTPUT
commandN
done
Examples
This type of for loop is characterized by counting. The range is specified by a beginning (#1) and ending number (#5). The for loop executes a sequence of commands for each member in a list of items. A representative example in BASH is as follows to display welcome message 5 times with for loop:
#!/bin/bashfor i in12345doecho"Welcome $i times"done
Sometimes you may need to set a step value (allowing one to count by two's or to count backwards for instance). Latest bash version 3.0+ has inbuilt support for setting up ranges:
#!/bin/bashfor i in{1..5}doecho"Welcome $i times"done
Bash v4.0+ has inbuilt support for setting up a step value using {START..END..INCREMENT} syntax:
#!/bin/bashecho"Bash version ${BASH_VERSION}..."for i in{0..10..2}doecho"Welcome $i times"done
Sample outputs:
Bash version 4.0.33(0)-release...
Welcome 0 times
Welcome 2 times
Welcome 4 times
Welcome 6 times
Welcome 8 times
Welcome 10 times
The seq command (outdated)
WARNING! The seq command print a sequence of numbers and it is here due to historical reasons. The following examples is only recommend for older bash version. All users (bash v3.x+) are recommended to use the above syntax.
The seq command can be used as follows. A representative example in seq is as follows:
#!/bin/bashfor i in $(seq1220)doecho"Welcome $i times"done
There is no good reason to use an external command such as seq to count and increment numbers in the for loop, hence it is recommend that you avoid using seq. The builtin command are fast.
Three-expression bash for loops syntax
This type of for loop share a common heritage with the C programming language. It is characterized by a three-parameter loop control expression; consisting of an initializer (EXP1), a loop-test or condition (EXP2), and a counting expression (EXP3).
Welcome 1 times
Welcome 2 times
Welcome 3 times
Welcome 4 times
Welcome 5 times
How do I use for as infinite loops?
Infinite for loop can be created with empty expressions, such as:
#!/bin/bashfor(( ; ; ))doecho"infinite loops [ hit CTRL+C to stop]"done
Conditional exit with break
You can do early exit with break statement inside the for loop. You can exit from within a FOR, WHILE or UNTIL loop using break. General break statement inside the for loop:
for I in12345do
statements1 #Executed for all values of ''I'', up to a disaster-condition if any.
statements2
if(disaster-condition)thenbreak#Abandon the loop.fi
statements3 #While good and, no disaster-condition.done
Following shell script will go though all files stored in /etc directory. The for loop will be abandon when /etc/resolv.conf file found.
#!/bin/bashforfilein /etc/*
doif["${file}" == "/etc/resolv.conf"]thencountNameservers=$(grep -c nameserver /etc/resolv.conf)echo"Total ${countNameservers} nameservers defined in ${file}"breakfidone
Early continuation with continue statement
To resume the next iteration of the enclosing FOR, WHILE or UNTIL loop use continue statement.
for I in12345do
statements1 #Executed for all values of ''I'', up to a disaster-condition if any.
statements2
if(condition)thencontinue#Go to next iteration of I in the loop and skip statements3fi
statements3
done
This script make backup of all file names specified on command line. If .bak file exists, it will skip the cp command.
#!/bin/bashFILES="$@"for f in$FILESdo# if .bak backup file exists, read next fileif[ -f ${f}.bak ]thenecho"Skiping $f file..."continue# read next file and skip the cp commandfi# we are here means no backup file exists, just use cpcommand to copy file
/bin/cp$f$f.bak
done
Check out related media
This tutorial is also available in a quick video format. The video shows some additional and practical examples such as converting all flac music files to mp3 format, all avi files to mp4 video format, unzipping multiple zip files or tar balls, gathering uptime information from multiple Linux/Unix servers, detecting remote web-server using domain names and much more.