Автор Тема: Аутентификация в ALTLinux с помощью pam_authenticate  (Прочитано 388 раз)

Оффлайн orontin

  • Начинающий
  • *
  • Сообщений: 12
Всем привет.

Имеется следующий код:
#include <errno.h>
#include <libgen.h>
#include <malloc.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <termio.h>
#include <security/pam_appl.h>
#include <sys/types.h>
#include <pwd.h>

static int ctl_c; /* was the conversation interrupted? */

static void interrupt(int x) {
    ctl_c = 1;
}

static char *getinput(int noecho) {
    struct termio tty;
    unsigned short tty_flags;
    char input[PAM_MAX_RESP_SIZE];
    int c;
    int i = 0;
    void (*sig)(int);

    ctl_c = 0;
    sig = signal(SIGINT, interrupt);
    if (noecho) {
        (void) ioctl(fileno(stdin), TCGETA, &tty);
        tty_flags = tty.c_lflag;
        tty.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
        (void) ioctl(fileno(stdin), TCSETAF, &tty);
    }

    flockfile(stdin);
    while (ctl_c == 0 && (c = getchar_unlocked()) != '\n' && c != '\r' && c != EOF) {
        if (i < PAM_MAX_RESP_SIZE) {
            input[i++] = (char) c;
        }
    }

    funlockfile(stdin);
    input[i] = '\0';

    if (noecho) {
        tty.c_lflag = tty_flags;
        (void) ioctl(fileno(stdin), TCSETAW, &tty);
        (void) fputc('\n', stdout);
    }

    (void) signal(SIGINT, sig);
    if (ctl_c == 1) {
        (void) kill(getpid(), SIGINT);
    }

    return (strdup(input));
}

static void free_resp(int num_msg, struct pam_response *pr) {
    int i;
    struct pam_response *r = pr;

    if (pr == NULL)
        return;

    for (i = 0; i < num_msg; i++, r++) {
        if (r->resp) {
            bzero(r->resp, strlen(r->resp));
            free(r->resp);
            r->resp = NULL;
        }
    }
    free(pr);
}

int pam_tty_conv(int num_msg, const pam_message **mess, pam_response **resp, void *my_data) {
    struct pam_message *m = (struct pam_message*)*mess;
    struct pam_response *r;
    int i;

    if (num_msg <= 0 || num_msg >= PAM_MAX_NUM_MSG) {
        (void) fprintf(stderr, "bad number of messages %d <= 0 || >= %d\n", num_msg, PAM_MAX_NUM_MSG);
        *resp = NULL;
        return (PAM_CONV_ERR);
    }

    if ((*resp = r = (struct pam_response*)calloc(num_msg, sizeof(struct pam_response))) == NULL) {
        return (PAM_BUF_ERR);
    }

    errno = 0;

    for (i = 0; i < num_msg; i++) {
        int echo_off;

        if (m->msg == NULL) {
            (void) fprintf(stderr, "message[%d]: %d/NULL\n", i, m->msg_style);
            goto err;
        }

        r->resp = NULL;
        r->resp_retcode = 0;
        echo_off = 0;
        switch (m->msg_style) {
            case PAM_PROMPT_ECHO_OFF:
                echo_off = 1;

            case PAM_PROMPT_ECHO_ON:
                (void) fputs(m->msg, stdout);

                r->resp = strdup("password");
                break;

            case PAM_ERROR_MSG:
                (void) fputs(m->msg, stderr);
                (void) fputc('\n', stderr);
                break;

            case PAM_TEXT_INFO:
                (void) fputs(m->msg, stdout);
                (void) fputc('\n', stdout);
                break;

            default:
                (void) fprintf(stderr, "message[%d]: unknown type %d/val=\"%s\"\n", i, m->msg_style, m->msg);
                goto err;
        }
        if (errno == EINTR) {
            goto err;
        }

        m++;
        r++;
    }
    return (PAM_SUCCESS);

err:
    free_resp(i, r);
    *resp = NULL;
    return (PAM_CONV_ERR);
}

