Ниже приведён пример программы на языке C, которая использует библиотеку libdomain для выполнения операции поиска LDAP. Программа устанавливает соединение с сервером LDAP, выполняет поиск в указанном сервере каталога.
Программа принимает аргументы командной строки для указания параметров соединения с сервером LDAP и параметров поиска:
$ ./libdomain-c-sample --host ldap://dc.example.org:389 --user administrator --pass password --bind "dc=example,dc=org" --sasl
Опции командной строки:
* --host (-h) — сервер LDAP в формате «протокол://адрес:порт», например, «ldap://example.org:389»;
* --user (-u) — имя пользователя LDAP;
* --pass (-w) — пароль LDAP;
* --bind (-b) — DN (Distinguished Name) для привязки к LDAP, например, «dc=example,dc=org»;
* --sasl (-s) — включить использование SASL-привязки.
#include <argp.h>
#include <libdomain/domain.h>
#include <libdomain/directory.h>
#include <libdomain/entry.h>
#include <libdomain/connection_state_machine.h>
#include <stdio.h>
#include <stdbool.h>
#include <talloc.h>
static char* LDAP_DIRECTORY_ATTRS[] = { "objectClass", NULL };
static void exit_callback(verto_ctx *ctx, verto_ev *ev)
{
(void) ctx;
(void) ev;
verto_break(ctx);
}
static enum OperationReturnCode connection_on_error(int rc, void* unused_a, void* connection)
{
(void)(unused_a);
verto_break(((ldap_connection_ctx_t*)connection)->base);
error("Unable to perform operation!\n");
exit(EXIT_FAILURE);
return RETURN_CODE_SUCCESS;
}
static void connection_on_update(verto_ctx *ctx, verto_ev *ev)
{
(void)(ctx);
struct ldap_connection_ctx_t* connection = verto_get_private(ev);
if (connection->state_machine->state == LDAP_CONNECTION_STATE_RUN)
{
verto_del(ev);
search(connection, "dc=domain,dc=alt", LDAP_SCOPE_SUBTREE,
"(objectClass=*)", LDAP_DIRECTORY_ATTRS, 0, NULL);
}
if (connection->state_machine->state == LDAP_CONNECTION_STATE_ERROR)
{
verto_break(ctx);
error("Error encountered during bind!\n");
}
}
const char *argp_program_version = "1.0.0";
const char *argp_program_bug_address = "https://bugzilla.altlinux.org";
static char doc[] = "Libdomain get RootDSE sample.";
static char args_doc[] = "[HOSTNAME] [BINDDN] <USERNAME> <PASSWORD> <USE_SASL>";
static struct argp_option options[] =
{
{ "host", 'h', "HOST", 0, "Host. Use protocol://adress:port format e.g. ldap://dc.example.org:389."},
{ "user", 'u', "USER", 0, "User name."},
{ "pass", 'w', "PASS", 0, "Password."},
{ "sasl", 's', "SASL", 0, "Whether or not use SASL bind."},
{ "bind", 'b', "BIND", 0, "Bind dn. For example: \"dc=example,dc=org\"."},
{ 0 }
};
struct arguments
{
char* hostname;
char* password;
char* username;
char* bind_dn;
bool useSasl;
};
static error_t parse_opt(int key, char *arg, struct argp_state *state)
{
struct arguments *arguments = state->input;
switch (key)
{
case 'h':
arguments->hostname = arg;
break;
case 'u':
arguments->username = arg;
break;
case 'w':
arguments->password = arg;
break;
case 's':
arguments->useSasl = true;
break;
case 'b':
arguments->bind_dn = arg;
break;
case ARGP_KEY_ARG:
return 0;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
static struct argp argp = { options, parse_opt, args_doc, doc, NULL, NULL, NULL };
int main(int argc, char **argv)
{
TALLOC_CTX* talloc_ctx = talloc_new(NULL);
struct arguments arguments;
arguments.hostname = NULL;
arguments.username = NULL;
arguments.password = NULL;
arguments.bind_dn = NULL;
arguments.useSasl = false;
argp_parse(&argp, argc, argv, 0, 0, &arguments);
if (arguments.hostname == NULL)
{
printf("Error: Missing required argument --host\n");
exit(EXIT_FAILURE);
}
if (arguments.bind_dn == NULL)
{
printf("Error: Missing required argument --bind\n");
exit(EXIT_FAILURE);
}
const int update_interval = 1000;
ld_config_t *config = NULL;
config = ld_create_config(talloc_ctx, arguments.hostname, 0, LDAP_VERSION3, "dc=domain,dc=alt",
arguments.username, arguments.password, !arguments.useSasl, false, arguments.useSasl, false,
update_interval, "", "", "");
const int exit_time = 10000;
LDHandle *handle = NULL;
ld_init(&handle, config);
ld_install_default_handlers(handle);
ld_install_handler(handle, connection_on_update, update_interval);
ld_install_handler(handle, exit_callback, exit_time);
ld_install_error_handler(handle, connection_on_error);
ld_exec(handle);
ld_free(handle);
talloc_free(talloc_ctx);
return 0;
}
Структура программы
Функции обработки событий:
* exit_callback — вызывает событие завершения программы;
* connection_on_error — обрабатывает ошибки во время операций LDAP;
* connection_on_update — обрабатывает обновления состояния соединения и обрабатывает ошибки во время установки соединения.
Обработка опций:
* parse_opt — разбирает опции командной строки с использованием библиотеки argp.
Основная функция:
1. При помощи функции talloc_new создаётся новый контекст talloc.
2. Инициализируется структура arguments, которая служит для хранения аргументов командной строки.
3. При помощи функции argp_parse производится обработка аргументов командной строки.
4. Происходит проверка обязательных аргументов host и bind_dn, если эти аргументы не найдены программа завершается.
5. Создаётся структура для конфигурации для подключения к серверу LDAP, при помощи функции ld_config.
6. Инициализируется основной указатель библиотеки handle при помощи функции ld_init.
7. Устанавливаются стандартные обработчики событий ld_install_default_handlers(handle).
8. Устанавливается обработчик с основной логикой программы: ld_install_handler(handle, connection_on_update, update_interval).
9. Устанавливается обработчик, который выключает программу через 10 секунд: ld_install_handler(handle, exit_callback, exit_time).
10. Устанавливаются обработчики ошибок.
11. Запуск основного цикла событий с помощью ld_exec.
12. Выполняется поиск.
13. Очищаются ресурсы при помощи функций: ld_free(handle) и talloc_free(talloc_ctx).
Обработка ошибок
* Ошибки, такие как невозможность выполнения операций LDAP, приводят к завершению программы с соответствующим сообщением об ошибке.
Обработка ошибок реализована в функции connection_on_error. Однако обработка ошибок соединения происходит в функции connection_on_update.
Примечания
* Программа выполняет LDAP-поиск при изменении состояния соединения на LDAP_CONNECTION_STATE_RUN. Объекты для поиска задаются в переменной LDAP_DIRECTORY_ATTRS.
Компиляция
Для компиляции программы необходимо установить библиотеку libdomain:
# apt-get install libdomain-devel libconfig-devel
Далее следует склонировать пример:
$ git clone https://github.com/libdomain/libdomain-c-sample
Команда компиляции:
$ mkdir build && cd build && cmake .. && make -j `nproc`