# Debian/Ubuntu
sudo apt-get install libldap2-dev
# CentOS/RHEL
sudo yum install openldap-devel
/etc/test/ldap_test.conf
## LDAP 서버의 주소 및 포트 지정
LDAP_URI = "ldap://192.168.1.152:389"
## Base DN
LDAP_BASE_DN = "dc=example,dc=com"
## Bind DN
LDAP_BIND_DN = "cn=admin,dc=example,dc=com"
## Base DN for Users
LDAP_USER_BASE_DN = "ou=People,dc=example,dc=com"
BaseDN vs BindDN
📌 Base DN
: LDAP Directory Tree의 검색 시작점을 나타냄
: 모든 LDAP 항목은 이 Base DN 아래에 위치함
: 일반적으로 조직의 도메인 이름을 역순으로 표현함
: e.g. "dc=company,dc=com"📌 Bind DN
: LDAP 서버에 연결할 때 사용하는 사용자의 DN (Distinguished Name)
: 사용자나 관리자 계정의 전체 경로를 나타냄
: e.g. "cn=admin,dc=company,dc=com"
: e.g. "cn=username,ou=People,dc=company,dc=com"
LDAP 서버 연결 테스트하기
ldap_connect.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <ldap.h>
#define CONFIG_FILE "/etc/test/ldap_test.conf"
#define MAX_LINE 256
int main() {
FILE *f = fopen(CONFIG_FILE, "r");
if (!f) {
perror("Failed to open config file");
return EXIT_FAILURE;
}
char ldap_uri[MAX_LINE] = {0};
char bind_dn[MAX_LINE] = {0};
char line[MAX_LINE];
while (fgets(line, sizeof(line), f)) {
if (sscanf(line, "LDAP_URI = \"%255[^\"]\"", ldap_uri) == 1) continue;
if (sscanf(line, "LDAP_BIND_DN = \"%255[^\"]\"", bind_dn) == 1) continue;
}
fclose(f);
if (!*ldap_uri || !*bind_dn) {
fprintf(stderr, "Required configuration not found in [%s] file\n", CONFIG_FILE);
return EXIT_FAILURE;
}
printf("LDAP URI: %s\n", ldap_uri);
printf("LDAP Bind DN: %s\n", bind_dn);
// LDAP handle pointer
LDAP* ld = NULL;
// ldap_initialize() -> LDAP 라이브러리 초기화 & 서버 연결
// LDAP 핸들 생성 + 지정된 URI의 서버에 연결 시도
// 반환 값 = LDAP 결과 코드. LDAP_SUCCESS = 성공.
int rc = ldap_initialize(&ld, ldap_uri);
// 연결 시도 결과 확인
if (rc != LDAP_SUCCESS) {
// 연결 실패
// ldap_err2string(): LDAP 결과 코드를 읽을 수 있는 문자열로 변환
fprintf(stderr, "ldap_initialize failed: %s\n", ldap_err2string(rc));
return 1;
}
// LDAP 프로토콜 버전 설정 (v3)
int version = LDAP_VERSION3;
rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
if (rc != LDAP_SUCCESS) {
fprintf(stderr, "Failed to set LDAP protocol version: %s\n", ldap_err2string(rc));
ldap_unbind_ext_s(ld, NULL, NULL); // LDAP 연결 종료
return 1;
}
// 비밀번호 입력 받기
char* password = getpass("Enter LDAP password: ");
if (!password) {
fprintf(stderr, "Failed to read password\n");
ldap_unbind_ext_s(ld, NULL, NULL);
return 1;
}
// LDAP 바인딩에 사용할 자격 증명 설정
struct berval cred;
cred.bv_val = password;
cred.bv_len = strlen(password);
// SIMPLE 메커니즘을 사용하여 LDAP 서버에 바인딩(인증)
// !주의: SIMPLE 메커니즘은 비밀번호를 평문으로 전송하므로, 실제 환경에서는 TLS와 함께 사용해야함.
rc = ldap_sasl_bind_s(ld, bind_dn, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
memset(password, 0, strlen(password));
if (rc != LDAP_SUCCESS) {
fprintf(stderr, "LDAP bind failed: %s\n", ldap_err2string(rc));
ldap_unbind_ext_s(ld, NULL, NULL);
return 1;
}
// 연결 성공
printf("Successfully connected to LDAP server: %s\n", ldap_uri);
printf("Authenticated as: [%s]\n", bind_dn);
// LDAP 연결 종료
ldap_unbind_ext_s(ld, NULL, NULL);
return 0;
}
컴파일 및 실행
gcc -o ldap_connect ldap_connect.c -lldap
./ldap_connect
결과 예시

namingContexts
LDAP DIT(Directory Information Tree)에서 특정 서버가 관리하는 루트나 루트들에 해당하는 디렉터리 경로를 나타내는 속성. LDAP 서버는 여러 개의 namingContext를 가질 수 있으며, 각 namingContext는 DIT의 다른 부분을 루트로 하여 관리한다. LDAP Client는namingContexts를 조회하여 서버가 제공하는 모든 루트 DN을 통해 디렉터리 구조를 파악할 수 있다.
LDAP 서버에서 namingContexts 조회 방법ldapsearch -x -H ldap://YOUR_LDAP_IP:389 -s base -b "" "(objectClass=*)" namingContexts
-H ldap://YOUR_LDAP_UP: LDAP 서버 URI 지정-x: 단순 인증 사용-s base: 검색 범위를 base로 지정-b "": baseDN을 루트로 지정"(objectClass=*)": 모든 객체namingContexts: 반환된 결과에서 namingContexts 속성만 표시
예시
- 해당 LDAP 서버는
dc=ldap,dc=company,dc=com을 루트로 하는 디렉터리 정보를 관리하고 있음을 나타냄- 이 정보를 통해 LDAP 서버가 관리하는 디렉터리의 최상위 구조를 알 수 있음.
dc=example,dc=com아래의 모든 엔트리 검색 예시ldapsearch -x -H ldap://192.168.1.152:389 -b "dc=example,dc=com" "(objectClass=*)"
uid로 사용자 검색하기
ldap_user_search.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ldap.h>
#include <lber.h>
#define CONFIG_FILE "/etc/test/ldap_test.conf"
#define MAX_LINE 256
int main() {
FILE *f = fopen(CONFIG_FILE, "r");
if (!f) {
perror("Failed to open config file");
return EXIT_FAILURE;
}
char ldap_uri[MAX_LINE] = {0};
char base_dn[MAX_LINE] = {0};
char bind_dn[MAX_LINE] = {0};
char user_base_dn[MAX_LINE] = {0};
char line[MAX_LINE] = {0};
// 설정 파일에서 LDAP_URI와 LDAP_BINDDN 읽어오기
while (fgets(line, sizeof(line), f)) {
if (sscanf(line, "LDAP_URI = \"%255[^\"]\"", ldap_uri) == 1) continue;
if (sscanf(line, "LDAP_BASE_DN = \"%255[^\"]\"", base_dn) == 1) continue;
if (sscanf(line, "LDAP_BIND_DN = \"%255[^\"]\"", bind_dn) == 1) continue;
if (sscanf(line, "LDAP_USER_BASE_DN = \"%255[^\"]\"", user_base_dn) == 1) continue;
}
fclose(f);
if (!*ldap_uri || !*base_dn || !*bind_dn || !*user_base_dn) {
fprintf(stderr, "Required configuration not found in [%s] file\n", CONFIG_FILE);
return EXIT_FAILURE;
}
const char *password = getpass("Password: ");
if (!password || !*password) {
fprintf(stderr, "Failed to read password\n");
return EXIT_FAILURE;
}
LDAP *ld;
int rc = ldap_initialize(&ld, ldap_uri);
if (rc != LDAP_SUCCESS) {
fprintf(stderr, "ldap_initialize failed: %s\n", ldap_err2string(rc));
return EXIT_FAILURE;
}
int version = LDAP_VERSION3;
rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
if (rc != LDAP_SUCCESS) {
fprintf(stderr, "ldap_set_option failed: %s\n", ldap_err2string(rc));
ldap_unbind_ext_s(ld, NULL, NULL);
return EXIT_FAILURE;
}
struct berval passwd;
passwd.bv_val = password;
passwd.bv_len = strlen(password);
rc = ldap_sasl_bind_s(ld, bind_dn, LDAP_SASL_SIMPLE, &passwd, NULL, NULL, NULL);
if (rc != LDAP_SUCCESS) {
fprintf(stderr, "ldap_sasl_bind_s failed: %s\n", ldap_err2string(rc));
ldap_unbind_ext_s(ld, NULL, NULL);
return EXIT_FAILURE;
}
printf("Successfully bound to LDAP server\n");
// 사용자에게 검색할 uid 입력 받기
char search_uid[MAX_LINE] = {0};
printf("Enter the [uid] to search: ");
if (!fgets(search_uid, sizeof(search_uid), stdin)) {
fprintf(stderr, "Failed to read [uid]\n");
ldap_unbind_ext_s(ld, NULL, NULL);
return EXIT_FAILURE;
}
search_uid[strcspn(search_uid, "\n")] = 0; // Remove newline
// uid를 기반으로 검색 필터 설정
char filter[MAX_LINE];
snprintf(filter, sizeof(filter), "uid=%s", search_uid);
// 검색할 속성들
char *attrs[] = { "cn", "gidNumber", "uidNumber", "createTimestamp", NULL };
printf("Search BaseDN: [%s]\n", base_dn);
printf("Search Filter: [%s]\n", filter);
LDAPMessage *res;
rc = ldap_search_ext_s(ld, user_base_dn, LDAP_SCOPE_SUBTREE, filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res);
if (rc != LDAP_SUCCESS) {
fprintf(stderr, "ldap_search_ext_s failed: %s\n", ldap_err2string(rc));
} else {
int count = 0;
for (LDAPMessage *entry = ldap_first_entry(ld, res); entry != NULL; entry = ldap_next_entry(ld, entry)) {
count++;
char *dn = ldap_get_dn(ld, entry);
printf("Search Result: [%s]\n", dn);
ldap_memfree(dn);
BerElement *ber = NULL;
for (char *attr = ldap_first_attribute(ld, entry, &ber); attr != NULL; attr = ldap_next_attribute(ld, entry, ber)) {
struct berval **values = ldap_get_values_len(ld, entry, attr);
if (values != NULL) {
printf("%s: %s\n", attr, values[0]->bv_val);
ldap_value_free_len(values);
}
ldap_memfree(attr);
}
if (ber != NULL) ber_free(ber, 0);
printf("\n");
}
if (count == 0) {
printf("No results found for uid: [%s] in [%s]\n", search_uid, user_base_dn);
} else {
printf("Success to find %d result(s) for [uid=%s]\n", count, search_uid);
}
ldap_msgfree(res);
}
ldap_unbind_ext_s(ld, NULL, NULL);
return EXIT_SUCCESS;
}
컴파일 및 실행
gcc -o ldap_user_search ldap_user_search.c -lldap -llber
./ldap_user_search
결과 예시

LDAP 서버에 등록된 user id/pw를 입력받아 로그인하기
ldap_login.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ldap.h>
#define CONFIG_FILE "/etc/test/ldap_test.conf"
#define MAX_LINE 256
// CONFIG_FILE을 읽는 함수
int read_config(char *ldap_uri, char *base_dn, char *bind_dn, char *user_base_dn) {
FILE *f = fopen(CONFIG_FILE, "r");
if (!f) {
perror("Failed to open config file");
return 0;
}
char line[MAX_LINE];
while (fgets(line, sizeof(line), f)) {
if (sscanf(line, "LDAP_URI = \"%255[^\"]\"", ldap_uri) == 1) continue;
if (sscanf(line, "LDAP_BASE_DN = \"%255[^\"]\"", base_dn) == 1) continue;
if (sscanf(line, "LDAP_BIND_DN = \"%255[^\"]\"", bind_dn) == 1) continue;
if (sscanf(line, "LDAP_USER_BASE_DN = \"%255[^\"]\"", user_base_dn) == 1) continue;
}
fclose(f);
if (!*ldap_uri || !*base_dn || !*bind_dn || !*user_base_dn) {
fprintf(stderr, "Required configuration not found in [%s] file\n", CONFIG_FILE);
return 0;
}
return 1;
}
int main() {
char ldap_uri[MAX_LINE] = {0};
char base_dn[MAX_LINE] = {0};
char bind_dn[MAX_LINE] = {0};
char user_base_dn[MAX_LINE] = {0};
if (!read_config(ldap_uri, base_dn, bind_dn, user_base_dn)) {
return EXIT_FAILURE;
}
printf("LDAP URI: %s\n", ldap_uri);
printf("LDAP Base DN: %s\n", base_dn);
printf("LDAP User Base DN: %s\n", user_base_dn);
char username[MAX_LINE] = {0};
printf("Enter username: ");
if (fgets(username, sizeof(username), stdin) == NULL) {
fprintf(stderr, "Failed to read username\n");
return EXIT_FAILURE;
}
username[strcspn(username, "\n")] = 0; // Remove newline
const char *password = getpass("Enter password: ");
if (!password || !*password) {
fprintf(stderr, "Failed to read password\n");
return EXIT_FAILURE;
}
LDAP *ld;
int rc;
// ldap_initialize: LDAP 세션 초기화 & LDAP 서버에 연결
// param: LDAP 구조체의 포인터, LDAP URI
// return: LDAP_SUCCESS 또는 에러 코드
rc = ldap_initialize(&ld, ldap_uri);
if (rc != LDAP_SUCCESS) {
fprintf(stderr, "ldap_initialize failed: %s\n", ldap_err2string(rc));
return EXIT_FAILURE;
}
int version = LDAP_VERSION3;
// ldap_set_option: LDAP 세션의 옵션 설정
// param: LDAP 구조체, 옵션 상수, 옵션 값의 포인터
// return: LDAP_SUCCESS 또는 에러 코드
rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
if (rc != LDAP_SUCCESS) {
fprintf(stderr, "ldap_set_option failed: %s\n", ldap_err2string(rc));
ldap_unbind_ext_s(ld, NULL, NULL);
return EXIT_FAILURE;
}
char user_dn[MAX_LINE * 2];
snprintf(user_dn, sizeof(user_dn), "cn=%s,%s", username, user_base_dn);
struct berval cred;
cred.bv_val = (char *)password;
cred.bv_len = strlen(password);
// ldap_sasl_bind_s: LDAP 서버에 바인딩(인증)
// param: LDAP 구조체, 바인딩할 DN, SASL 메커니즘, 인증 정보, 서버 컨트롤, 클라이언트 컨트롤, 서버 자격 증명
// return: LDAP_SUCCESS 또는 에러 코드
rc = ldap_sasl_bind_s(ld, user_dn, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
if (rc != LDAP_SUCCESS) {
fprintf(stderr, "LDAP bind failed: %s\n", ldap_err2string(rc));
ldap_unbind_ext_s(ld, NULL, NULL);
return EXIT_FAILURE;
}
printf("Successfully logged in as user: %s\n", username);
// ldap_unbind_ext_s: LDAP 세션을 종료 & 리소스 해제
// param: LDAP 구조체, 서버 컨트롤, 클라이언트 컨트롤
// return: LDAP_SUCCESS 또는 에러 코드
ldap_unbind_ext_s(ld, NULL, NULL);
return EXIT_SUCCESS;
}
컴파일 및 실행
gcc -o ldap_login ldap_login.c -lldap -llber
./ldap_login
결과 예시

안되는데요 syyoo씨