LDAP Standard API

LDAP Seminar <2>for Initech
권용철(godslord@sparcs.kaist.ac.kr)1998

1. LDAP Standard API

LDAP 자체는 Client/Server 구조를 기본으로 한다.
그리고, LDAP를 이용한 Client Software를 제작하기 용이하도록
University of Michigan의 LDAP 패키지에는 SLAPD, SLURPD와 함께
Standard LDAP API가 제공된다. 이 외에도 Netscape사에서 역시 C용,
JAVA용 LDAP SDK를 개발하요 무료로 배포하고 있다.

먼저, 미시간 대학의 표준 API에 대해서 살펴 보도록 하겠다.

1.1. Michigan Standard API
Michigan Standard API는 미시간 대학에서 배포하는 LDAP패키지에 포함
되어 있으며, LDAP v2 Spec을 완벽히 지원한다. 컴파일시 Header에러가
난다면, ldap.h의 첫 부분 적당한 곳에 #include <lber.h>를 첨가하기
바란다. 링크할 라이브러리들은 "ldap"와 "lber"이다.

Michigan API를 사용해서 프로그램을 짜는 순서는 크게 4단계이다.

* LDAP 서버와의 커넥션을 연다(한번에 여러개의 커넥션을 열 수
있다.(ldap_open())
* LDAP 서버나, X.500 DSA에 Authentication을 한다.
Standard API에서는 Kerberos, Simple Authentication을 지원한다.
(ldap_bind())
* LDAP 서버에 Request를 보내고(ldap_search(),ldap_modify(),
ldap_modrdn(),ldap_add(),ldap_delete()), 결과를 받는다. 결과는
ldap_result2error(), ldap_first_entry(), ldap_next_entry()등의
함수로 파싱이 가능하다.
* 볼 일이 끝 났으면 커넥션을 닫는다.(ldap_unbind())

위에서 각각 설명한 절차에 따라 프로그램을 작성하면 되며, 각각의 함수들
중 synchronous함수들은 함수의 이름 뒤에 "_s"의 접미사가 붙게된다.
(Ex : ldap_search(), ldap_search_s())
Synchronous함수들은 Operation의 수행 결과를 나타내는 상수를 리턴한다.
(Ex : LDAP_SUCCESS, or etc...)
Asynchronous함수들은 각 Operation에 할당된 고유의 Msg ID를 리턴하게
된다. 이 Msg ID를 이용해서, ldap_result()를 통해 해당 Operation의 수행
결과를 알 수 있다. Asynchronous로 수행된 Operation은 ldap_abandon()을
호출하여 서버측에 실행 취소를 요구할 수 있다.

Standard API에서 호출하는 모든 함수들에는 LDAP 서버와의 커넥션 핸들이
인자로 포함되고 있다. 버리지 말고 잘 쓰도록 하자...--;

1.2. API Reference

1.2.1. 커넥션 열기


typedef struct ldap {
/* ... opaque parameters ... */
int ld_deref;
int ld_timelimit;
int ld_sizelimit;
int ld_errno;
char *ld_matched;
char *ld_error;
/* ... opaque parameters ... */
} LDAP;

LDAP *ldap_open( char *hostname, int portno );

위에서 보인 구조체는 LDAP 커넥션 핸들이다. 커넥션 핸들에는 앞으로
수행될 여러 Operation에 공통적으로 적용되는 정보들이 포함되어
있다.

ldap_open의 Arguments :
* hostname
Human Readerble Hostname(Ex: sparcs.kaist.ac.kr)이나 IP
Address(Ex: 143.248.8.2)들이 올 수 있다. 여러개의 name을
같이 적어 줄 수도 있다. 이때 각 hostname의 구분은 `,'로
하게 되며, 열거된 순서로 접속을 시도한다.
* portno
LDAP 서버의 TCP 포트 번호를 적어주면 된다.

1.2.2. Authentication

int ldap_bind( LDAP *ld, char *dn, char *cred, int method );
int ldap_bind_s( LDAP *ld, char *dn, char *cred, int method );
int ldap_simple_bind( LDAP *ld, char *dn, char *passwd );
int ldap_simple_bind_s( LDAP *ld, char *dn, char *passwd );
int ldap_kerberos_bind( LDAP *ld, char *dn );
int ldap_kerberos_bind_s( LDAP *ld, char *dn );

ldap_bind의 Arguments :
* ld
ldap_open에서 넘겨받은 커넥션 핸들
* dn
Binding할 DN을 지정한다.
* cred
각각의 Athentication에 필요한 정보가 들어간다.
* method
LDAP_AUTH_SIMPLE, LDAP_AUTH_KRBV41, LDAP_AUTH_KRBV42 중의
하나의 값을 가지며, Binding 방식을 지정한다.
* passwd
ldap_simple_bind() 함수에서 사용하며, 이것을 사용하면
Entry의 userPassword속성의 값과 비교하여 Binding한다.
(이 필드와 dn필드가 NULL로 지정되면, Anonymous로
Authentication하게 된다)

1.2.3. 커넥션 닫기

int ldap_unbind( LDAP *ld );

커넥션을 닫을 때 불러준다. 이 함수는 Asynchronous 버젼이 없다.

ldap_unbind의 Arguments :
* ld
ldap_open에서 넘겨받은 커넥션 핸들

1.2.4. 검색

struct timeval {
long tv_sec;
long tv_usec;
};

int ldap_search(LDAP *ld,char *base,int scope,char *filter,char *attrs[],int attrsonly);
int ldap_search_s(LDAP *ld,char *base,int scope,char *filter,char *attrs[],int attrsonly,LDAPMessage **res);
int ldap_search_st(LDAP *ld,char *base,int scope,char *filter,char *attrs[],int attrsonly,struct timeval timeout,LDAPMessage **res);

ldap_search의 Arguments :
* ld
ldap_open에서 넘겨받은 커넥션 핸들
* base
검색을 시작할 dn
* scope
LDAP_SCOPE_BASE : Base DN에 대한 검색
LDAP_SCOPE_ONELEVEL : Base DN에서 한단계 하위 Entry들까지
검색
LDAP_SCOPE_SUBTREE : Base DN의 모든 하위 Entry들에 대해서
검색
* filter
RFC 1558에 정의된 검색 filter를 그대로 사용
* attrs
Null terminated array로 끝나며, 각 attrs에는 매칭된
Entry의 어떤 속성 값들을 리턴할 지를 정하는 속성들이
들어간다. 이 값을 NULL로 주면 기본적으로 모든 속성들에
대한 정보를 리턴한다.
* attrsonly
Entry가 가지고 있는 속성의 이름들만을 리턴할 지를 정한다.
0이면 속성 이름과 값들이 모두 리턴되고, 0이외의 값이 오면
속성 이름만을 리턴한다.
* timeout


ldap_search_st()에서 사용하며, timeout 시간을 설정한다.
* res
Synchronous 함수로 검색을 수행할 때, 이 구조체로 결과들이
리턴된다.

%% 커넥션 핸들에서 검색에 영향을 미치는 변수들이다
. ld_sizelimit
한 번의 검색에서 리턴할 수 있는 최대 엔트리의 수
. ld_timelimit
한 번의 검색이 이루어 질수 있는 최대 시간
. ld-deref
다른 서버로 접속하라는 결과를 받았을 때, 이 결과에
대한 처리 방법을 결정

%% Asynchronous Search는 ldap_search()로 시작되며, 결과는
메시지 ID와 함께 ldap_result()를 호출하여 얻어 낼 수 있다.

%% 하나의 Entry에 대해서 억세스 하려 할 때...
별다른 API를 지원하지 않는다. Search에서 filter를
"(objectclass=*)"로 주고, scope를 BASE로 주면 된다.

%% 하나의 Entry의 하위 Entry들을 보고 싶을 때...
역시 별다른 API를 지원하지 않는다. Search에서 filter를
"(objectclass=*)"로 주고, scope를 ONELEVEL로 주면 된다.

1.2.5. Entry의 Data고치기

typedef struct ldapmod {
int mod_op;
char *mod_type;
union {
char **modv_strvals;
struct berval **modv_bvals;
} mod_vals;
} LDAPMod;

#define mod_values mod_vals.modv_strvals
#define mod_bvalues mod_vals.modv_bvals

int ldap_modify( LDAP *ld, char *dn, LDAPMod *mods[] );
int ldap_modify_s( LDAP *ld, char *dn, LDAPMod *mods[] );

하나의 Entry에 대해서, 속성들을 추가하거나, 값들을
변경,추가,삭제하는데 쓰인다. 주의할 점은 LDAPMod의 Value는 반드시
Null terminated-array여야 한다는 것이다.

ldap_modify의 Arguments :
* ld
ldap_open에서 넘겨받은 커넥션 핸들
* dn
Modify가 수행될 Entry의 dn
* mods
반드시 Null-terminated Array여야 한다. 즉, 마지막 원소에는
꼭 "NULL"로 되어있어야 한다.
%% LDAPMod 구조체에 대해서 알아보자
* mod_op
LDAP_MOD_ADD : 지정한 속성의 값을 추가하는 역할을 한다.
속성이 없을 경우에는 만들어서 값을 추가한다.
LDAP_MOD_DELETE : 지정한 속성 중에서 사용자가 준 속성값
과 일치하는 속성값을 Entry에서 삭제한다.
LDAP_MOD_REPLACE : 추가를 하는게 아니라 덮어쓴다.

%% 모든 값들에는 LDAP_MOD_BVALUES가 OR연산될 수 있으며,
OR연산이 된 상태에서는 mods의 멤버 중, mod_bvals가
쓰여져야만 한다.
* mod_type
어떤 속성에 대한 연산인지를 밝히는 속성 이름이
들어간다.


* mod_vals
실제 연산이 수행되면서 필요한 값들이 모두 저장된다.
mod_strvals에는 문자 데이터들이 들어가게 된다. 만약
mod_op에서 LDAP_MOD_BVALUES를 OR연산 했다면, 여기서
mod_bvals에 값을 넣어줘야 한다. berval의 선언은 다음과
같다.

typedef struct berval {
unsigned long bv_len;
char *bv_val;
};

bv_len은 bv_val의 길이를 나타낸다. bv_val은 Binary
데이터를 담고 있으며, Null로 끝나는 스트링이어야 한다.

1.2.6. Entry의 이름 바꾸기

int ldap_modrdn (LDAP *ld,char *dn,char *newrdn,int deleteoldrdn);
int ldap_modrdn_s (LDAP *ld,char *dn,char *newrdn,int
deleteoldrdn);

이 함수들은 주어진 dn이 가리키는 Entry의 이름을 변경하는데 쓰인다.
위 modify와의 다른 점이라면, 위에서는 Entry의 속성만을 변경하는데
비해, 이것은 Entry의 특수 속성 중의 하나인 Entry의 이름을
변경한다는데 있다.

ldap_modrdn의 Arguments :
* ld
ldap_open에서 넘겨받은 커넥션 핸들
* dn
Modify가 수행될 Entry의 dn
* newrdn
변경 후에 dn의 Entry가 가질 새로운 이름이다. 바뀔 dn을
Full로 적어 주지 않는다면, 이전 DN에서 빠진 부분을 채워
넣는다. 이 dn이 이미 존재할 경우 연산을 실패한다.
Ex) cn=godslord,ou=SPARCS,o=KAIST,c=KR 에서
cn=YongChul,ou=SPARCS,o=KAIST,c=KR로 변경하고 싶을 때는
NewRdn에 "cn=YongChul"만을 적어주면 된다.
* deleteoldrdn
0이 올 경우에는 이전 dn에 대해서 속성 값들을 삭제 하지
않고 방치한다. 0이외의 값들이 오게 되면 이전 dn에 대한
모든 값들을 삭제한다.

1.2.7. 새로운 Entry를 추가하기

int ldap_add( LDAP *ld, char *dn, LDAPMod *attrs[] );
int ldap_add_s( LDAP *ld, char *dn, LDAPMod *attrs[] );

이 함수들은 디렉토리에 새로운 Entry를 추가할 때 사용된다. 역시
Modify와 다른 점은 Modify는 이미 존재하는 Entry에 대해서만 변경이
가능하지만, 이것은 Entry가 존재하지 않을 때 사용된다는 것이다.
주의할 점은 지정한 dn의 바로 상위 dn들이 먼저 존재해야만 한다는
것이다.

ldap_add의 Arguments :
* ld
ldap_open에서 넘겨받은 커넥션 핸들
* dn
새롭게 만들어질 Entry의 dn
* attrs
Modify의 그것과 동일하다.

1.2.8. Entry를 삭제하기

int ldap_delete( LDAP *ld, char *dn );
int ldap_delete_s( LDAP *ld, char *dn );

이 함수들은 디렉토리에서 특정 Entry를 삭제하는데 쓰인다. 그리고
삭제 대상이 되는 Entry는 하위 Entry들을 가지고 있지 않아야만 한다.
모든 하위 Entry에 대한 삭제는 LDAP 자체에서 지원하지 않는다.

ldap_delete의 Arguments :
* ld
ldap_open에서 넘겨받은 커넥션 핸들
* dn
삭제될 Entry의 DN

1.2.9. 연산 취소

int ldap_abandon( LDAP *ld, int msgid );

Asynchronous 연산을 수행 중일 때만 수행이 가능하다. 지정한 msgid의
수행 취소를 서버측에 요구하며, 프로그램은 이 함수의 호출 후 해당
연산에 대해서 신경을 끊어야 한다.

ldap_abandon의 Arguments :
* ld
ldap_open에서 넘겨받은 커넥션 핸들
* msgid
취소를 요구할 연산의 고유 번호

1.2.10. 결과 메시지들에 대한 Parsing

int ldap_result(LDAP *ld,int msgid,int all,struct timeval
*timeout, LDAPMessage **res);
int ldap_msgfree(LDAPMessage *res);

ldap_result()는 Asynchronous 함수들에 대한 수행 결과를 얻을 때
사용된다. ldap_msgfree()는 ldap_result()나 Synchronous 함수들에
대한 결과들을 free시킬 때 사용된다.

ldap_result의 Arguments :
* ld
ldap_open에서 넘겨받은 커넥션 핸들
* msgid
Asynchronous 함수를 호출하면서 얻은 msgid를 써 주면, 그
msgid에 대한 결과를 리턴한다.
LDAP_RES_ANY : msgid에 상관없이 리턴된 결과가 있으면 바로
리턴해 준다.
* all
Search에 대해서만 영향을 끼친다. 0의 값이 오면 Entry들이
넘어오는 즉시 리턴하게 되고, 그 이외의 값이 오면 모든
Entry들이 넘어 올 때 까지 리턴하지 않는다.
* timeout
결과가 리턴할 때 까지 얼마나 기다릴 지를 지정한다.
NULL : 결과가 넘어 올 때 까지 Block시킨다.
* res
ldap_result()가 결과를 적어 넣을 구조체에 대한 포인터를
지정한다. 이 구조체는 사용후 ldap_msgfree()를 이용해서
free시켜 주어야 한다.

%% ldap_result는 성공적으로 결과를 받아 오면 다음 중의 하나의
상수를 리턴하여 어떤 연산에 대한 결과인지를 알린다.

LDAP_RES_BIND, LDAP_RES_SEARCH_ENTRY,
LDAP_RES_SEARCH_RESULT, LDAP_RES_MODIFY, LDAP_RES_ADD,
LDAP_RES_DELETE, LDAP_RES_MODRDN, LDAP_RES_COMPARE

1.2.11. Error Handling

int ldap_result2error(LDAP *ld,LDAPMessage *res,int freeit);
char *ldap_err2string( int err );
void ldap_perror( LDAP *ld, char *msg );

API로 부터 반환된 에러들을 Human Readerble String으로 바꿔
준다.
ldap_result2error()는 ldap_result()나 Synchronous함수들의
리턴 결과에 대해서 상수 error code로 변환해 주는 역할을 한다. 이
함수는 결과 구조체에서 ld_mached와 ld_error들도 해석하여 커넥션
핸들에 추가해 넣어주는 역할도 한다. 모든 Synchronous함수들은
리턴하기 전에 이 함수를 호출한다.

%% ld_matched : LDAP_NO_SUCH_OBJECT 에러에 사용된다.
ld_error : 서버 측에서 날아오는 에러 메시지들을 담고 있다.
ld_errno : 연산의 수행 결과에서 에러가 났을 때를 가리킨다.

ldap_err2string()은 ldap_result2error()나 Synchronous함수들의
리턴 결과를 Null terminated Error메시지로 바꾸어준다.
ldap_perror()는 Standard Err에 출력할 때 사용된다.

Arguments :
* ld
ldap_open에서 넘겨받은 커넥션 핸들
* res
ldap_result()에서 넘겨 받은 결과나, Synchronous 함수에서
넘겨 받은 결과를 지정한다.
* freeit
res argument에 대해서 0이면 free시키지 않고, 그 이외의
값이면 free시킨다.
* err
ldap_result2error()에서 넘어온 error code나
Synchronous함수에서 리턴된 error code를 지정한다.
* msg
LDAP error메시지 출력 전에 출력할 문장이다.

1.2.12. 결과의 해석

이제 부터 살펴 볼 함수들은 Search Operation의 결과로 넘어온
LDAPMessage 구조체에 대한 Parsing에 대해서 살펴 볼 것이다.

LDAPMessage *ldap_first_entry( LDAP *ld, LDAPMessage *res );
LDAPMessage *ldap_next_entry( LDAP *ld, LDAPMessage *entry );
int ldap_count_entries( LDAP *ld, LDAPMessage *res );

이 함수들은 LDAPMessage 구조체에 대해서 Entry별로 잘라서 리턴해
준다. ldap_first_entry()를 반드시 먼저 호출해 주고,
ldap_next_entry()로 ldap_count_entries()의 값 만큼 읽어 주면
Entry별 Parsing은 끝난다.
ldap_first_entry()와 next_entry()들은 더 이상 Parsing할 데이터가
없으면 NULL을 리턴한다.
ldap_count_entries()는 지정한 LDAPMessage포인터에 대해 몇 개의
Entry가 들어있는지를 리턴해 준다.

Arguments :
* ld
ldap_open에서 넘겨받은 커넥션 핸들
* res
Search결과가 담겨진 구조체의 포인터이다. ldap_result()나
Synchronous search함수의 결과들이 올 수 있다.
* entry
이전 ldap_first_entry()나 ldap_next_entry()들의 호출에 의해
넘어온 LDAPMessage의 포인터들을 지정하면 된다.

char * ldap_first_attribute ( LDAP * ld, LDAPMessage *entry, void
**ptr );
char * ldap_next_attribute ( LDAP * ld, LDAPMessage *entry, void
*ptr );

위 Entry별 파싱이 하나하나 이루어 질 때 마다, 위 함수를 이용하여
그 Entry에 들어있는 Attribute Value들에 대해서도 파싱을 해야 한다.
역시 ldap_first_attribute()를 반드시 먼저 호출해 준 다음,
ldap_next_attribute()를 NULL을 리턴할 때 까지 호출해 주면 된다.

Arguments :
* ld
ldap_open에서 넘겨받은 커넥션 핸들
* entry
어떤 Entry에 대해서 Attribute를 추출할 지를 지정한다.
위에서 살펴본 ldap_first_entry()나, ldap_next_entry()에서
리턴 받은 값을 사용하면 된다.
* ptr
이 포인터는 ldap_first_attribute()에서는 지정한
Entry내에서 내부적으로 위치를 표시하기 위해서 사용된다.
ldap_next_attribute()에서는 ldap_first_attribute()에서
사용하던 것을 가져다 쓰면 된다.

두 함수 모두 더 이상 파싱할 Attribute들이 없으면 NULL을 리턴한다.
두 함수 모두 현재 Attribute name을 가지고 있는 포인터를 리턴한다.
리턴된 이름은 ldap_get_values()등에서 사용된다.

char ** ldap_get_values(LDAP *ld,LDAPMessage *entry,char *attr);
struct berval ** ldap_get_values_len(LDAP *ld,LDAPMessage
*entry,char *attr);
int ldap_count_value(char **vals);
int ldap_count_values_len(struct berval **vals);
int ldap_value_free(char **vals);
int ldap_value_free_len(struct berval **vals);

ldap_get_values()와 ldap_get_values_len()은 한 Entry에서 주어진
속성의 값을 읽어 오는데 사용된다. ldap_count_values와
ldap_count_values_len()은 넘어온 결과 값들이 몇 개인지를 리턴한다.
ldap_value_free()와 ldap_value_free_len()은 값들을 free시키는데
쓰인다.

Arguments :
* ld
ldap_open에서 넘겨받은 커넥션 핸들
* entry
값을 읽어올 Attribute가 속한 Entry를 지정한다. 역시
ldap_first_entry()나 ldap_next_entry()의 리턴값이
사용된다.
* attr
값을 읽어올 속성의 이름이다. ldap_first_attribute()나
ldap_next_attribute()에서 리턴값이 사용된다. 또는 "mail"과
같이 사용자가 직접 지정해 줄 수도 있다.
* vals
ldap_get_values()나 ldap_get_values_len()에서 읽어낸
결과값을 저장할 포인터를 지정해 주면 된다.

위 함수들 중 _len 접미사가 붙은 함수들은 Binary나 String 데이터에
관계없이 사용될 수 있는 것들이며, 접미사가 붙지 않은 것은 String
데이터에 대해서만 적용된다.

%% 리턴받은 Value들은 malloc'ed 된 것들이기 때문에 반드시
ldap_value_free()나 ldap_value_free_len()을 이용하여 free시켜
줘야 한다.

1.2.13. Entry의 이름 얻어 내기

char *ldap_get_dn( LDAP *ld, LDAPMessage *entry );
char **ldap_explode_dn( char *dn, int notypes );
char *ldap_dn2ufn( char *dn );

ldap_get_dn()은 Entry의 이름을 얻어낼 때 쓰인다.
ldap_explode_dn()은 이름의 type을
ldap_dn2ufn()은 Entry의 이름을 좀더 읽기 편한 형태로 바꾸어 준다.

Arguments :
* ld
ldap_open에서 넘겨받은 커넥션 핸들
* entry
이름을 얻어낼 Entry에 대한 포인터이다.
ldap_first_entry()나 ldap_next_entry()가 리턴한 포인터를
사용하면 된다.
* dn
ldap_get_dn()에서 리턴 받은 것을 사용하면 된다.
* notypes
0이 아닌 경우 dn을 이루는 원소들의 type 정보들을 표시하지
않는다.
Ex) "cn=YongChul"이 "YongChul"로 표기 된다.

%% ldap_get_dn()은 에러시에 NULL을 리턴한다. 그리고 malloc'ed된
포인터를 리턴하기 때문에 free()를 이용하여 free시켜 줘야 한다.
%% ldap_explode_dn()은 char *의 배열을 리턴하기 때문에 다 사용했을
경우에는 ldap_value_free()를 이용하여 free시켜 줘야 한다.

2.2. Netscape LDAP SDK 1.0

Netscape LDAP SDK 1.0은 LDAP API Implementation중의 하나로
Netscape사에서 각 Platform별로 개발하여 무상으로 배포하고
있다(불행히도 서버는 그렇지 않다...TT). Netscape SDK에서는 LDAP v3
Spec을 완벽히 지원하며, 그 장점 중의 하나로 SSL의 사용으로 보다 안전한
커넥션을 보장해 준다는 것이다.
SSL을 사용하려면, "ldap_ssl.h" 헤더 파일을 include해 주어야 한다.
컴파일시에는 "ldap10"라이브러리를 링크해 주고, Solaris의 경우 추가로
"socket"이나 "nsl", "thread"등의 라이브러리를 추가로 링크해 주어야
한다.

영리를 목적으로 하는 만큼, Standard API보다 여러모로 강력한 기능들을
제공한다. 두 API들에서 상당 부분의 함수들이 동일한 기능을 한다. 그래서
이 절에서는 Standard API와 차이가 있는 부분들 만을 짚고 넘어가도록
하겠다.

2.2.1. About Connection

. Netscape SDK(이하 ND라 표기)에서는 커넥션을 열기위해 ldap_init()
이라는 함수를 사용하며, 함수의 Arguments는 ldap_open()과 동일하다.
. ND에서는 ldap_unbind()에도 _s가 붙은 버전이 있지만 모두
Synchronous버전이다.
. ldap_get_option()과 ldap_set_option()을 이용하여 Session에
관련된 여러가지 옵션들을 지정할 수 있다.

2.2.2. About Using Secure Sockets Layer(SSL)

ND에서는 LDAP서버와 SSL을 통해 연결할 수 있는 함수들을 제공하고
있다. SSL은 몇몇 서버에서만 지원되고 있고, Netscape Enterprise
Server만이 SSL 3.0을 지원하는 유일한 서버이다(라고 자사 제품을
선전하고 있다...--;). 그리고 이 SDK에서는 Server측의
Authenication과 Encryption만을 지원하고 있다. Client의
Authentication은 아직 지원하지 않는다.

2.2.2.1. SSL을 이용한 커넥션

int ldapssl_client_init( const char *certdbpath,
void *certdbhandle );

Arguments :
* certdbpath
Client의 Certificates를 가지고 있는 DB의 경로를
지정한다. 이 DB는 Netscape Navigator 3.x가 사용하는
cert5.db cert DB이거나, Netscape 2.x 서버들이 사용하는
ServerCert.db cert DB여야만 한다.
* certdbhandle
NULL값을 주면 된다(현재 사용되지 않는다).

LDAP *ldapssl_init( const char *defhost, int defport,
int defsecure );

Arguments :
* defhost
연결할 호스트를 지정한다.
* defport
연결할 호스트의 포트 번호를 지정한다.
* defsecure
기본적으로 SSL을 사용해서 연결을 할 것인지를 결정한다.
0 이외의 값이 오면, 기본적으로 SSL을 이용해서
연결한다.

먼저, ldapssl_client_init()함수를 호출하여 Client를 초기화 해
주어야 한다. 그 다음에 ldapssl_init()함수를 호출하여, LDAP
Session을 연결 해 주어야 한다. Client를 초기화 해 주는
작업에서 Client는 Cert DB를 연결한다.

프로그램의 구성은 대략 다음과 같이 이루어 진다.

1) ldapssl_client_init()의 호출
2) ldapssl_init()의 호출
3) 그 뒤로는 여타 함수를 사용하여 Operation을 수행하면 된다.

이 방법 대신에 쓰이는 한 가지 방법이 더 있다.

1) ldapssl_client_init()의 호출
2) ldap_init()의 호출
3) ldapssl_install_routines()의 호출
4) ldap_set_option(ld,LDAP_OPT_SSL,LDAP_OPT_ON)을 호출

위 방법은 ldapssl_init()함수를 풀어서 쓴 것이나 마찬가지
효과를 지닌다.

2.2.3. Handling Referral

ND에서는 Referral에 대한 지원이 강력하다. Referral에 의해 다른
서버에 다시 Authentication이 필요할 때, 보통은 Anonymous로
Authentication을 수행하지만, USER가 직접 Authentication을 지정해
줄 수도 있다. 이것은 rebindproc()이라는 함수의 호출로 가능하다.

int rebindproc( LDAP *ld, char **dnp, char **passwdp, int
authmethodp, int freeit, void *arg );

Arguments :
* dnp
User가 Binding할 DN이다.
* passwd
User의 Binding Password이다.
* authmethodp
Authentication의 방법을 지정한다. 현재로서는
LDAP_AUTH_SIMPLE만이 지원된다.
* freeit
이전에 호출된 rebindproc()에 의해 할당된 메모리를 free시킬
것인지의 여부를 지정한다. 0이외의 값이 온다면 free시킨다.
* arg
결과를 받아낼 포인터를 지정한다.

%% 이것을 Referral이 수행되는 동안에 반영되게 하려면,
ldap_set_rebind_proc()을 호출해야 한다.

2.2.4. Result Sorting

ND에서는 Search의 결과에 대한 Sort 함수들도 제공하고 있다.

int ldap_sort_entries( LDAP *ld, LDAPMessage *chain, char *attr,
int (*cmp)());
int ldap_sort_values( LDAP *ld, char **vals, int (*cmp)() );

Arguments :
* ld
커넥션 핸들이다
* chain
Synchronous search나 ldap_result()에서 받은 결과를 지정해
주면 된다.
* attr
기준이 될 Attribute를 지정한다. NULL이면 DN에 대해서
정렬한다.
* vals
정렬할 값들의 포인터를 지정한다.
* int (*cmp)()
정렬 할 때 사용할 함수를 지정한다(Ex : strcmp)

2.2.5. 이 외의 것들

굵직 굵직한 것들은 모두 Standard API와 동일하다.
이 외에는 주로 데이터들을 좀 더 편하게 다룰 수 있게 해 주는
함수들과 각 타입들에 따라 확실한 data free함수들을 제공하는 것들
등이 대부분이다.

2. Constructing User Specific Backend API(umich SLAPD)

2.1. SLAPD Backend API


총 12개의 Call로 구성되어 있다. 이중 9개는 LDAP 프로토콜 Operation에
해당하는 것들(bind, unbind, search, compare, modify, modify RDN, add,
delete, abandon)이고, 나머지 3개는 Backend의 Initialize와 Shutdown,
그리고 Backend-specific Configuration을 다루는데 쓰인다.
LDAP 프로토콜 Operation에 해당하는 call들은 다음의 3가지 인자들을
공통적으로 넘겨 받아야만 한다.

Backend *be /* info about this backend */
Connection *conn /* info about this connection */
Operation *op /* info about this operation */

나머지 인자들은 각각의 call들에 따라 결정된다.

2.1.1. Bind Call

foo_bind(Backend *be,Connection *conn,Operation *op,char *dn,int
method,struct berval *cred);

Arguments :
* dn
Binding DN
* method
LDAP_AUTH_SIMPLE
LDAP_AUTH_KRBV41
LDAP_AUTH_KRBV42
* cred
Kerberos Credential이나 password가 올 수 있다.

Return values :
성공적으로 수행 되었을 때 0을 리턴하고, 그 이외에는 0이외의
값을 리턴한다. 0이 리턴되어야지만 Front end가 그 커넥션이
Authenticate되었다고 인정하고, 다음 Operation들을 수행한다.

%% cred 항목이 NULL이거나, dn이 NULL이라면 NULL Authentication이
수행되어야만 한다.

2.1.2. Unbind Call

foo_unbind(Backend *be,Connection *conn,Operation *op);

%% backend가 그 Connection에서 사용한 자원들을 해제하는 루틴이
제공되어야만 한다.

2.1.3. Compare Call

foo_compare(Backend *be,Connection *conn,Operation *op,char *dn,
Ava *ava);

Arguments :
* dn
Compare를 수행할 DN을 지정한다.
* ava
해당하는 Entry에 대한 Attribute Assertion이다.

%% typedef struct ava {
char *ava_type;
struct berval ava_value;
} Ava;
type에 대한 비교는 ava_type에 의해 이루어 지며, value에
대한 비교는 ava_value에 의해 이루어 진다.

2.1.4. Search Call

foo_search(Backend *be,Connection *conn,Operation *op,char *base,
int scope,int sizelimit,int timelimit,Filter *filter,char
*filterstr,char **attrs,int attrsonly);
method,struct berval *cred);

Arguments :
* base
search를 수행하기 시작할 최초 시작점
* scope
LDAP_SCOPE_BASEOBJECT
LDAP_SCOPE_ONELEVEL
LDAP_SCOPE_SUBTREE
* sizelimit
Client 쪽에서 요구한 size limit이다. 0이면 무제한이다.
* timelimit
Client 쪽에서 요구한 time limit이다. 0이면 무제한이다.
* filter
search filter를 나타내는 구조체이다. backend에서는 이
항목을 사용하던지 아래의 filterstr을 사용하던지 둘 중
하나를 택일해야만 한다. 아래에 이 Structure에 대한 정의를
실었다.
* filterstr
보통의 String 형식의 Search Filter이다.
* attrs
search를 수행하고 리턴할 속성들을 지정하고 있다. NULL일
경우 모든 속성들을 리턴한다.
* attrsonly
속성 이름만을 리턴할지 결정한다. 0이면 값들까지 리턴한다.

%% Filter ::= CHOICE {
and [0] SET OF Filter,
or [1] SET OF Filter,
not [2] Filter,
equalityMatch [3] AttributeValueAssertion,
substrings [4] SubstringFilter,
greaterOrEqual [5] AttributeValueAssertion,
lessOrEqual [6] AttributeValueAssertion,
present [7] AttributeType,
approxMatch [8] AttributeValueAssertion
}

C Languuage Definition은 "slap.h"에 정의되어 있다.

2.1.5. Modify Call

foo_modify(Backend *be,Connection *conn,Operation *op,char
*dn,LDAPMod *mods);

Arguments :
* dn
Modify될 Entry의 dn
* mods
Modify될 내용들을 담은 list

2.1.6. Modify RDN

foo_modifyrdn(Backend *be,Connection *conn,Operation *op,char
*dn,char *newrdn,int deleteoldrdn);

Arguments :
* dn
Operation이 수행될 dn을 지정한다.
* method
LDAP_AUTH_SIMPLE
LDAP_AUTH_KRBV41
LDAP_AUTH_KRBV42
* cred
Kerberos Credential이나 password가 올 수 있다.

Return values :
성공적으로 수행 되었을 때 0을 리턴하고, 그 이외에는 0이외의
값을 리턴한다. 0이 리턴되어야지만 Front end가 그 커넥션이
Authenticate되었다고 인정하고, 다음 Operation들을 수행한다.

%% cred 항목이 NULL이거나, dn이 NULL이라면 NULL Authentication이
수행되어야만 한다.

2.1.1. Bind Call

foo_bind(Backend *be,Connection *conn,Operation *op,char *dn,int
method,struct berval *cred);

Arguments :
* dn
Binding DN
* method
LDAP_AUTH_SIMPLE
LDAP_AUTH_KRBV41
LDAP_AUTH_KRBV42
* cred
Kerberos Credential이나 password가 올 수 있다.

Return values :
성공적으로 수행 되었을 때 0을 리턴하고, 그 이외에는 0이외의
값을 리턴한다. 0이 리턴되어야지만 Front end가 그 커넥션이
Authenticate되었다고 인정하고, 다음 Operation들을 수행한다.

%% cred 항목이 NULL이거나, dn이 NULL이라면 NULL Authentication이
수행되어야만 한다.

2.1.1. Bind Call

foo_bind(Backend *be,Connection *conn,Operation *op,char *dn,int
method,struct berval *cred);

Arguments :
* dn
Binding DN
* method
LDAP_AUTH_SIMPLE
LDAP_AUTH_KRBV41
LDAP_AUTH_KRBV42
* cred
Kerberos Credential이나 password가 올 수 있다.

Return values :
성공적으로 수행 되었을 때 0을 리턴하고, 그 이외에는 0이외의
값을 리턴한다. 0이 리턴되어야지만 Front end가 그 커넥션이
Authenticate되었다고 인정하고, 다음 Operation들을 수행한다.

%% cred 항목이 NULL이거나, dn이 NULL이라면 NULL Authentication이
수행되어야만 한다.

2.1.1. Bind Call

foo_bind(Backend *be,Connection *conn,Operation *op,char *dn,int
method,struct berval *cred);

Arguments :
* dn
Binding DN
* method
LDAP_AUTH_SIMPLE
LDAP_AUTH_KRBV41
LDAP_AUTH_KRBV42
* cred
Kerberos Credential이나 password가 올 수 있다.

Return values :
성공적으로 수행 되었을 때 0을 리턴하고, 그 이외에는 0이외의
값을 리턴한다. 0이 리턴되어야지만 Front end가 그 커넥션이
Authenticate되었다고 인정하고, 다음 Operation들을 수행한다.

%% cred 항목이 NULL이거나, dn이 NULL이라면 NULL Authentication이
수행되어야만 한다.

by 큐브 | 2007/04/18 09:36 | LDAP | 트랙백 | 덧글(2)
트랙백 주소 : http://cubenuri.egloos.com/tb/151549
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Commented by blitz고양이 at 2007/04/18 11:29
프린트해서 찬찬히 읽어봐야겠습니다.
Commented by 큐브 at 2007/04/18 14:08
오~ 놀라워라 오늘 이제 첨 올렸는데 벌써 comment 가 달리다니....^^; 감사합니다~
LDAP 관련 자료는 한글로 된게 몇개 없고 샘플도 없어서 프로그래밍하기 참 힘들더군요.
그래서 어제 하루종일 검색해봤었는데 그나마 이게 api 마냥 잘 정리되어있는거 같아서 카피를 해왔더랬지요

:         :

:

비공개 덧글



< 이전페이지 다음페이지 >