/* Disable keyboard interrupts (Ctrl-C, Ctrl-Z, Ctrl-\) */
static void
disable_kbd_signals(void) {
    (void) signal(SIGINT, SIG_IGN);
    (void) signal(SIGTSTP, SIG_IGN);
    (void) signal(SIGQUIT, SIG_IGN);
}

/* Terminate current user session, i.e., logout */
static void
logout() {
    pid_t pgroup = getpgrp();

    (void) signal(SIGTERM, SIG_IGN);
    (void) fprintf(stderr, "Sorry, your session can't be restored.\n");
    (void) fprintf(stderr, "Press return to terminate this session.\n");
    (void) getchar();
    (void) kill(-pgroup, SIGTERM);
    (void) sleep(2);
    (void) kill(-pgroup, SIGKILL);
    exit(-1);
}

int main(int argc, char *argv[]) {
    struct pam_conv conv = {pam_tty_conv, NULL};
    pam_handle_t *pamh;
    struct passwd *pw;
    int err;

    disable_kbd_signals();
    if ((pw = getpwuid(getuid())) == NULL) {
        (void) fprintf(stderr, "plock: Can't get username: %s\n", strerror(errno));
        exit(1);
    }

    err = pam_start("system-auth", pw->pw_name, &conv, &pamh);
    if (err != PAM_SUCCESS) {
        (void) fprintf(stderr, "plock: pam_start failed: %s\n", pam_strerror(pamh, err));
        exit(1);
    }

    do {
        (void) fprintf(stderr, "Terminal locked for %s. ", pw->pw_name);
        err = pam_authenticate(pamh, 0);
        if (err == PAM_USER_UNKNOWN) {
            logout();
        } else if (err != PAM_SUCCESS) {
            (void) fprintf(stderr, "Invalid password.\n");
        }
    } while (err != PAM_SUCCESS);

    switch (err = pam_acct_mgmt(pamh, 0)) {
        case PAM_SUCCESS:
            break;
        case PAM_USER_UNKNOWN:
        case PAM_ACCT_EXPIRED:
            logout();
            break;
        case PAM_NEW_AUTHTOK_REQD:
            do {
                err = pam_chauthtok(pamh, 0);
            } while (err == PAM_AUTHTOK_ERR);
            if (err != PAM_SUCCESS) {
                logout();
            }
            break;
        default:
            logout();
    }

    if ((err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) {
        logout();
    }

    if ((err = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
        logout();
    }

    if ((err = pam_close_session(pamh, 0)) != PAM_SUCCESS) {
        logout();
    }

    if ((err = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) {
        logout();
    }

    if (pam_setcred(pamh, PAM_REFRESH_CRED) != PAM_SUCCESS) {
        logout();
    }

    (void) pam_end(pamh, 0);
    return (0);
}

Суть этой небольшой программки - проверка аутентификации - правильно ли введен пароль для пользователя который запускает программку.

На Астра и RedOS - данный код работает прекрасно.
Но, на ALT он постоянно падает с ошибкой pam_tcb(system-auth:auth): Authentication failed for user from user(uid=500)
Единственные мои подозрения это на схему tcb.

Возможно на ALT необходимо использовать что-то особенное?

Машина ALT 9.2 - была специально создана, чтобы проверить этот кусочек кода на работоспособность.
« Последнее редактирование: 31.08.2022 18:01:35 от orontin »

Оффлайн zerg

  • ненужная строка
  • alt linux team
  • ***
  • Сообщений: 2 486
  • ненужная строка
    • Найдётся всё
Программа, использующая pam_tcb не от root вынуждена иметь SGID на chkpwd, иначе не сработает.
Убрать этот мусор можно переключателем: Не показывать подписи других пользователей.

Оффлайн zerg

  • ненужная строка
  • alt linux team
  • ***
  • Сообщений: 2 486
  • ненужная строка
    • Найдётся всё
> правильно ли введен пароль для пользователя который запускает программку
Возможно, это получится сделать через polkit, если SGID недопустим.

P.S.
Ну и можете высказаться на https://bugzilla.altlinux.org/43627
Убрать этот мусор можно переключателем: Не показывать подписи других пользователей.

Оффлайн orontin

  • Начинающий
  • *
  • Сообщений: 12
SGID

Спасибо!
Это решило мою проблему.