3.2. 응용에게 기대하는 것

3.2.1. 대화 함수

#include <security/pam_appl.h>
struct pam_message {
    int msg_style;
    const char *msg;
};

struct pam_response {
    char *resp;
    int resp_retcode;
};

struct pam_conv {
    int (*conv)(int num_msg, const struct pam_message **msg,
                struct pam_response **resp, void *appdata_ptr);
    void *appdata_ptr;
};
  

3.2.1.1. 설명

PAM 라이브러리에선 응용에서 정의한 콜백을 이용해 응용과 적재된 모듈이 직접 소통할 수 있게 한다. 트랜잭션 시작 때 pam_start(3)에 주는 struct pam_conv로 콜백을 지정한다.

모듈에서 해당 conv() 함수를 호출할 때 그 구조체의 두 번째 항목을 appdata_ptr 인자에 설정한다.

conv() 호출의 나머지 인자들은 모듈과 응용 사이에 주고받는 정보에 대한 것이다. 말하자면 num_msg는 포인터의 배열인 msg의 길이를 담는다. 성공 반환 시 포인터 resp가 pam_response 구조체의 배열을 가리키는데, 그 구조체들은 응용에서 제공한 텍스트를 담는다. 그 구조체의 resp_retcode 멤버는 쓰지 않으며 0으로 설정해야 한다. 그 배열과 응답들을 free(3)로 해제하는 건 호출자의 책임이다. *resp가 포인터의 배열이 아니라 struct pam_response 배열이라는 점에 유의하자.

응답의 개수는 언제나 대화 함수 인자 num_msg와 같다. 따라서 대화 함수 호출 후마다 응답 배열이 free(3) 돼야 한다. 응답들의 인덱스는 pam_message 배열 프롬프트의 인덱스와 대응한다.

실패 시 대화 함수는 할당한 자원이 있으면 모두 해제한 후 미리 규정된 PAM 오류 코드들 중 하나를 반환해야 한다.

각 메시지는 네 가지 타입 중 하나이며, struct pam_messagemsg_style 멤버에 지정돼 있다.

PAM_PROMPT_ECHO_OFF

텍스트 반향 없이 문자열 얻기.

PAM_PROMPT_ECHO_ON

텍스트 반향하면서 문자열 얻기.

PAM_ERROR_MSG

오류 메시지 표시하기.

PAM_TEXT_INFO

어떤 텍스트 표시하기.

메시지가 배열로 돼 있으므로 모듈에서 한 번의 호출로 여러 가지를 응용으로 전달하는 게 가능해진다. 응용 입장에서도 관련 항목들이 한번에 오는 게 편할 수 있다. 그 경우 창 형태 응용에서 양식 하나로 여러 메시지/프롬프트를 한꺼번에 표시할 수 있다.

여담으로, Linux-PAM에서 대화 함수 인자 const struct pam_message **msg를 다루는 방식이 솔라리스의 PAM과 (또 그에 기반한 HP/UX 등과) 차이가 있다는 점을 언급해 둬야겠다. Linux-PAM은 msg 인자를 프로토타입 const struct pam_message *msg[]와 완전히 동등하게 해석한다. (다들 아는 main() 함수의 argv 인자에 흔히 쓰는 프로토타입이 char **argv와 char *argv[]인 것과 같은 식이다.) 요컨데 Linux-PAM에서는 msg 인자를 읽기 전용 'struct pam_message' 포인터 num_msg 개짜리 배열에 대한 포인터로 해석한다. 솔라리스 PAM 구현에서는 이 인자를 pam_message 구조체 num_msg개짜리 배열에 대한 포인터에 대한 포인터로 해석한다. 대부분 모듈 응용 개발자에게는 (아마도) 다행스럽게도 num_msg의 값이 1일 때 두 정의는 완전히 동등하다. 그러다 별 생각 없이 그 수를 2개로 올리면 예상치 않은 호환성 문제가 발생한다.

어느 쪽이 바람직한가는 제쳐 두고, 모듈 작성자가 두 가지 PAM 구현 모두와 소스 수준 호환성을 유지하기 위한 방법으로 두 가지가 있다.

  • 절대 num_msg를 1보다 크게 해서 대화 함수를 호출하지 않기.

  • msg를 이중 참조 구조로 만들어서 두 가지 대화 함수 모두 메시지를 찾아낼 수 있게 하기. 즉 다음처럼 만들기:

           msg[n] = & (( *msg )[n])
           

3.2.1.2. 반환 값

PAM_BUF_ERR

메모리 버퍼 오류.

PAM_CONV_ERR

대화 실패. 응용에선 *resp를 설정하지 않아야 한다.

PAM_SUCCESS

성공.