check_password_caps = cap_dac_read_search+p
$ ./check_password_caps
Username: mtk
Password:
Successfully authenticated: UID=1000
Листинг 39.1. Программа для аутентификации пользователей с поддержкой системы возможностей
cap/check_password_caps.c
#define _BSD_SOURCE /* Получаем объявление getpass()
из заголовочного файла
#define _XOPEN_SOURCE /* Получаем объявление crypt()
из заголовочного файла
#include
#include
#include
#include
#include
#include "tlpi_hdr.h"
/* Меняем параметры возможностей в действующем наборе вызывающего процесса */
static int
modifyCap(int capability, int setting)
{
cap_t caps;
cap_value_t capList[1];
/* Получаем текущие возможности вызывающего процесса */
caps = cap_get_proc();
if (caps == NULL)
return –1;
/* Меняем параметры 'capability' в действующем наборе 'caps'.
Третий аргумент, 1 — это количество элементов в массиве 'capList'. */
capList[0] = capability;
if (cap_set_flag(caps, CAP_EFFECTIVE, 1, capList, setting) == –1) {
cap_free(caps);
return –1;
}
/* Возвращаем ядру измененные наборы возможностей, чтобы они
вступили в силу для вызывающего процесса */
if (cap_set_proc(caps) == –1) {
cap_free(caps);
return –1;
}
/* Удаляем структуру, выделенную интерфейсом libcap */
if (cap_free(caps) == –1)
return –1;
return 0;
}
static int /* Включаем возможность в действующий набор вызывающего процесса */
raiseCap(int capability)
{
return modifyCap(capability, CAP_SET);
}
/* Аналогичная функция dropCap() (не нужна в этой программе)
может быть определена как modifyCap(capability, CAP_CLEAR); */
static int /* Удаляем все возможности из всех наборов */
dropAllCaps(void)
{
cap_t empty;
int s;
empty = cap_init();
if (empty == NULL)
return –1;
s = cap_set_proc(empty);
if (cap_free(empty) == –1)
return –1;
return s;
}
int
main(int argc, char *argv[])
{
char *username, *password, *encrypted, *p;
struct passwd *pwd;
struct spwd *spwd;
Boolean authOk;
size_t len;
long lnmax;
lnmax = sysconf(_SC_LOGIN_NAME_MAX);
if (lnmax == –1) /* Если невозможно определить ограничение, */
lnmax = 256; /* берем значение наугад */
username = malloc(lnmax);
if (username == NULL)
errExit("malloc");
printf("Username: ");
fflush(stdout);
if (fgets(username, lnmax, stdin) == NULL)
exit(EXIT_FAILURE); /* Выходим при обнаружении символа EOF */
len = strlen(username);
if (username[len — 1] == '\n')
username[len — 1] = '\0'; /* Удаляем символ '\n' в конце */
pwd = getpwnam(username);
if (pwd == NULL)
fatal("couldn't get password record");
/* Включаем возможность CAP_DAC_READ_SEARCH только на период, когда она нам нужна */
if (raiseCap(CAP_DAC_READ_SEARCH) == –1)
fatal("raiseCap() failed");
spwd = getspnam(username);
if (spwd == NULL && errno == EACCES)
fatal("no permission to read shadow password file");
/* На этом этапе нам больше не нужны никакие возможности, поэтому очищаем все наборы */
if (dropAllCaps() == –1)
fatal("dropAllCaps() failed");
if (spwd!= NULL) /* Если запись в файле с паролями существует, */
pwd->pw_passwd = spwd->sp_pwdp; /* используем пароль */
password = getpass("Password: ");
/* Шифруем пароль и сразу же удаляем незашифрованную версию */
encrypted = crypt(password, pwd->pw_passwd);
for (p = password; *p!= '\0';)
*p++ = '\0';
if (encrypted == NULL)
errExit("crypt");
authOk = strcmp(encrypted, pwd->pw_passwd) == 0;
if (!authOk) {
printf("Incorrect password\n");
exit(EXIT_FAILURE);
}
printf("Successfully authenticated: UID=%ld\n", (long) pwd->pw_uid);
/* Теперь выполняем аутентификацию… */
exit(EXIT_SUCCESS);
}
cap/check_password_caps.c
Ранее были описаны различные механизмы, благодаря которым привилегии пользователя с идентификатором 0 (администратор) зависят от системы возможностей.
• Когда процесс с хотя бы одним нулевым пользовательским идентификатором присваивает всем своим UID ненулевое значение, его разрешенный и действующий наборы возможностей сбрасываются (см. раздел 39.6).
• Если поменять действующий идентификатор пользователя, который изначально был равен 0, на ненулевое значение, процесс потеряет все свои действующие возможности. При обратном действии разрешенные возможности копируются в действующий набор. Похожая процедура выполняется для подмножества возможностей, когда UID файловой системы переключается между 0 и ненулевым значением (см. раздел 39.6).