2011-05-06 5 views
8

유선을 통해 비동기 적으로 사용자 이름/비밀번호 요청을받는 기존 앱이 있습니다. 내가 이미 사용자 이름과 암호를 변수로 저장했기 때문에 Linux에서 PAM으로 인증하는 가장 좋은 방법은 무엇입니까 (Debian 6)?레거시 애플리케이션의 PAM 인증

나는 자신의 대화 기능을 쓰려고했지만, 암호를 얻는 가장 좋은 방법은 확실치 않습니다. 나는 그것을 appdata에 저장하고 pam_conv 구조체를 참조하는 것으로 생각했지만, 어떻게하는지에 대한 문서는 거의 없다.

대화 기능이 과도하게 사용되지 않으면 서 사용자를 인증하는 간단한 방법이 있습니까? 나는 pam_set_data를 성공적으로 사용할 수 없으며 그것이 적절하다고 확신하지 못한다.

여기에 내가 뭘 내용은 다음과 같습니다 대화 기능에서

user = guiMessage->username; 
pass = guiMessage->password; 

pam_handle_t* pamh = NULL; 
int   pam_ret; 
struct pam_conv conv = { 
    my_conv, 
    NULL 
}; 

pam_start("nxs_login", user, &conv, &pamh); 
pam_ret = pam_authenticate(pamh, 0); 

if (pam_ret == PAM_SUCCESS) 
    permissions = 0xff; 

pam_end(pamh, pam_ret); 

그리고 초기 시도의 결과 (암호가 테스트를 위해 하드 코딩) :

int 
my_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *data) 
{ 
    struct pam_response *aresp; 

    if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG) 
    return (PAM_CONV_ERR); 
    if ((aresp = (pam_response*)calloc(num_msg, sizeof *aresp)) == NULL) 
    return (PAM_BUF_ERR); 
    aresp[0].resp_retcode = 0; 
    aresp[0].resp = strdup("mypassword"); 

    *resp = aresp; 
    return (PAM_SUCCESS); 
} 

어떤 도움을 주시면 감사하겠습니다. 고맙습니다!

답변

12

이것이 내가 한 일입니다. 세 개의 별표가 표시된 주석을보십시오. 표준 정보 (예 : 암호) PAM에 대한 전달

#include <stdlib.h> 
#include <iostream> 
#include <fstream> 
#include <security/pam_appl.h> 
#include <unistd.h> 

// To build this: 
// g++ test.cpp -lpam -o test 

struct pam_response *reply; 

//function used to get user input 
int function_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) 
{ 
    *resp = reply; 
    return PAM_SUCCESS; 
} 

int main(int argc, char** argv) 
{ 
    if(argc != 2) { 
     fprintf(stderr, "Usage: check_user <username>\n"); 
     exit(1); 
    } 
    const char *username; 
    username = argv[1]; 

    const struct pam_conv local_conversation = { function_conversation, NULL }; 
    pam_handle_t *local_auth_handle = NULL; // this gets set by pam_start 

    int retval; 

    // local_auth_handle gets set based on the service 
    retval = pam_start("common-auth", username, &local_conversation, &local_auth_handle); 

    if (retval != PAM_SUCCESS) 
    { 
    std::cout << "pam_start returned " << retval << std::endl; 
    exit(retval); 
    } 

    reply = (struct pam_response *)malloc(sizeof(struct pam_response)); 

    // *** Get the password by any method, or maybe it was passed into this function. 
    reply[0].resp = getpass("Password: "); 
    reply[0].resp_retcode = 0; 

    retval = pam_authenticate(local_auth_handle, 0); 

    if (retval != PAM_SUCCESS) 
    { 
    if (retval == PAM_AUTH_ERR) 
    { 
     std::cout << "Authentication failure." << std::endl; 
    } 
    else 
    { 
     std::cout << "pam_authenticate returned " << retval << std::endl; 
    } 
    exit(retval); 
    } 

    std::cout << "Authenticated." << std::endl; 

    retval = pam_end(local_auth_handle, retval); 

    if (retval != PAM_SUCCESS) 
    { 
    std::cout << "pam_end returned " << retval << std::endl; 
    exit(retval); 
    } 

    return retval; 
} 
+0

고마워요! 그리고 여기에서 나는 대화 기능 대신에 그저 응답을 우회하고 응답하는 대신 대화 할 수있는 방법을 찾고자했습니다. –

+0

이것은 '루트'(단지 '루트', 다른 모든 사용자는 정식으로 인증 됨)에서 작동하지 않습니다. 그게 버그 야? – alexandernst

