pam會話函數詳解


摘自:https://blog.csdn.net/wzsy/article/details/37725375

會話函數也叫轉換函數,是服務(如sshd,vsftpd)中的函數。Pam模塊可以取到這個函數並且使用這個函數。

        會話函數的作用就是處理與用戶之間的會話。就是說,可以向用戶、服務或設備顯示消息,並從中收集輸入內容。會話可采用多種形式,例如,文本終端設備中常見的”Login:”提示

此部分主要包括會話函數的注冊、實現、獲得、使用。其中注冊、實現在服務(sshd服務)中完成。獲得、使用在pam模塊中完成。

1.1 會話函數的注冊

        應用服務程序(如sshd)調用 pam_start函數發起PAM會話時,將對會話函數進行注冊。函數原型:

int pam_start(const char *service_name, const char *user, const struct pam_conv *pam_conversation, pam_handle_t **pamh); 

參數const struct pam_conv *pam_conversation即為要注冊的會話函數。

1.2 會話函數的實現

下面是sshd服務源碼中的會話函數:

 

static int
sshpam_thread_conv(int n, sshpam_const struct pam_message **msg,
    struct pam_response **resp, void *data)
{
    Buffer buffer;
    struct pam_ctxt *ctxt;
    struct pam_response *reply;
    int i;
    debug3("PAM: %s entering, %d messages", __func__, n);
    *resp = NULL;
    if (data == NULL) {
        error("PAM: conversation function passed a null context");
        return (PAM_CONV_ERR);
    }
    ctxt = data;
    if (n <= 0 || n > PAM_MAX_NUM_MSG)
        return (PAM_CONV_ERR);
    if ((reply = malloc(n * sizeof(*reply))) == NULL)
        return (PAM_CONV_ERR);
    memset(reply, 0, n * sizeof(*reply));
    buffer_init(&buffer);
    for (i = 0; i < n; ++i) {
        
        //會話函數的核心就是下面的代碼
        switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
        case PAM_PROMPT_ECHO_OFF:    //用於取得密碼,不回顯
            buffer_put_cstring(&buffer,
             PAM_MSG_MEMBER(msg, i, msg));
            //終端顯示提示,如 Password:
            if (ssh_msg_send(ctxt->pam_csock,
             PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
                goto fail;
            //取得密碼
            if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1)
                goto fail;
            if (buffer_get_char(&buffer) != PAM_AUTHTOK)
                goto fail;
            //密碼存在reply[i].resp中
            reply[i].resp = buffer_get_string(&buffer, NULL);
            break;
        case PAM_PROMPT_ECHO_ON:        //用於取得用戶名,回顯
            buffer_put_cstring(&buffer,
             PAM_MSG_MEMBER(msg, i, msg));
            //終端顯示提示,如 Login:
            if (ssh_msg_send(ctxt->pam_csock,
             PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
                goto fail;
            //取得用戶名
            if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1)
                goto fail;
            if (buffer_get_char(&buffer) != PAM_AUTHTOK)
                goto fail;
            //用戶名存在reply[i].resp中
            reply[i].resp = buffer_get_string(&buffer, NULL);
            break;
        case PAM_ERROR_MSG:        //錯誤信息顯示
            buffer_put_cstring(&buffer,
             PAM_MSG_MEMBER(msg, i, msg));
            if (ssh_msg_send(ctxt->pam_csock,
             PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
                goto fail;
            break;
        case PAM_TEXT_INFO:        //信息顯示
            buffer_put_cstring(&buffer,
             PAM_MSG_MEMBER(msg, i, msg));
            if (ssh_msg_send(ctxt->pam_csock,
             PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
                goto fail;
            break;
        default:
            goto fail;
        }
        buffer_clear(&buffer);
    }
    buffer_free(&buffer);
    *resp = reply;
    return (PAM_SUCCESS);
 fail:
    for(i = 0; i < n; i++) {
        if (reply[i].resp != NULL)
            xfree(reply[i].resp);
    }
    xfree(reply);
    buffer_free(&buffer);
    return (PAM_CONV_ERR);
 }
 

 

 

1.3 會話函數的獲得

       Pam模塊與終端通話,即顯示信息,取得用戶名、密碼,都需要使用會話函數才能完成。

在pam模塊中,通過下面方法取得會話函數(如sshd服務的會話函數)

       pam_get_item(pamh, PAM_CONV, (const void **) &conversation);

       conversation是包含會話函數的結構體

1.4 會話函數的使用

     上面取得會話函數后,就可以通過會話函數取得密碼、用戶名,以及顯示信息了。

    r 獲取用戶名:

 

        message.msg = "\nPlease input authen ID: ";
        int retval;
        message.msg_style = PAM_PROMPT_ECHO_ON; //設置回顯
        retval = conversation->conv(1, &pmessage, &res, conversation->appdata_ptr);//會話函數
        if (retval != PAM_SUCCESS)
            LOGOUT("pam_conv error %d (%s).", retval, pam_strerror(pamh, retval));
        strcpy(user, res->resp);        //保存用戶名

 

r 獲取密碼:

 

        message.msg = "Enter fixed password: ";
        int retval;
        message.msg_style = PAM_PROMPT_ECHO_OFF; //設置不回顯
        retval = conversation->conv(1, &pmessage, &res, conversation->appdata_ptr);//會話函數
        if (retval != PAM_SUCCESS)
            LOGOUT("error %d (%s).", retval, pam_strerror(pamh, retval));
        strcpy(passwd, res->resp);

 

 

    pam配置好后,通過telnet登錄系統,上面程序的顯示結果為:
    Please input authen ID: 

    Enter fixed password:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM