'분류 전체보기'에 해당되는 글 174건
- 2008.10.03 [번역] MAC, DAC and RBAC 비교
- 2008.10.03 [번역] 5.4 Type Rules 2
- 2008.10.03 [번역] 5.3.1. Common AV Rule Syntax
- 2008.10.03 [번역] 5.2 타입과 속성
- 2008.10.03 [번역중] 4.2.5 TE Access Vector Rules 2
- 2008.10.03 [번역중] 4.2.1. 속성선언, 4.2.2. 타입선언
- 2008.10.03 [번역중] Selinux Policy - 2 Concept
- 2008.10.03 define Syntax
- 2008.10.03 Policy Compile Setting(Make Server)
- 2008.10.03 [펌] 정규표현식 기초
MAC, DAC and RBAC 비교
From Partout.NET
MAC(Mandatory Access Control)은 사용자와 객체에게 부과된 보안 레이블(Security Label) 기반으로 접근통제를 수행하며 DAC(Discretionary Access Control)은 객체에 부여된 허가, 거부 정책에 기반하여 객체에 대한 접근을 통제한다. 상용 환경에서는 정보의 변경 가능성이 불법 사용자에 의한 정보의 접근 가능성인 비밀성보다 더 중요한 관심사가 될 수 있다. 예를 들어 은행 업무에서 예금 계좌에 대한 정보 변경에 관련된 위협이 예금 계좌에 관련된 정보의 접근보다 더 위협적일 수 있다. 그런데, MAC은 등급화된 정보의 기밀성을 위한 보안에 촛점이 맞춰져 있고 DAC은 접근 권한이 객체의 소유자(owner) 의해 임의로 변경될 수 있어서 기업이나 정부 조직과 같이 무결성을 요구하는 상업적 응용의 정보 보안에는 부적절하다. 그래서 무결성 제어가 필요한 상용 환경에서는 RBAC(Role-Based Access Control) 방식이 MAC, DAC의 대안으로 주목받고 있다.
RBAC은 필요할 때 MAC, DAC과 함께 사용될 수 있는 접근통제의 독자적인 요소이다. 그럴 경우 접근은 RBAC, MAC, DAC에 의해 허가되었을 경우에 허락된다. 물론 RBAC 그 자체 만으로도 존재할 수 있다.
RBAC 자체는 임의적, 또는 강제적인 메커니즘인가? 이 대답은 RBAC 시스템에서 사용자, 역할, 허가의 정확한 본질과 설정뿐만 아니라 임의적인 것과 강제적인 것의 정확한 정의에 달려있다. 강제적인 것은 각 사용자가 어떤 허가 또는 사용자가 역할에 할당되는가에 대한 선택권을 가지지 못하는 것이고 반면에 임의적인 것은 각 사용자가 이러한 결정을 만들 수 있다는 것을 의미한다. 앞에서 언급한 것처럼 RBAC은 자체로서는 정책 중립적이다. RBAC의 특정한 설정에 따라 강제적인 요소를 가지게 되고 또한 임의적인 요소를 가질 수도 있게 된다.
RBAC 개념
평범한 UNIX 시스템에서, 루트(root)는 모든 파일을 읽고 쓸 수 있으며 모든 프로그램을 실행시킬 수 있고 모든 프로세스에 종료 신호를 보낼 수 있는 권한을 가진다. 실제적인 말로, 이것은 슈퍼유저가 될 수 있는 모든 사람은 사이트의 방화벽을 수정하고, 회계 보고서를 바꾸고, 직원들의 급여와 다른 비밀 기록을 읽을 수 있고, 심지어 전체 네트워크를 못쓰게 할 수도 있다. 그렇기 때문에, 조직들이 더 이상 그들이 그래왔던 것처럼 루트의 암호를 자유롭게 놔 두지 않는다는 것은 의심할 여지가 없다.
RBAC는 모든 권한을 갖거나 권한을 전혀 갖지 않게 되는 슈퍼유저 모델에 대한 대안이다. RBAC는 가장 특권이 적은 보안 원리에 따라 유지되며, 그것은 어떤 사용자도 그 사람의 일을 수행하는데 필요한 권한 이상을 가지지 않는다는 것을 말한다. RBAC는 한 조직이 슈퍼유저의 능력들을 분리할 수 있게 해주고 그것들을 특정 개인들을 그들의 일의 필요에 따라 할당하기 위한 특별 사용자 계정 혹은 역할로 포장할 수 있게 해준다. 이것은 다양한 보안 정책을 가능하게 해 준다. 계정들은 보안, 네트워킹, 방화벽, 백업, 그리고 시스템 운영과 같은 영역에서 특정 목적의 관리자를 위해 설정될 수 있다. 한명의 강력한 관리자를 선호하고 좀 더 복잡하게 사용자들이 그들 자신의 시스템의 일부를 고칠 수 있도록 하길 원하는 사이트는 상급 사용자(Advanced User) 역할을 설정할 수 있다. 보안의 많은 측면에서, RBAC는 단지 기술만은 아니다. 그것은 산업을 수행하는 방식이다. RBAC는 시스템 제어를 재할당 하는 수단을 제공하지만, 그 구현을 결정하는 것은 그 조직이다.
RBAC모델은 2004년에 ANSI 표준으로 등재되었으며, 모델의 설명, 기능, 스펙까지 표준문서에 정리되어 있어 개발자에게 좋은 가이드가 될 것이다. 표준에서는 RBAC을 세가지 모델로 구분하고 있다.
- Core RBAC 모델
- Hierarchical RBAC 모델
- Constrained RBAC 모델
자세한 사항을 표준문서를 참고하기 바란다.
참조 사이트
1. NIST 의 RBAC 페이지:
http://csrc.nist.gov/rbac/#intro
2. RBAC
http://en.wikipedia.org/wiki/RBAC
Chapter 2.3 The Role( 역활 ) of Rules
SElinux는 또한 role-based access control(RBAC)를 제공한다.SElinux의 RBAC (ex: root 사용자가 가진 권한을 일반 사용자에게 일부만 허용하게 하는 역할 기반 접근 제어를 사용) 는 타입 시행를 토대로 되어 있다. Selinux에서의 접근제어는 타입 시행을 첫번째로 거친다. Roles은 프로세스의 보안 문맥에서의 rule식별자에 기초된 변환되는 한계를 가진다.
이런식으로 정책 작성자는 domain 타입들의 설정으로의 변환을 허용하는 규칙을 만들 수 있다.( 타입 시행 규칙이 변환을 허용한다는 가정하에.)
그 때문에 규칙의 제한을 정의한다. 타입 시행 규칙에 따르면 비록 패스워드 프로그램은 새로운 passwd_t domain에 들어간 user_t domain에 의해 실행되지만 또한 변환이 일어나기 위한 새로운 domain 타입과의 결합되는 것을 허용할 수 있다.
<FIGURE 2-6> p-30
우리는 보안적인 문맥의 role부분( user_r )추가했다. 또한 우리는 새로운 규칙인 특별한 role statement를 추가했다.
role user_r type passwd_t;
이 role statement은 role 식별자( user_r )를 선언하고 미리 선언된 role( passwd_t )와 결합시킨다.이 선언의 의미는 이러하다.
" passwd_t 타입은 user_r role을 지닌 보안 문맥과 동시에 존재하도록 허용된다. "
이 role statement 없이 새로운 문맥인 joe:user_r:passwd_t 는 만들어 질 수 없다. 그리고 execve() 시스템 콜은 실패 할 것이다. 심지어 TE정책이 모든 접근을 가진 user_t 타입을 allow할지라도.
정책 작성자는 한층더 강요된?? 규칙을 정의하고 특정한 유저들에게 그 규칙들을 결합할 수 있다. 예를 들어 passwd_t 타입과는 결합되지 않은 user_r과 동일한 restricted_user_r을 생성한다고 했을 때 user_r대신에 restricted_user_r이 joe의 role(역활)이라고 한다면 Joe는 패스워드 프로그램을 실행할 수 있는
권한을 부여받지 못한다. 심지어 TE규칙이 그의 domain 타입( user_t ? )의 접근을 허용 한다고 할지라도.
( 지환 생각 : 어떠한 유저에 대해 권한이 부여된 user_t 타입에 user_r라는 역활권한을 더 추가하여 작업을 수행할 수 있도록 하는 접근제어 권한을 말하는 듯하다. )
5.4 Type Rules
Type Rules 은 실행중에 객체들의 생성이나 relabel을 위한 명세를 한다. 우리는 이미 Chapter 2에서 예로써 보았다. type_transition 규칙을 이용한 domain transition을...
Type Rules 에는 아래와 같이 두 종류로써 정의 된다.
type_transition : domain transition과 객체 생성을 위한 label을 수행하기 위한 명세
type_change : SElinux-aware application에 의해 실행되어지는 relabel을 위한 명세
Common Type Rule Syntax
다음은 하나의 source,target, 그리고 default type , 하나의 객체 클래스를 가진 타입 규칙의 간단한 형태이다.
type_transition user_t passwd_exec_t : process passwd_t;
이 규칙은 chapter 2(다음 섹션에 제시)에서 보았던 것이다. 다시 해석하자면 user_t 타입의 프로세스가 passwd_exec_t타입의 한 파일을 실행할때 이 프로세스 타입은 별도로 요청하지 않는다면 defalut인 passwd_t로 변화를 시도할 것이다.
( 쟌이 생각 : 쉽게 말해서 만약 로그인을 한다면 로그인전의 권한들을 가진 type을 이용하여 로그인을 하면 로그인자가 가질 수 있는 타입으로 바뀐다는 것 )
target 타입은 정해진 객체 클래스가 process일때 file 객체 클래스와 결합된다. 그리고 정해진 객체 클래스(process)는 소스타입과 default타입(passwd_t)과 결합된다. ??
AV rules와 마찬가지로 type rules에서도 여러개의 타입을 묶어서 처리 할 수 있다.
type_transition { user_t sysadm_t } passwd_exec_t : process passwd_t;
이 type_transition 규칙은 두개의 타입인 user_t와 sysamd_t를 소스리스트로 가지고 있다. AV rules처럼 이 규칙은 두개의 규칙으로 확장 가능하다.
type_transition user_t passwd_exec_t : process passwd_t;
type_transition sysadm_t passwd_exec_t : process passwd_t;
속성의 사용또한 AV rules처럼 사용할 수 있다.
소스필드나 타겟필드와는 다르게 default type에서는 두새의 멀티 타입을 사용할 수 없다. 만약 두개 이상으로 사용 된다면 이 규칙은 애매해지고
커널이 두 타입중에 어느 것을 사용할지를 결정하기가 불가능 해질 것이다.
하나의 default 타입을 위한 이 제한은 또한 두개의 동등한 default타입로써 같은 소스타입, 타겟타입과 객체 클래스를 가지지 못한다는 뜻이 된다.
예를 보자
type_transition user_t passwd_exec_t : process passwd_t;
type_transition user_t passwd_exec_t : process user_passwd_t;
두 정책이 현재의 정책에 있을려 한다면 이 정책 컴파일러는 에러를 낸 것이다. 만약 두 정책에서 passwd_t 와 user_passwd_t 이 현재 존재한다면 default 타입으로 무었을 사용 할 것인가??
Chapter 2의 type_transition 부분 p28 ( 2.2.5 Default Domain Transition : type_transistion statement )
default에 의해 일어나는 domain 변환을 지원 (우리는 주로 패스워드 프로그램의 경우서 이 것을 원한다.) 하는 것에
대하여 새로운 규칙인 type transition rule ( type_transition )의 소개를 필요한다. default 변환은 만약 따른 명세적인 변환 요청이 없을 때 시도 되어져야 한다.
type_transition user_t passwd_exec_t : process passwd_t;
이 규칙의 문맥은 allow규칙의 문맥과 다르다. source와 target 타입들, process 클래스 객체는 유효하지만 permission
대신에 default type( passwd_t )이 사용되었다.
type_transition 규칙은 execve() 시스템콜의 default에 의해 나타난다. 만약 호출한 프로세스의 domain타입이 user_t
그리고 실행가능한 파일의 타입이 passwd_exec_t ( figure 2-5 참조 )이면 새로운 domain인 passwd_t로의 변환이 시도된다.
type_transition 규칙은 정책 작성자로 하여금 유저의 명시적 입력없이 초기화된 default domain를 이용해 권한(권한이 부여된 default 타입) 변환을 가능하게 한다.
예를 들어 joe는 접근제어나 타입들에 대한 어떤 것은 알고 싶지 않고 단지 패스워드를 바꾸고 싶을 때 그 시스템
과 정책디자이너는 type_transition 규칙을 사용하여 유저에게 쉽게 변환 할 수 있도록 해줄 수 있는 것이다. 만약
이 것이 없다면 사용자가 자신의 패스워드를 바꾸기 위해 selinux상에서의 타입과 접근제어를 자기가 작성하거나
수정해야 할 것이다.
5.4.2 Type Change Rules
우리는 Selinux를 가진 어플리케이션에 의해 실행되어진 Relabeling을 위한 default types을 명세한 type_change 규칙을 이용할 수 있다. type_transition 규칙과 동일하게 type_change규칙은 default에 대한 명세를 하지만 접근을 허용하진 않는다. 하지만 type_transition과 달리 type_change의 효과는 커널안에서는 필요한 권한을 주지 않지 않고
userspace 어플리케이션에 의존적이다는 것이다. login, sshd와 같이 정책에 기초한 relabel 객체들처럼 말이다.
예를 보자
type_change sysadm_t tty_device_t : chr_file sysadm_tty_device_t;
위의 규칙은 sysadm_t 타입을 대신하여 tty_device_t 타입의 character file 을 relabeling 할 때 sysadm_tty_device_t
타입을 사용해야 한다는 뜻이다.
위의 규칙은 type_change규칙중 유저 로그인에서의 마지막 종점을 relabeling하는 가장 일반적인 쓰인 것의 한 예이다.
login 프로그램은 SELinux 모듈에서 커널 인터페이스를 경유하여 정책에 질문한다. sysadm_t타입을 거치고
tty_device_t, 그리고 바뀌어 relabel을 위해 쓰이는 타입으로써 sysyadm_tty_device_t 타입을 받는다.
이 메카니즘은 로그인 프로세스에게 새로운 로그인 세션동안 유저를 대신하여 tty device를 label할 수 있게 한다.??
어플리케이션에서의 hard-coded 대신에 정책에서의 캡슐화된 타입의 명세를 남겨두게 된다.??
우리는 아마도 이것을 잘 쓰지는 않는다. 만약 type_change규칙을 쓴다면 대게 core operating systes services에 의해
쓰일 것이다.
Type_member rules
정책 커파일러는 또한 3번째 규칙인 type_member를 지원한다. 최근 이 규칙은 아직 의미없는 규칙이며 효과적이지도
않다. 하지만 우리는 여기서 이것을 언급한다. 왜냐하면 이규칙에 대한 필요성을 위한 작업이 계속 되고 있기 때문이다.
type_member 규칙은 장래에 polyinstantiated object( 여러 형상화된 객체들 )의 멤버들를 위한 타입을 명세를 지원 할 것이다.
이 규칙은 아마도 뜻깊은 규칙이 될 것이다. 이 규칙의 문법은 앞의 두 규칙의 문법과 동일하다.
5.3.1. Common AV Rule Syntax
비록 각각의 AV 규칙은 다른 목적을 가지지만 그들은 똑같은 기본 문맥을 가진다.
그리고 각 5개의 원소를 포함한다.
- Rule Name
: allow, dontaudit, auditallow, 또는 neverallow
- 소스 타입 ( source type )
: 접근이 주어질 타입, 대개 접근이 시도되는 프로세스의 도메인 타입을 말한다.
- 타겟 타입 ( target type )
: 접근이 주어질 소스 객체의 타입
- 객체 클래스 ( object class )
: 접근이 허용되어진 것에 대해 명세한 객체의 클래스
- 허용 ( permission )
: 객체 클래스 나타내기위한 타겟 타입이 허용한 소스의 허용 권한에 대해 명세한다.
단순한 AV 규칙을 가진 것은 소스타입, 타겟타입, 객체 클래스, 허용에 대한 정보를 가진다.
아래의 allow 규칙을 통하여 AV 규칙과 같은 많은 예를 볼수 있다.
allow user_t bin_t : file execute;
이 allow 규칙은 source type 인 user_t, target type인 bin_t, object class인 file, 그리고 permission에 해당하는 execute가 있다.
이 규칙을 간단히 풀이하자면 " bin_t타입의 파일들을 user_t 타입이 실행하도록 허용한다. "
그외의 다른 4개의 av 규칙또한 정확한 같은 문맥을 가진다.
예) auditallow user_t bin_t : file execute;
AV Role에서의 속성 사용 ( Using Attribute in AV Rules )
이때까지 우리는 type을 선언함에 있어 source type과 target type을 써서 선언을 했다. 하지만 AV Rules에서 속성을 사용하여 멀티 타입을 이용하는 방법
도 있다. 예로 가령 exec_type이라는 일반 유저 프로그램에서의 모든 파일과 접근하는 속성을 정의하고 우리는 bin_t같은 명백한 타입보다 앞에서 언급했던
exec_type 속성을 사용할 수 있다. 다음을 보자
allow user_t exec_type : file execute;
앞의 예와 같지 않다. 이 규칙은 커널에 의해 직접적으로 반영되지 못한다. 속성을 포함하고 있는 규칙은 속성과 함께 결합되어 있는 각 타입을 위한 분리 키안 커널 내부로 확장이 된다.?? 만약 20개파일 타입이 exec_type속성과 결합되어 있다면 커널 AVC는 아마도 20개의 키를 규칙과 결합할 것이다.??
우리는 또한 속성을 AV rule의 소스로써 또는 rule의 소스와 타겟 양쪽으로도 이용할 수 있다 예를 들어 가령 우리가 domain이라는 모든 domain 타입( user_t 포함 ) 과 결합된 속성을 만들고 그 모든 domain 타입이 file_type속성을 가진 파일 타입을 실행하고 싶다면 다음과 같이 작성할 수 있다.
allow dimain exec_type L file execute;
규칙의 더 좋은 확장성에 대한 설명을 하자면 가령 우리의 정책이 user_t와 staff_t타입을 가진 domain속성과 bin_t와 local_bin_t와 sbin_t의 파일
타입을 가진 exec_type속성이 결합된다면 위의 단순한 규칙은 다음과 같은 명백한 규칙과 동등한 의미를 가진다는 것이다.
allow user_t bin_t : file execute;
allow user_t local_bin_t : file execute;
allow user_t sbin_t : file execute;
allow staff_t bin_t : file execute;
allow staff_t local_bin_t : file execute;
allow staff_t sbin_t : file execute;
AV rules에서의 멀티 타입과 속성 ( multiple types and Attributes in AV Rules )
AV_Rules에서의 소스필드와 타겟필드에서의 싱글 타입 또는 속성의 쓰임에 제한은 없다. 다 나아가 차라리 우리는 멀티 타입또는 멀티 속성을 쓸 수가 있다.
하나의 타입 또는 속성보다 더 존재할 경우 다음과 같이 쓸 수 있다.
allow user_t { bin_t sbin_t } : file execute;
이 규칙에서 타겟은 bin_t과 sbin_t 양쪽이 된다.
또한 우리는 소스필드에서도 다음과 같이 쓸 수 있다. 다음 예는 타겟필드와 소스 필드에서 같이 혼합하여 멀티 선언한 것이다.
allow {user_t domain} {bin_t file_type sbin_t} : file execute ;
특별한 타입 self
정책언어는 self라는 정해진 단어가 있다. 이는 하나의 AV_Rule의 타겟 필드에서 쓰일 때 한 타입과 같은 역활을 한다. 예를 들어보자
밑의 예의 두 규칙은 서로 같은 뜻이다.
allow user_t user_t : process signal;
allow suer_t self : process signal;
self라는 키워드는 단순히 각 소스타입을 위한 한 규칙을 대신하여 쓴다는 것을 의미한다. 그래서 이 소스와 타겟 필드의 내용은 같은 것이 되는 것이다.
다음 예를 보자
allow {user_t staff_t} self : process signal;
이 예에서 두개의 정책이 만들어 졌다. 이 규칙은 다음 예의 규칙과 동일하다.
allow user_t user_t : process signal;
allow staff_t staff_t : process signal;
self는 source필드의 자기 자신과 관계가 있다. 특별히 user_t가 staff_t에 접근이 허용되지는 않는다. 그 반대도 그렇다.
self는 특별히 속성, 많은 양의 타입 리스트, AV rule 의 소스로써의 속성에서 가치를 지닌다. 예를 들어 우리가 모든 domain에게 자기 자신에 대해서만 signal할수 있도록 하고 싶다면 우리는 아마도 이런 식으로 작성할 지도 모른다.
allow domain diamin : process signal;
비록 이 규칙도 우리가 원하는 결과를 가지고 오지만 이 또한 모든 도메인끼리의 signal할수가 있다. 이 것은 보안상 좋지 않다. self를 씀으로써 우리는
각 도메인 타입에서 자기 자신에게만 접근을 허용할 수 있도록 보장해 준다.
allow domain self : process signal;
The Negation Special Operator
AV rules에서 타입을 위한 마지막 문맥은 타입 취소이다. 이 문맥은 주로 타입의 리스트와 규칙에 주어진 속성으로부터 타입을 제거할때 주로 쓰인다.
- operator를 이용하여 사용이 되며 타입 이름의 처음에 위치하게 된다. 예를 들어 우리가 sbin_t 타입을 제외한 exec_type 속성을 가지고 그 타입의 파일을
실행하고 싶다면 다음과 같이 작성하면 된다.
allow domain { exec_type -sbin_t } : file execute;
이 규칙은 exec_type 속성이 마치 sbin_t 타입을 포함하지 않는 것 처럼 동작 될 것이다.
타입 취소에 대한 문법은 순서에 의존적이지 않다.
allow domain { -sbin_t exec_type } : file execute;
Specifying Object Classes and Permissions in AV Rules
AV rules는 또한 Permissions와 Object classes 의 리스트를 포함할 수 있다.
예를 보자
allow user_t bin_t : { file dir } { read getattr };
이 규칙은 결과적으로 두 키를 가지며 다음의 규칙과 같은 의미를 가진다.
allow user_t bin_t : file { read getattr } ;
allow user_t bin_t : dir { read getattr };
맨 위의 문법을 쓰면 간편하지만 이 것은 또한 file과 dir인 두 object classes에게 모두 permissions이 허용된다는 의미가 된다.
만일 두 object중 dir이 search에 대한 권한을 부여한다면 우리는 두 규칙을 사용하여 작성해야 할 것이다.
만일 아래와 같이 규칙이 작성된다면...
allow user_t bin_t : { file dir } { read getattr search };
file object class에게도 serach의 권한을 부여하게 됨으로 좋지 않다..
그러면 어떻게 해야할까? 다음과 같다..
allow user_t bin_t : file { read getattr };
allow user_t bin_t : dir {read getattr search };
Special Permiision Operators for AV Rules
우리는 Permissions 리스트를 작성함에 있어 2개의 특별한 operator를 사용할 수 있다. 첫번째는 * operator이다
이것은 object class를 위한 모든 권한을 줄 때 사용된다. 예를 보자
allow user_t bin_t : { file dir } *;
두번째는 ~ operator이다 예를 보자
allow user_t bin_t : file ~{ write setattr ioctl };
컴파일 할때 이 규칙은 write, setattr, ioctl을 제외한 파일의 객체 클래스를 위한 모든 permissions을 허용해 준다.
5.3.2. Allow Rules
앞에서 배운 allow라는 권한 설정 규칙에 대한 예는 Selinux 정책의 가장 첫번쨰 목적을 구현하는데 가장 일반적인 것이다.
여기서 allow라는 규칙은 실행동안 주어질 모든 권한에 대한 명세를 말한다. 이것은 오직 Selinux 정책안에서만 권한이 허용되는 의미이다.
한가지 기억할 것은 비접근은 예외로 되어 있다는 점이다. 예를 보자
allow user_t bin_t : file { read execute };
이 예에서 우리는 user_t는 bin_t 타입의 파일에 대하여 write할 수 없다.
5.3.3. Audit Rules
Selinux는 기록이나 검사(감사), 정책에 의해 허용되었거나 거부된 접근시도에 대한 광범위한 기능을 가지고 있다. 이 감사 메시지를 종종 AVC message라고 부른며 접그시도가 허용되었거나 거부되었거나 또는 소스나 타겟의 보안 문맥, 그리고 접근 시도에 포함된 자원에 대하여 세부정보를 제공한다.
다른 커널 메시지나 /var/log에 로그파일로 저장된 것과 유사한 이 메시지는 정책개발, 시스템 관리, 시스템 모니터링을 위해 없어서는 안될 도구이다.
이 Chapter에서 우리는 접근시도가 메시지로 만들어져 형성되는 정책 형태에 대해 알아 볼것이다. 파트 3에서는 메시지가 디버깅과 정책의 이해에 어떻게
이용되는지에 대해 더 많은 정보를 제공한다.
예외적으로 Selinux는 허용된 것에 대한 접근체크에 대해 기록하지 않는다. 그러나 거부된 것에 대해서는 기록을 한다. 놀랄일은 아니다. 거의 모든 시스템에서
수천개의 접근들이 매초마다 허용되어진다. 그러나 몇몇의 접근들이 거부된다. 접근에대한 접근정보는 이미 기대되어졌던 것이기 때문에 감사 요청을 하지 않는다. 거부된 접근은 종종 일어나지만 기대치 않게 항상 일어나는 것이기도 하다. 이것들에 대한 감사작업은 정책 버그나 침입 시도인지를 모니터하는 관리자를
도와주는 것이다.
SElinux는 접근시도에 대하여 감사되도록 하는 컨트롤에 대한 두개의 AV Rules를 허용한다. dontaudit와 auditallow이다.
dontaaudit 규칙은 가장 일반적으로 사용된다. 이것은 감사되어지지 않아야 한다는 접근거부에 대한 명세를 나타낸다..??
예를 보자
dontaudit httpd_t etc_t : dir search;
이 규칙은 httpd_t타입의 프로세스들이 etc_t타입의 디렉토리에 search에 대해 거부되어질 때에 대한 명세를 한다. 이규칙에 의하면 거부되어질때 감사작업
을 하지 말라는 의미이다. dontaudit규칙은 우리가 기대하고 있던 거부에 대한 감사(검사)를 덮어버리고 싶을 때 사용된다. 그리고 이 규칙은 우리에게
불필요한 접근이 주어지는 것을 피할수 있도록 해준다.
다른 audit(감사,검사) 규칙은 auditallow이다 이 규칙은 접근시도가 허용된 것에 대한 감사에 대하여 컨트롤 할 수 있도록 해준다. 거부된 접근과 다르게
허용된 접근은 예외적으로 기록되지 않는다. 예를 보자
auditallow domain shadow_t : file write;
이 규칙은 domain 속성이 shadow_t 타입의 파일에 write접근을 성공적으로 획득했을때에 대하여 접근 허용에 대한 감사를 명세를 하고 있다.
auditallow 규칙은 주로 중요한 보안 이벤트를 가진 접근에 대해 감사를 실시한다.
shadow password파일에 쓰이는것이 포함된 auditallow 규칙을 가진 접근이나 커널에 새로운 정책이 실리는 것에 대한 예가 있다.
기억하자! audit 규칙은 예외적으로 있는 검사에 대한 세팅을 할 수 있도록 한다. allow 규칙은 접근이 허용되는 것에 대한 명세를 하고
auditallow는 접근허용이 아닌 오직 권한이 허용된 것의 감사를 할 수 있도록 해주는 것이다.
5.3.4. Neverallow Rules
AV Rule의 마지막 규칙은 neverallow 규칙이다 이 규칙은 allow규칙에 의해 절대 허용되지 않아야 하는 확실한 접근들에 대한 명세이다.
이 규칙의 존재이유는 예외에 의해 접근이 거부되기 때문이다. 즉 확실히 허용되기를 바라지 않는다고 하지 않은 것에 의해 정책이 설정되고
그 때문에 우리의 정책내에 그 허용들의 사고적인 포함을 막는다.
neverallow 규칙은 이러한 상황을 막아주는 것이다. 예를 보자.
neverallow user_t shadow_t : file write;
위의 규칙은 컴파일 에러에 의해 user_t 타입에 shadow_t 타입의 파일을 쓰는 규칙을 정책에 추가하는 것을 막아준다.
이 규칙은 접근을 제거하는 것이 아니라 단지 컴파일 에러를 내 주는 것이다. 이 규칙은 allow규칙을 쓰기 시작하기 전에 우리의 정책에 대하여 중요한
것이다. 그리고 이 규칙은 우리가 의도하지 않았던 허용에 대해서 막아주는 역활도 한다.
neverallow 규칙은 다른 AV Rules에서는 할 수 없는 어떤 추가적인 문맥이 있다. 특별히 neverallow 규칙에서의 소스와 타겟타입의 리스트에서는
wildcard(*)와 complement(~) operator을 포함할 수 있다. 예를 보자!
neverallow * domain : dir ~{ read getattr };
이 규칙의 상태는 domain 속성과 결합된 타입들의 하나와 연결된 디렉토리에 read와 getattr접근을 제외한 나머지 permission의 접근을 허용치 않는다는
의미이다. 여기서 *operator는 neverallow 규칙의 source타입에서 필요하다는 것이다. 왜냐하면 앞에서 언급했듯이 일부 또는 모든 타입들이 아직
생성되기 전이기 때문이다. 앞에서 우리는 allow전에 neverallow을 한다고 했다..(7줄 위에..언급)
다른 일반적인 neverallow 규칙의 예를 보자.
neverallow domain ~domain : process transition;
이 규칙은 이 Chapter앞에서 설명한 domain속성의 개념을 보충해주기 위한 것이다. 이 규칙의 상태는 프로세스는 domain속성을 가지지 않은 타입과 transition할 수 없다는 의미이다. 이것은 domain속성을 가지지 않은 프로세스를 위해 타입이 설정되는 정책을 만드는 것이 불가능 해지게 한다.
BookName : Selinux by Example -
5.2.2 Types and Attributes (Page 93 ~ 97 )
아마도 상상될 것이다. 그 많고 복잡한 정책은 시스템상의 모든 다른 리소스을 나타내는 아마도 수백개 또는 수천개의 타입일 것이라는 것을...
예를 들어 페도라 4에서 쓰는 정책은 800개보다 적게 쓰고 있다. ... ...
속성은 2가지 방법으로 쓰인다. 하나는 타입의 특징 또는 특성으로써 또 하나는 타입의 한 그룹으로써...
가령 우리가 backup application에 모든 파일에 대한 읽기 권한을 주고 싶다고 하자. 우리는 먼저 backup application (backup_t)의 도메인 타입을 먼저
생성한다. 그리고 그 타입에게 어떤 파일과 결합된 모든 타입에 접근할 수 있는 권한을 준다.( 파일과 연결된 다른 타입에게 접근할 수 있는 권한 )
예)
type backup_t;
# 파일 객체를 쓰는 다른 모든 타입에 접근하는 읽기 권한을 주는 룰을 추가한다.
allow backup_t httpd_user_content_t : file read;
allow backup_t shadow_t : file read;
여기서우리는 backup_t 도메인 타입에게 두 파일 타입들에게 접근하도록 해주었다. 우리는 httpd_user_content_t ?? 와
/etc/shadow 파일의 타입으로 예상되는 shadow_t 타입을 가진 것으로 볼 수 있다. 두개는 backup application 이 반드시 읽는 디스크 파일이다.
이렇게 우리는 수 많은 타입에게 수 많은 권한을 줄 수 있으며 우리는 backup_t에게 접근을 허용한 규칙들을 기억 할 수 있다.
하지만 이것은 지루하고 에러나기 쉬운 처리방법이다. 속성들은 '그룹접근'으로 쉽게 명세해 준다. 속성 선언으로 우리는 모든 파일 타입과 속성접근
을 줄 수 있을 것이고 이것은 하나하나 타입을 결합하는 것보다는 좋을 것이다. 왜냐하면 그렇게 되면 backup_t는 하나의 규칙으로 접근허용을 줄 수 있
기 때문이다. 아래의 속성 선언을 보자.
attribute file_type;
이 상태는 file_type라고 하는 한 속성을 선언한 것이다. 타입과 속성들은 같은 이름 공간을 가지고 그래서 타입과 속성은 같은 이름을 가질 수 없다.
아래의 규칙으로 우리는 file_type와 모든 관계된 타입들이 서로 연결되어 있다는 것을 추측 할 수 있으며 그것을 우리는 backup_t에 읽기접근을 허용하는
문장을 하나로 나타낼 수 있다.
allow backup_t file_type : file read;
수백개의 접근허용 규칙을 주는 것을 우리는 한 문장으로 나타내었다. 이 정책이 컴파일 할때 이 한문장의 규칙은 자동으로 수백개의 파일타입들을 접근제어하기 위한 규칙으로 확장된다. 더 중요한 것은 우리가 파일을 위한 새로운 타입을 정의 할때이다. 우리는 file_type 속성과 backup_t 도메인 타입의 결합으로 새로운 읽기 접근에 대한 정책을 만들 수 있을 것이다.( 재사용성)
5.2.3 타입과 속성의 결합
앞에서 우리는 어떻게 타입과 속성을 정의하는 지 배웠다 하지만 이 두개가 서로 결합하는 지에 대해서는 알지 못한다. 타입은 거의 보통 타입을 선언할 때
속성과 함께 결합된다., 예를 들어 우리는 file_type의 속성과 httpd_user_content_t와의 결합을 보자.
type httpd_user_content_t file_type;
...
...
타입들은 하나의 속성만을 가지지는 않는다. 일반적으로 타입은 몇개의 속성과 결합된 형태를 지닌다. 예를 들어 우리는 모든 웹서버를 통해 모든 파일을 이용 할수 있도록 하기 위해 httpdcontnet속성을 만든다. 타입은 file_type 속성과 함께 httpdcontent속성을 같이 가지게 된다. 다음 예를 보자.
type httpd_user_content_t, file_type, httpdcontent;
type shadow_t, file_type;
allow backup_t file_type : file read;
allow httpd_t httpdcontent : file read;
우리는 지금 httpd_user_content_t타입에 속성을 추가했다. 그리고 shadow_t타입의 좀더 특권적인 선언을 통해 우리는 오직 file_type속성만 가지도록 했다. 왜냐하면 웹서버에 shadow 패스워드 파일을 보이게 한다는 것은 좋은 생각으로 보이지 않기 때문이다. ( <- 두번째 타입선언에서 httpdcontent속성은 없는 이유 )
또한 두개의 allow한 규칙을 가지고있는데 웹서버와 backup program에 그들이 필요로 하는 속성과 결합된 형태로 존재한다. 결과적으로 웹서버(httpd_t)는 httpdcontent의 속성으로 모든 파일을 읽을 수 있고 그러나 shadow_t와 같은
다른 파일은 읽지 못한다. 반면에 backup application( backup_t )은 file_type 속성을 가진 모든 파일을 읽을 수 있다.
게다가 typeattribute를 통하여 기존의 type과 결합할 속성들을 결합할 수 있다. 예를 보자
type httpd_user_contnet_t;
typeattribute httpd_user_content_t file_type, httpdcontent;
# 한문장으로 나타내면
type httpd_user_content_t, file_type, httpdcontent;
# 저기 위에 앞의 선언과 동일
- TE Access Vector Rules은 타입한쌍과 객체 안전 클래스를 바탕으로 한 허용설정을 명세하고 있다.
- 이 규칙은 섹션 3.1의 토의에서 TE 처리 테이블을 정의하고 있다.
- ...
te_av_rule -> av_kind source_types target_types ’:’ classes permissions ’;’
av_kind -> ALLOW | AUDITALLOW | DONTAUDIT
source_types -> set
target_types -> set
classes -> set
permissions -> set
set -> ’*’ | identifier | nested_id_set | ’~’ identifier | ’~’ nested_id_set | identifier ’-’ nested_id_set -> ’{’ nested_id_list ’}’
nested_id_list -> nested_id_element | nested_id_list nested_id_element
nested_id_element -> identifier | ’-’ identifier | nested_id_set
4.2 TE Statements
4.2.1 속성 선언
- 타입속성은 유사한 자원을 가지는 타입들의 구별하는데 쓰이는 이름이다. 타입들은 서로 다른 속성의 이름을 가지고 속성들은 타입의 어떤 번호와 결합할 수 있다. 속성들은 선언된 타입들과 결합 되어지고 다음 부분으로 설명된다. 선언된 타입의 속성은 쓰이기 전에 반드시 명백하게 선언되어야 한다.
- 속성 선언을 위한 구문은 다음과 같다.
attrib_decl -> ATTRIBUTE identifier ';'
예)
attribute domain;
attribute privuser;
attribute privrole;
- 속성이름은 그 속성과 결합되는 타입들의 설정을 표현하는 정책 구성 곳곳에 쓰인다. 속성의 이름은 타입으로써 같은 이름의 공간 내부에 존재한다.
- 그러나 속성이름은 보안적인 문맥의 타입필드에서는 사용할 수 없다. selinux에서 속성은 명백한 의미를 가지지 않는다. 모든 속성들의 의미는 구성 내부에서 그들이 사용됨을 통하여 완전히 정의 되어진다.
4.2.2 타입 선언
- TE 구성 언어는 정의된 모든 타입을 필요로 한다. ... ... 선언된 서로의 타입은 타입을 위한 첫번째 이름 , 타입을 위한 별명의 선택적 설정, 타입을 위한
속성의 선택적 설정을 명세한다. 타입선언을 위한 문맥은 다음과 같다.
type_decl -> TYPE identifier opt_alias_def opt_attr_list ’;’
opt_alias_def -> ALIAS aliases | empty
aliases -> identifier | ’{’ identifier_list ’}’
identifier_list -> identifier | identifier_list identifier
opt_attr_list -> ’,’ attr_list | empty
attr_list -> identifier | attr_list ’,’ identifier
본래 이름과 어떤 별명은 TE 구성내부에 호환성 있게 쓰인다. 실행동안 예들들어 보안서버는 항상 SID(?)를 위해 안정성 문맥을 반환할 때 본래의 이름을 사용하여 식별한다. 그리고 어플리케이션에서는 본래이름과 별명을 같이 사용 할 수 있다. 별명은 타입의 빠른어구형이나 동의어를 위해 제공되지만 보안의 관점에서 보면 중요하지 않다. ...
또한 typealias 와 typeattribute 상태를 사용하여 분리된 추가적인 별명또는 속성을 선언할 수 있다. 이 상태들은 이미 타입으로 선언된 별명과 속성을 추가해 준다.
typealias_decl -> TYPEALIAS identifier ALIAS aliases ’;’
typeattribute_decl -> TYPEATTRIBUTE identifier attr_list ’;’
다음은 Secure shell daemon과 관련된 정책 구성의 예로 부터 몇몇 타입의 선언을 보여준다.
type sshd_t, domain, privuser, privrole, privlog, privowner;
type sshd_exec_t, file_type, exec_type, sysadmfile;
type sshd_tmp_t, file_type, sysadmfile, tmpfile;
type sshd_var_run_t, file_type, sysadmfile, pidfile;
sshd_t 타입은 데몬 프로세스의 도메인이다. sshd_exec_t 타입은 실행가능한 sshd의 타입이다.
sshd_tem_t 와 sshd_var_run_t 타입은 임시파일과 PID파일을 위한 타입들이며 이들은 각각 데몬 프로세스에 의해 생성된다. 이 타입들은 서로 TE구성내부의
규칙에 의해 작성된 속성으로 결합되어 있다.
2.1 타입 실행을 위한 보안 문맥
모든 동작하는 시스템 접근 제어는 객체와 주체이 결합된 속성의 접근제어의 일부 타입에 기초한다. selinux에서 접근제어 속성(대상에 대한 성질)은 보안 문맥이라고 한다. 모든 객체( 파일, interprocess communication channels, 소켓들 네트워크 호스트들,,등등 ) 과 주체( 프로세스 )는 그들끼리 결합된 하나의 보안 문맥을 가진다. 보안 문맥은 3개의 요소인 user(사용자) role(역활) type identifiers(타입 식별자 - 접근 속성이 정의되고 설정되어 있는 타입을 구별하는 이름)을 가지고 보안문맥을 보여주거나 명세하기 위한 일반 포멧은 다음과 같다.
user:role:type
이 각 요소를 위한 일련의 식별자들은 selinux 정책 언어에 의해 정의된다. 이 언어에 대해서 우리는 뒤에 자세히 배울 것이다. 지금은 단지 유효한(쓸수 있는) 보안 문맥은 반드시 하나의 유효한 사용자, 역활, 타입 식별자를 가지고 있어야 한다는 점만 이해하자.
2.2 Type Enforcement Access Control
selinux에서 모든 접근은 반드시 명시적으로 주어져야 한다. selinux에서는 user/group ID들과 상관없이 예외적으로 비접근으로 주어져 있기 때문이다.
그렇다 이말은 selinux에서 일반적인 리눅스의 root와 같은 예외적인 수펴유저가 없다는 것이다. 접근의 방법은 subject( domain ) 타입으로 부터 명세된 접근에 의해 가능하고 object 타입은 allow 규칙에 의해 사용된다.
예를 보자
allow user_t bin_t : file { read execute getattr };
이 예는 한 TE규칙의 기본적인 문법을 보여준다. 이 규칙은 두개의 식별자 source 타입(subject 또는 domain) , target 타입(object)을 가진다. 그리고
식별자 file은 정책에 의해 정의된 object class의 이름이다. permission은 file 객체 클래스의 instance를 위한 유효한 권한의 한 요소를 기반으로 포함되어 있다.
이 규칙의 변환은 다음과 같이 볼 수 있다.
domain type을 가진 프로세스는 bin_t타입을 가진?? file 객체에 대하여 read, execute 또는 속성을 얻을 수 있다.
< selinux의 권한허용은 대체로 오직 rwx의 세 타입을 가진 일반 리눅스보다 더 낱알처럼 되어있다. >
예로 본 type 시행
타입 시행에 대하여 패스워드 관리 프로그램의 예를 들어보자. 리눅스에서 패스워드 프로그램은 암호화된 패스워드가 저장된 shadow 패스워드 파일을 읽고
수정하는 것을 원한다. 패스워드 프로그램은 오직 자신의 패스워드를 바꿀 수 있는 것을 일반 사용자에게 허용하는 내부의 보안 정책을 구현하고 있다.
헥갈리는 의미들...
type enforcement : 주체에게 객체클래스의 권한이 포함된 객체를 실행 할 수 있도록 허용해 주는 것.
trans_transition : 어떠한 주체가 어떤 실행을 하였을 때 기재된 도메인(주체)으로 변환을 해주는 것.
role of rules : 어떠한 사용자에 대하여 일부 권한을 부여해 주는 것 - 설사 user_t타입이 권한에 접근을 허용했을 지라도 해당 user_r의 권한이 허용되지 않았다면 실행 불가.
< define Syntax >
define은 여러 값들을 묶어 놓은 vaule형태와 define함수 형태가 있다.
define함수형은 내부 인자값들을 둘 수 있고 그 인자값에 해당하는 타입에 여러 문법을 적용할 수 있으며
아래와 같이 표현된다.
define(`can_ps',` allow $1 $2:dir { search getattr read }; allow $1 $2:{ file lnk_file } { read getattr }; allow $1 $2:process getattr; # We need to suppress this denial because procps tries to access # /proc/pid/environ and this now triggers a ptrace check in recent kernels # (2.4 and 2.6). Might want to change procps to not do this, or only if # running in a privileged domain. dontaudit $1 $2:process ptrace; ') |
다음 value형태는 classes나 permission들의 묶음을 뜻한다.
#
|
두 define정의가 되어 있다. 하나는 클래스들에 대한 묶음이고 또 하나는 permission에 대한 묶음이다.
여기서는 getattr이라는 하나의 permission만 묶여있지만 여러개를 같이 묶을 수도 있다.
위의 모든 예는 macro/ core_macros.te 파일에 모두 나타나 있다
Policy Information Data Parsing
define 함수에 대한 파싱법은 간단하다. define에 대한 정의문이 먼저 나오기 때문에 define함수를 먼저 찾으면
된다. 하지만 그 define문이 함수 형태인지..아니면 value 거기다...classes의 묶음인지..permission의 묶음인지
를 구분하기가 애매했다.
그래서 먼저 인자값을 받는 의미인 $표시를 가진 것을 기준으로 define함수와 define value를 구분하였다.
그 다음 classes와 permission을 구분하기 위하여 define명을 참조하면 간단하겠지만..그건 말도 안되는
방법이고 가장 좋은 방법은 내부 묶여져 있는 속성들을 검사하는 것이다.
클래스와 내부 permission에 대한 정의는 ..\policy\based_policy\access_vectors파일에 나타나 있다.
뒤에서 설명할 class와 permission에 대한 정보 파일을 이용하여 해당 묶인 값이 permission에 해당하는지
아니면 class에 해당 하는지 조사해 보면 된다. 나는 permission을 기준으로 검사하였다..
많은 검색이 이루어 지기 때문에 속도가 다소 느린점이 있는데...commnet정보까지 파싱한다면
과연 노다가임에 틀림없다..ㅡ,.ㅡ
커널과 cygwin과의 의존성
windows 환경에서의 정책 컴파일을 위한 방법으로 처음에 cygwin을 선택했다.
그러나 cygwin은 환경설정이 너무 많고 또한 selinux관련 lib를 설치함에 있어
cygwin내에는 원래 존재하지 않는 커널과의 의존성을 가지고 있었다.
별로 상관없을꺼 같은 커널내의 함수와 여러 매크로와의 충돌이 많았고
이것들을 다 잡다가는 배보다 배꼽이 더 큰 격이 될 듯했다.
결국 PL은 cygwin을 포기하고 다른 방법을 모색했다 .
VM나 virtual PC를 이용한 방법이다.
서버와 클라이언트 구축
VM와 Virtual PC상에서 컴파일을 시행하기 위해서 linux쪽에 서버를 작성하고
windows 프로그램쪽에 클라이언트을 작성하였다.
클라이언트측에서 정책에 대한 파일을 묶어 보내주면
그걸 받은 linux서버측에서 정책 컴파일을 수행한 후 생성된 정책 이미지와 contexts파일을
다시 클라이언트측으로 전송시켜 주는 것이다.
virtual PC에서의 환경 구축
- 좀 더 좋은 환경에서 작업하기 위하여 SSH 터미널을 이용하였다.
- 방화벽에 대한 문제가 있을 수 있으므로 주의 하도록 하자.
- ->방화벽 설정
- -> .....> lokkit (입력)
- -> Customize (선택)
- -> Trusted Devices: [*] eth0 (체크!!)
-
2. -> IP주소 변경 - 사용할 IP주소를 변경하자.
- -> etc/sysconfig/network-scripts/ifcfg-eth0 파일 수정
- -> HWADDR 부분 수정
3. aceept함수에서의 형변환에러 주의
- client_socket = accept( server_socket, (struct sockaddr*)&client_add, (socklen_t*)&client_addlen );
-> (socklen_t*) :C++에서는 명시적 형변환을 해야함
4. SSH터미널 설정이나 다른 세부사항은 동영상 참조. (동영상은 지환한테 있습니다.ㅎㅎㅎ)
SSL서버에서의 window와 linux의 차이점
SSL서버를 구축할 때 기본적으로 쓰이는 소켓생성이나 다른여러 함수는 각 환경에 따라 동일하게 쓰인다.
한가지는 Windows에서 사용했던 Win32OpenSSL_0.9.8e버젼에서는
#include "ssl/applink.c"에 대한 참조를 하였지만 내가 하는 리눅스 환경에서는 필요가 없었다.
아마 리눅스에서 쓰인 openssl 버젼이나 환경에 따라 차이점때문에 그런것이겠지만
기본적으로 알고 있으면 삽집하는 일이 없을 것이다.
컴파일 실행
-> ....> export LANG=euc_kr - 에러 소스에 대해 깨질 때 쓰자.
-> ....> g++ -lssl -o Server_SSL Server_SSL.c
SSL서버와 파일 송수신 소스 참조
Linux상의 SSL서버 |
1 #include <stdio.h> 49 char * serverAddress = SERVER_ADDRESS; |
windows에서의 클라이언트 (TransFileClass : 파일전송 클래스 - linux서버의 파일전송소스와 동일) |
char* server_name= "210.118.75.59"; int socket_type = SOCK_STREAM; // SSL 구조체 생성 BIO * errBIO; m_List_FlowSystem.AddString("인증서버에 연결을 시작합니다."); // 파일 전송 플러그 if ((retval = WSAStartup(0x202,&wsaData)) != 0) SSL_load_error_strings(); meth = SSLv3_method(); server_add.sin_family = AF_INET; conn_socket = socket(AF_INET,socket_type,0); if ( connect( conn_socket,(struct sockaddr*)&server_add,sizeof(server_add) )== SOCKET_ERROR ) ssl = SSL_new( ctx ); // 주체의 DN을 문자열로 얻음 // 발급자의 DN을 문자열로 얻음 X509_free (server_cert); ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // 전송할 파일의 크기를 구함. int TotalFielSize = TransFileClass.Get_SendListFileSize( "comsetup.log" ); ret_data = TransFileClass.SendFile( 0, ssl, "comsetup.log", TotalFielSize ); ////////////////////////////////////////////////////////////////////////// // 파일 이름 받기 retval = TransFileClass.recvn(ssl, filename, 256, 0, (SOCKADDR*) &server_add, &addrlen); // 파일 수신 m_List_FlowSystem.AddString("정책서버 -> 컴파일 서버로의 연결 해제"); closesocket(conn_socket); WSACleanup(); m_List_FlowSystem.AddString( "연결종료 "); |
windows에서의 ssl서버 ( 위의 windows서버와 동작 가능 ) |
Server_SSL.zip |
정규표현식 기초
저자 전정호 (mahajjh@myscan.org)
0.1 판 (2001년 11월 20일)
--------------------------------------------------------------------------------------------
Copyright (c) 2001 Jeon, Jeongho.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
--------------------------------------------------------------------------------------------
이 글은 유닉스 사용과 관리에 필수인 정규표현식을 설명합니다. 또, 정규표현식을 처리하는 C 라이브러리도 마지막에 설명합니다.
1. 정규표현식이란?
아마 MS-DOS를 접해본 분이라면 와일드카드(wildcard, 유닉스에서는 glob pattern이라고 부른다)이라고 부르는 *나 ?와 같은 기호에 익숙할 겁니다. a로 시작하는 모든 GIF 파일을 a*.gif와 같이 비슷한 파일명을 일일이 명시하지 않고 지정할 수 있습니다. 정규표현식(regular express, 줄여서 regexp, regex, re)도 MS-DOS의 *나 ?와 같이 패턴을 기술하는 방식입니다. 그러나 정규표현식은 MS-DOS의 와일드카드와는 달리 파일명 뿐만이 아니라 파일 내용을 포함한 일반적인 용도로 사용이 가능하며, 그 기능도 더 강력합니다.
유닉스는 기본적으로 그래픽보다는 문자 기반 인터페이스를 제공하기 때문에, 문자들을 찾거나 다른 문자로 대체하는 도구인 정규표현식은 매우 중요합니다. 사실, 정규표현식을 모르고 유닉스를 사용하는 것이 가능할까란 의문이 들 정도로 정규표현식은 유닉스 사용과 관리의 많은 부분에 적용이 가능합니다. 우리가 자주 사용하는 편집기인 vi와 emacs, 자주 사용하는 도구인 grep과 sed와 awk, portable shell로 불리는 Perl, 자동으로 메일을 정리하는 procmail 등, 정규표현식은 유닉스의 거의 모든 도구와 관련이 있습니다. 개인적으로 뼈아픈 경험뒤에 "멍청하면 손발이 고생한다"는 격언(?)의 적절한 예로 정규표현식을 꼽습니다.
불행히도 도구마다 정규표현식을 지원하는 정도가 조금 차이가 나지만 몇번 시도해보면 이 차이를 알 수 있습니다. 그러면 기본적이고 광범위하게 쓰이는 정규표현식부터 하나씩 알아봅시다.
2. 정규표현식 기초
기본적으로 정규표현식은 다음 세가지로 구별할 수 있습니다.
문자에 해당되는 부분
앞의 해당되는 부분을 반복하는 부분
문자에 해당되지않고 위치나 결합을 나타내는 부분
이제 MS-DOS의 *와 같이 특수한 의미를 가지는 문자들을 만나게 됩니다. 우리가 정규표현식을 배운다는 것은 이런 특수 문자들과 그들의 의미를 아는 것입니다.
2.1. 문자에 해당되는 부분
우선 보통 알파벳과 숫자 등은 그 문자 그대로를 나타냅니다. 물론 대소문자는 서로 구별됩니다.
$ egrep 'GNU' COPYING
GNU GENERAL PUBLIC LICENSE
freedom to share and change it. By contrast, the GNU General Public
the GNU Library General Public License instead.) You can apply it to
...(생략)...
$
위에서 egrep은 파일들에서 원하는 문자들을 찾는 도구입니다. (흔히들 사용하는 grep의 변종으로 grep보다 다양한 정규표현식을 사용할 수 있습니다.) 첫번째 아규먼트로 원하는 문자를 나타내는 정규표현식을 사용합니다. 여기서 GNU는 정규표현식으로 뒤에 나오는 파일들에서 G, N, U 세 문자가 연이어 나오는 경우를 찾습니다. 여기서 사용한 파일인 COPYING은 자유 소프트웨어 소스코드에서 쉽게 찾을 수 있는 GPL 조항입니다. 결과를 명확하게 하기 위해서 찾은 단어를 굵게 표시했습니다.
그런데 왜 GNU 주위에 따옴표를 했을까요? 여기서 따옴표는 정규표현식에서 쓰이는 *, ?, | 등의 문자들이 쉘에서도 특별한 기능을 하기때문에 이들 문자가 쉘에서 처리되지 않게하려고 필요합니다. 또, egrep 'modified work' COPYING와 같이 찾으려는 패턴에 공백이 포함된 경우에도 따옴표는 이들을 한개의 아규먼트로 처리합니다. 사실 위의 GNU에 따옴표는 필요없지만, 항상 규칙처럼 따옴표를 같이 사용하는 것을 권합니다.
어떤 특정한 문자가 아니라 가능한 여러 문자들을 지정할 수도 있습니다.
$ egrep '[Tt]he' COPYING
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
software--to make sure the software is free for all its users. This
...(생략)...
$
위에서 [Tt]는 그 자리에 T나 t가 나올 수 있음을 의미합니다. 이렇게 [와 ]안에 가능한 문자들을 적어줄 수 있습니다.
[a-z]와 같이 [] 안에 -를 사용하여 그 범위 안의 문자들도 지정할 수 있습니다. 예를 들어, [a-zA-Z0-9]는 영문 알파벳 대소문자와 숫자들을 모두 포함합니다. 또, [^a-z]와 같이 [] 처음에 ^를 사용하여 뒤에서 지정된 문자 이외의 문자를 지시할 수도 있습니다. 즉, 이는 영문 알파벳 소문자를 제외한 문자들을 의미합니다.
([a-z]에서 범위는 ASCII 코드값으로 a (97)에서 z (122)까지를 뜻합니다. 만약 [z-a]와 같이 큰 값을 앞에 쓰면 안됩니다. ASCII 코드값은 man ascii로 볼 수 있습니다.)
마지막으로 (보통 행바꿈 문자를 제외한) 어떤 문자에도 대응되는 .이 있습니다. (MS-DOS의 ?와 같습니다.)
$ egrep 'th..' COPYING
of this license document, but changing it is not allowed.
freedom to share and change it. By contrast, the GNU General Public
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
...(생략)...
$
이는 th 뒤에 두 문자가 나오는 경우를 찾습니다. 세번째 줄 끝에 This는 대소문자를 구별하기 때문에 패턴에 해당되지않고, the 에서 공백도 한 문자로 취급한 것을 주의하길 바랍니다. 위에서 program will individually obtain patent licenses, in effect making the와 같은 줄을 출력하지 않은 이유는 마지막 the에서 th와 그 뒤의 한 문자는 찾았지만 그 뒤에 문자가 줄바꿈 문자이기 때문에 조건이 만족되지않기 때문입니다.
2.2. 앞의 해당되는 부분을 반복하는 부분
여기서는 *, ?, +을 다룹니다.
*는 바로 앞의 문자를 0번 이상 반복해도 됨을 나타냅니다. 예를 들어, abc*는
abccccccccc
abc
ab
를 모두 만족합니다. 여기서 주의해서 볼 것은 "0번 이상"이기 때문에 마지막 경우와 같이 앞의 문자가 안나와도 된다는 것입니다. (그래서 MS-DOS의 *은 정규표현식으로 .*입니다.)
*와 비슷하게, ?는 앞의 문자가 없거나 하나 있는 경우를 나타내고, +는 앞의 문자가 1번 이상 반복하는 경우를 나타냅니다. 그래서 a+는 aa*와 같습니다.
이제 abc 모두를 반복하고 싶다면 어떻게 해야 되는지 의문이 듭니다. 이 경우 (, ) 괄호를 사용하여 문자들을 묶어주면 됩니다. 그래서 (abc)*는
abcabcabcabc
abc
를 모두 만족합니다. 마지막 예는 0번 반복한 경우로 어떤 문자도 없는 빈 경우입니다. 이제 앞에서 말한 "앞의 문자"라는 말을 정정해야 겠습니다. *, ?, +는 "앞의 문자"에 적용되는 것이 아니라 "앞의 단위"에 적용됩니다. 기본적으로 한 문자는 그 자체로 한 단위입니다. 그래서 abc*에서 *는 바로 앞 문자이자 단위인 c에 적용된 것입니다. 그러나 괄호로 문자들을 묶어서 단위를 만들 수 있고, (abc)*의 경우에 *는 앞의 단위인 abc에 적용된 것입니다.
주의
--------------------------------------------------------------------------------------------
위에서 (abc)*가 0번 반복해서 어떤 문자도 없는 것을 나타낼 수 있음을 주의해야 합니다. 정규표현식에서 이런 경우 대상과 관계없이 패턴이 만족한 것으로 판단하기 때문에 egrep '(abc)*' COPYING와 같은 명령어는 COPYING에 abc라는 부분이 없음에도 불구하고 모든 줄을 출력합니다. 즉, egrep '(abc)*' COPYING | wc -l과 wc -l COPYING은 같습니다.
또, 주의할 점은 정규표현식은 패턴을 만족시키는 가장 긴 부분을 찾는다는 점입니다. 즉, abababab에 대한 정규표현식 (ab)+는 ab나 abab에 대응되지 않고 abababab 모두에 대응됩니다. 이런 행동은 어떻게보면 당연한 것이지만 주의를 하지않으면 문제가 생길 수도 있습니다. 예를 들어, <B>compiler</B> and <B>interpreter<\B>에 대한 정규표현식 <B>.*<\B>는 (의도했을) <B>compiler</B>을 찾지않고 <B>compiler</B> and <B>interpreter<\B> 전체를 찾게 됩니다. 이를 해결하기 위해 <B>[^<]*<\B>을 사용합니다. . 대신에 [^<]를 사용한 것처럼 찾는 대상을 제한하기 위해서 [^...] 형식을 자주 사용합니다.
--------------------------------------------------------------------------------------------
2.3. 문자에 해당되지않고 위치나 결합을 나타내는 부분
여기서 다루는 ^, $, |는 앞에서와는 달리 특정 문자에 대응하지는 않지만, 위치나 결합의 중요한 기능을 합니다.
우선 ^는 줄의 처음을 뜻합니다.
$ egrep '^[Tt]he ' COPYING
the GNU Library General Public License instead.) You can apply it to
the term "modification".) Each licensee is addressed as "you".
the scope of this License.
The source code for a work means the preferred form of the work for
...(생략)...
$
정규표현식의 마지막 문자가 공백임을 주의하길 바랍니다. 만약 이 공백이 없다면 These나 themselves,로 시작하는 줄들도 찾게됩니다. 이렇듯 정규표현식을 적을 때는 자신이 찾길 원하는 부분을 빼먹거나, 자신이 원하는 부분 이외의 것을 포함하지 않도록 주의해야 합니다. 지금처럼 정규표현식을 입력하고 그 결과를 하나씩 살펴볼때는 문제가 없지만, 많은 경우 정규표현식은 스크립트로 많은 문서를 한꺼번에 처리할때 사용하기때문에 주의해야 합니다. 잘못 쓴 정규표현식때문에 원하는 결과를 얻지 못하는 것은 물론이고 원본까지 망치게 되는 경우가 있습니다.
^는 이렇게 [Tt]와 같이 특정 문자에 대응되지는 않지만 원하는 문자가 선택될 수 있게 도와줍니다. 반대로, $는 줄의 끝을 나타냅니다. 그래서 ^$과 같은 정규표현식은 빈 줄을 찾습니다.
|은 기호 앞뒤의 것 중 하나를 선택한다는 뜻입니다. 즉, 문서에서 this(This)나 that(That)을 찾는다면,
this|This|that|That
[tT]his|[tT]hat
[tT]his|hat - 틀림! 이 정규표현식은 [tT]his나 hat을 찾음.
[tT](his|hat)
[tT]h(is|at)
모두 가능합니다. 세번째와 네번째 경우에서 괄호의 기능을 알 수 있습니다.
2.4. 일반문자와 특수문자
아마도 지금쯤 ^이 두가지 의미로 쓰인다는 것이 이상해 보일 수도 있을 겁니다. 정규표현식에서 쓰이는 문자는 크게 일반문자와 특수문자로 나눠볼 수 있습니다. 여기서 특수문자란 앞에서 다룬 (순서대로) [, ], -, ^, ., *, ?, +, (, ), $, |과 같이 정규표현식에서 문자그대로의 의미로 해석되지 않는 문자들입니다. 반대로 특수문자가 아닌 문자는 일반문자로 G, N, U와 같이 문자그대로의 의미를 가집니다.
여기서 특수문자는 쓰이는 곳에 따라 다릅니다. 자세히 말하면, []안이냐 밖이냐에 따라 특수문자가 달라집니다.
우선 [] 밖에서는 -를 제외한, ^, ., *, ?, +, (, ), $, |이 특수문자입니다. 여기서 ^는 줄의 시작을 의미합니다.
그러나 [] 안에서는 -과 ^만이 특수문자이고, 다른 문자들은 일반문자가 됩니다. 즉, [*?+]는 반복이 아니라 문자그대로 *나 ?나 + 중 하나를 뜻합니다. [] 안에서 (제일 앞에 나오는) ^는 뒤에나오는 조건을 만족하지 않는 문자를 찾는다는 의미가 됩니다.
2.5. 특수문자에 해당하는 문자 사용하기
그렇다면 찾으려는 부분에 특수문자가 포함되있다면 어떻게 할까요? 예를 들어 what?이라는 물음표로 끝나는 문자를 찾고 싶다고, egrep 'what?' ...이라고 하면 ?이 특수문자이므로 wha를 포함한 whale도 찾게 됩니다. 또, 3.14로 찾을때는 3+14 등도 찾게 됩니다.
특수문자가 [] 안과 밖에서 다르다는 점을 생각하여 각각의 경우를 살펴봅시다. 우선 [] 밖의 경우는,
\을 특수문자 앞에 붙이기. 예, what\?, 3\.14
[]을 사용하기. 예, what[?], 3[.]14
첫번째 방법은 보통 escape라고 부르며, 특수문자 앞에 \을 붙여서 특수문자의 특수한 기능을 제거합니다. 두번째 방법은 [] 밖의 많은 특수문자들이 [] 안에서는 일반문자가 되는 점을 이용한 것입니다. 보통 첫번째 방법을 많이 사용합니다.
주의할 점은 첫번째 방법에서 사용하는 \가 뒤에 나오는 특수문자를 일반문자로 만드는 특수문자이기 때문에, 문자 그대로의 \을 나타내려면 \\을 사용해야 합니다. 물론 [\]도 가능합니다.
[] 안의 특수문자는 위치를 바꿔서 처리합니다. 먼저, ^는 [^abc]와 같이 처음에 나와야만 의미가 있으므로 [abc^]와 같이 다른 위치에 사용하면 됩니다. -는 [a-z]와 같이 두 문자 사이에서만 의미가 있으므로 [-abc]나 [abc-]와 같이 제일 처음이나 마지막에 사용합니다.
(grep과 같이 도구에 따라 역으로 일반 문자앞에 \를 붙여서 특수문자를 만드는 경우가 있습니다. 아래 각 도구에 대한 설명 참고.)
3. 정규표현식 고급
고급이라고 제목을 붙였지만 여기서는 도구마다 차이가 나거나 없을 수도 있는 내용을 다룹니다.
3.1. 자세한 반복
반복하는 횟수를 자세히 조정할 수 있습니다.
{n} - 정확히 n번 반복. a{3}은 aaa와 같음.
{n,} - n번 이상 반복. a{3,}은 aaaa*와 같음.
{n,m} - n번 이상 m번 이하 반복. a{2,4}는 aaa?a?와 같음.
물론 (abc){2,4}같이 괄호로 반복할 단위를 지정할 수 있습니다. 여기서 {, }도 *, ?, +와 같이 특수문자임을 주의하길 바랍니다. (엄밀한 의미에서 }은 특수문자가 아닙니다.)
3.2. 기억하기
앞에서 여러 문자를 묶어서 단위로 만드는 괄호는 정규표현식으로 찾은 부분을 기억하여 다른 곳에서 사용할때도 사용합니다. 예를 들어, HTML 제목 테그는 (egrep에서) <[Hh]([1-6])>.*</[Hh]\1>와 같이 찾을 수 있습니다. 여기서 ([1-6])의 (, )는 사이에 대응된 부분을 기억하여 (첫번째 기억된 내용을) \1에서 사용합니다. 즉, <H2>Conclusion</H2>에서 </H2> 외에 </H1>나 </H3> 등은 만족하지 않습니다.
(...)은 여러번 사용할 수 있고 (심지어 겹쳐서도), \n은 기억된 n번째 부분을 지칭합니다. 순서는 기억이 시작되는 (의 순서입니다.
여기에서는 (과 )이 특수문자이고, 그냥 \(와 \)는 일반문자이지만, 도구에 따라 반대인 경우도 있습니다.
이 기능은 또 치환에서 자주 사용됩니다. 아래 vi와 sed 부분을 참고하길 바랍니다.
3.3. 단어 찾기
앞에서 the를 찾으면 the 외에 them 등도 같이 찾는 것을 보았습니다. 그러면 정관사 the만 찾으려면 어떻게 할까요?
간단히 정규표현식 앞뒤에 공백을 추가한 the 를 생각해 볼 수 있습니다. 그러나 이 정규표현식에는 두가지 문제가 있습니다. 첫번째는 탭(tab) 등 다른 공백문자가 있기 때문입니다. 두번째는 이 정규표현식으로 the가 줄 제일 앞이나 제일 뒤에 나오는 경우는 찾지 못하기 때문입니다. 물론 [], ^, $와 |를 복잡하게 결합하여 이들 경우를 모두 처리할 수 있는 정규표현식을 쓸 수 있지만, 자주 사용하는 표현이기 때문에 간단히 할 수 있는 방법이 마련되있습니다.
그것은 \<과 \>로, \<은 공백에서 공백이 아닌 문자 사이, \>는 공백이 아닌 문자에서 공백 사이의 위치를 나타냅니다. 즉, ^나 $와 같이 문자에 해당되지않고 위치만을 나타냅니다. 이제 해답은 \<the\>입니다.
3.4. 단축 표현들
정규표현식에는 이외에도 자주 사용되는 표현에 대한 단축된 형식을 제공합니다. 예를 들어, vim에서 \i는 (C 언어 인식자 이름에서 사용하는 문자인) [_a-zA-Z0-9]와 같습니다. 그러나 이런 단축된 형식은 도구에 따라 많은 차이가 나기때문에 관련 문서를 참고하길 바랍니다.
POSIX.2에서 정의한 단축 표현은 다음과 같습니다. (C 언어에서 <ctype.h>에 선언된 is*() 함수와 비슷한 것을 알 수 있습니다.) 단축된 형식이 나타내는 정확한 값은 locale에 따라 변합니다. 여기서는 영어권에서 사용하는 값을 보입니다. 독일어의 움라우트(ä)와 같이 다른 언어권에서는 다른 값을 가질 수 있습니다.
[:alnum:] - 알파벳과 숫자. [a-zA-Z0-9]
[:alpha:] - 알파벳. [a-zA-Z]
[:cntrl:] - 제어문자. ASCII 값으로 0x00-0x1F와 0x7F
[:digit:] - 숫자. [0-9]
[:graph:] - 제어문자와 공백을 제외한 문자. ASCII 값으로 0x21-0x7E
[:lower:] - 소문자. [a-z]
[:print:] - 제어문자를 제외한 문자. ASCII 값으로 0x20-0x7E
[:punct:] - [:graph:] 중에 [:alnum:]에 속하지 않은 문자. !, @, #, :, , 등
[:space:] - space, tab, carriage return, new line, vertical tab, formfeed. ASCII 값으로 0x09-x0D와 0x20
[:upper:] - 대문자. [A-Z]
[:xdigit:] - 16진수에 사용하는 문자. [0-9a-fA-F]
3.5. 눈으로 보는 정규표현식
정규표현식이 패턴을 찾는 과정을 시각적으로 보여주는 프로그램들이 있습니다.
Visual REGEXP(Tcl/Tk 사용)
RegExplorer(Qt 사용)
4. 정규표현식 사용
이제 이런 정규표현식을 실제로 어떻게 사용하는지 알아봅시다. 평소에 많이 사용하는 vi, grep/egrep/fgrep, sed/awk의 예를 들어보겠습니다.
4.1. vi에서
vi에서 정규표현식은 ':'상태에서 사용합니다. (실제로 이 상태에서 실행하는 명령어는 ed나 ex라는 프로그램이 처리하게 됩니다. 그래서 보통 이 상태를 "ed-모드"라고 합니다.) 문서에서 원하는 패턴을 찾으려면, (커서 다음에서 찾을때) /패턴이나 (커서 전에서 찾을때) ?패턴을 사용합니다.
정규표현식은 문자치환과 결합하여 강력한 기능을 합니다. 문자치환 명령은 다음과 같습니다.
:범위s/변경전/변경후/수정자
"범위"는 명령이 실행될 범위를 나타내며, 보통은 현재 편집하고 있는 문서 전체를 지시하는 (첫번째 줄에서 마지막 줄까지를 뜻하는) 1,$나 줄여서 %를 사용합니다.
뒤에 "s"는 치환(substitute) 명령어입니다.
"변경전"과 "변경후"에 치환할 내용을 입력합니다. "변경전"에 정규표현식을 적습니다. 정규표현식으로 ., *, ^, $, [], \(...\), \<...\>, POSIX.2 단축 표현을 사용할 수 있습니다. 여기서 여러 문자를 묶여서 단위를 만들고 찾은 내용을 기억하는 특수문자가 \(, \)임을 주의해야 합니다. 반대로 (, )가 일반문자입니다. vim(VI iMproved)에서는 vi에 추가로 |, +, (?와 같은) =, {n,m}을 사용할 수 있지만, 앞에 \를 붙여야 합니다. 또, vim에는 \i, \k, \p, \s 등의 단축 표현들이 있습니다.
"변경후"에 \n과 &를 사용할 수 있습니다. \n는 "변경전"에서 n번째 \(...\)에 대응하는 부분이고, &는 "변경전"에 만족한 전체를 나타냅니다. 예를 들어, :%s/\([0-9][0-9]*\) \([Cc]hapter\)/\2 \1/는 문서에서 12 Chapter같은 부분을 Chapter 12와 같이 치환하고, :%s/F[1-9][12]*/&/g는 HTML 문서에서 "F1" ~ "F12"란 단어 모두를 굵은 체로 바꿉니다. (주의! &는 정규표현식의 특수문자는 아니지만 vi의 특수문자이므로, 문자그대로의 &를 사용하려면 대신 \&를 사용해야 한다.) 이외에도 (뒤를 모두 대문자로) \u나 (뒤를 모두 소문자로) \l같은 기능이 있습니다.
"수정자"는 치환 명령의 세부사항을 결정합니다. 필요한 것만 뒤에 적어주면 됩니다.
g (global) - 한 줄에서 정규표현식을 만족하는 부분을 여러개 찾았을 때 모두다 치환한다. 이 수정자를 사용하지 않으면 처음 것만 치환한다.
c (confirm) - 만족하는 정규표현식을 찾았을때 치환하기 전에 확인한다.
i (ignore-case) - 대소문자를 무시하고 찾는다. 즉, :%s/[aA][bB][cC]/XXX/ 대신에 :%s/abc/XXX/i를 사용할 수 있다.
마지막으로 주의할 점은 치환명령어가 / 문자로 각 부분을 구분하기때문에 "변경전"이나 "변경후"에 / 문자를 사용하려면 \/ 같이 써야합니다. 필요하다면 / 대신 다른 문자를 사용해도 됩니다. 예를 들어, :%s/\/usr\/local\/bin\//\/usr\/bin\//g 대신 :%s#/usr/local/bin/#/usr/bin/#g가 알아보기 더 쉽습니다.
4.2. grep/egrep/fgrep에서
grep은 Global Regular Expression Print(ed 명령어로 :g/re/p)의 준말로 입력에서 원하는 정규표현식을 찾는 명령어입니다. grep에는 egrep과 fgrep이라는 변종이 있습니다. 전통적으로 egrep은 grep 보다 더 다양한 정규표현식을 지원하고, fgrep은 정규표현식을 지원하지 않고 빨리 검색하기 위한 명령어입니다. GNU grep에서 egrep은 grep -E, fgrep은 grep -F와 같습니다.
grep과 egrep 모두 ., *, ?, +, {n,m}, ^, $, |, [], (...), \n, \<...\>, POSIX.2 단축 표현을 지원합니다. 단, grep은 ?, +, {, |, (, )를 일반문자로 보기때문에 특수문자로 사용하려면 앞에 \를 붙여야 합니다.
4.3. sed/awk에서
...
5. Perl 정규표현식
...
6. 정규표현식 응용
7. 정규표현식 프로그래밍
프로그래밍 언어와 관계없이 정규표현식을 프로그래밍하는 방식은 비슷하다. 먼저, 사용할 정규표현식을 "컴파일"한다. 여기서 컴파일한다는 말은 정규표현식을 실행파일로 만든다는 말이 아니라 정규표현식을 처리하기위한 내부 자료구조를 만든다는 뜻이다. 이 자료구조를 사용하여 정규표현식을 빠르게 처리할 수 있다. 컴파일한 후 컴파일된 자료구조를 사용하여 원하는 검색과 치환을 하게된다. 마지막으로 사용이 끝난 자료구조를 반환한다. 프로그래밍 언어에 따라 이 과정이 필요없는 경우도 있다.
7.1. C 언어
glibc(GNU C Library)에 정규표현식을 위한 다음과 같은 함수들이 있다.
#include <regex.h>
int regcomp(regex_t *compiled, const char *pattern, int cflags);
int regexec(regex_t *compiled, char *string, size_t nmatch, regmatch_t matchptr[], int eflags);
void regfree(regex_t *compiled);
size_t regerror(int errcode, regex_t *compiled, char *buffer, size_t length);
먼저 함수와 자료형이 선언된 regex.h를 포함한다. regcomp()는 pattern에 주어진 정규표현식을 컴파일하여 결과를 compiled에 저장한다. cflags 인자는 정규표현식 처리 옵션들을 지정한다. 정상적으로 실행되면 0을 반환하고, 오류가 발생한 경우 0이 아닌 값을 반환한다.
[표 1] cflags 인자
REG_EXTENDED
REG_ICASE : 대소문자 구별안함
REG_NOSUB : 괄호로 찾은 부분 영역 기억하지 않기
REG_NEWLINE : 여러 줄을 처리. 이 옵션이 없다면 .에 행바꿈 문자가 포함되고, (사이에 행바꿈 문자가 있더라도) ^과 $는 찾으려는 문자열의 시작과 끝만을 의미한다.
실제 정규표현식 검색은 regexec()으로 한다. string에 정규표현식으로 검색할 문자열을 주면 ...
http://www.onjava.com/pub/a/onjava/2003/11/26/regex.html참고
7.2. Java
7.3. Python
7.4. PHP
참고 자료
grep(1), regex(3), regex(7), fnmatch(3) manpage
GNU C Library 문서
Learning the vi Editor, 6th ed, Linda Lamb, O'Reilly, 1998
sed & awk, 2nd ed, Dale Dougherty & Arnold Robbins, O'Reilly, 1997