+0

잘 모르겠습니다. 나는 뿌리를 내리지 않았다. 정기적으로 루트 암호를 사용해야하는 경우에는 아마 잘못된 것입니다. – Fantius

1

방법은를 pam_set_item와 PAM 핸들 (를 pam_set_item에 대한 매뉴얼 페이지를 참조하십시오)에서 설정 한 변수를 사용하는 것입니다.

응용 프로그램이 나중에 pam_stack에 사용해야하는 모든 것을 설정할 수 있습니다.

pam_handle_t* handle = NULL; 
pam_start("common-auth", username, NULL, &handle); 
pam_set_item(handle, PAM_AUTHTOK, password); 

이 암호를 만들 것입니다 : 당신이 pam_stack에 암호를 설정하고 싶은 경우에 당신은 바로 아래 의사 코드와 유사한 스택에 PAM_AUTHTOK 변수를 설정하여 보았 듯이 pam_start()를 호출 한 후 그렇게 할 수 있어야한다 스택을 사용할 수있는 모든 모듈에서 사용할 수 있지만 일반적으로 서비스의 pam_configuration에서 표준 use_first_pass 또는 try_first_pass 옵션을 설정하여 모듈에 사용하도록 지시해야합니다 (이 경우 /etc/pam.d/). 공통 인증).

표준 pam_unix 모듈은 try_first_pass를 지원하므로 시스템의 pam 구성 (pam_unix의 줄 끝 부분)에 pam 구성에 추가하면 안됩니다.

이 작업을 수행 한 후 common-auth 서비스에서 호출 된 pam_authenticate()을 호출하면 암호를 선택하고 함께 사용하면됩니다.

use_first_pass와 try_first_pass의 차이점에 대한 작은 메모 : 모듈 (이 경우 pam_unix)은 pam_stack에서 암호를 시도하지만 둘 다 암호/AUTHTOK를 사용할 수없는 경우에는 동작이 다릅니다. 누락 된 경우 use_first_pass는 실패하고 try_first_pass는 모듈이 암호를 요구할 수있게합니다.

+0

http://pubs.opengroup.org/onlinepubs/8329799/chap4.htm#tagcjh_05_02_01_01에서는'PAM_AUTHTOK'는 "PAM 모듈에만 _ 가능하며 응용 프로그램에는 _ 사용할 수 없음"이라고 언급합니다. 그래서 당신은 당신이 묘사 한 것을 할 수 없어야합니다. 작동 여부를 확인 했습니까? 어쩌면 휴대용이 아닌가? –

+0

다시'pam_set_item' 문서 (http://pubs.opengroup.org/onlinepubs/8329799/pam_set_item.htm#tagmref_pam_set_item)는'PAM_AUTHOK'를 제공하는 동안 그 조건을 반복하지 않는 것 같습니다. –

0

Fantius의 솔루션은 나를 위해, 심지어 루트로 작동했습니다.

나는 원래 John 솔루션을 선택했다. 더 깨끗하고 대화 기능이없는 PAM 변수를 사용했기 때문에 (실제로 여기에는 그 필요성이 없다.)하지만 작동하지 않았고 작동하지 않을 것이다. Adam Badura가 두 게시물에서 언급했듯이 PAM에는 PAM_AUTHTOK의 직접 설정을 방지하는 내부 검사가 있습니다.

John의 해결 방법은 here과 유사하게 동작합니다 (여기서 pam_conv 변수를 선언했지만 정의하지 않아도 암호 값은 로그인 할 수 있습니다).

사용자는 malloc의 위치를 ​​알고 있어야합니다. malloc은 응용 프로그램에 따라 다를 수 있으므로 (위의 코드는 다른 테스트/템플릿보다 더 많이 사용합니다).

+0

이 질문에 대한 답변을 제공하지 않습니다. 충분한 [평판] (https://stackoverflow.com/help/whats-reputation)이 있으면 [모든 게시물에 주석 달기] (https://stackoverflow.com/help/privileges/comment) 할 수 있습니다. 대신, [질문자의 설명이 필요없는 답변을 제공하십시오] (https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can- i-do- 대신). - [검토 중] (리뷰/저품절 게시물/18803902) – Umair

+0

답변으로 '감사합니다'를 추가하지 마십시오. 대신 도움이되는 답변에 투표하십시오. - [리뷰에서] (리뷰/저품절 포스트/18803902) – Graham

+0

내가 이런 종류의 사이트에서 캐주얼 한 이유를 생각 나게 해줘서 고마워.) 사과! – gagan