• 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 = "
    Please 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:

  • 相关阅读:
    hdu 4504(背包最优方案数)
    hdu 4508(完全背包)
    hdu 4509(memset标记)
    hdu 2188
    hdu 2141(二分)
    《算术探索》(高斯) 第一篇(第112目) 总结
    数论概论(Joseph H.Silverman) 定理39.1 连分数的递归公式
    数论概论(Joseph H.Silverman) 定理39.2 连分数相邻收敛项之差定理
    《算术探索》(高斯) 第一篇(第112目) 总结
    有理数的小数表示若无限,则必为无限循环的
  • 原文地址:https://www.cnblogs.com/LiuYanYGZ/p/12669289.html
Copyright © 2020-2023  润新知