Pluggable Authentication Modules
Prev |  | Next

# C. Sample PAM Conversation Function

The conversation function presented below is a greatly simplified version of OpenPAM's openpam_ttyconv(3). It is fully functional, and should give the reader a good idea of how a conversation function should behave, but it is far too simple for real-world use. Even if you are not using OpenPAM, feel free to download the source code and adapt openpam_ttyconv(3) to your uses; we believe it to be as robust as a tty-oriented conversation function can reasonably get.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>

    #include <security/pam_appl.h>

    int
    converse(int n, const struct pam_message **msg,
        struct pam_response **resp, void *data)
    {
        struct pam_response *aresp;
        char buf[PAM_MAX_RESP_SIZE];
        int i;

        data = data;
        if (n <= 0 || n > PAM_MAX_NUM_MSG)
            return (PAM_CONV_ERR);
        if ((aresp = calloc(n, sizeof *aresp)) == NULL)
            return (PAM_BUF_ERR);
        for (i = 0; i < n; ++i) {
            aresp[i].resp_retcode = 0;
            aresp[i].resp = NULL;
            switch (msg[i]->msg_style) {
            case PAM_PROMPT_ECHO_OFF:
                aresp[i].resp = strdup(getpass(msg[i]->msg));
                if (aresp[i].resp == NULL)
                    goto fail;
                break;
            case PAM_PROMPT_ECHO_ON:
                fputs(msg[i]->msg, stderr);
                if (fgets(buf, sizeof buf, stdin) == NULL)
                    goto fail;
                aresp[i].resp = strdup(buf);
                if (aresp[i].resp == NULL)
                    goto fail;
                break;
            case PAM_ERROR_MSG:
                fputs(msg[i]->msg, stderr);
                if (strlen(msg[i]->msg) > 0 &&
                    msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
                    fputc('\n', stderr);
                break;
            case PAM_TEXT_INFO:
                fputs(msg[i]->msg, stdout);
                if (strlen(msg[i]->msg) > 0 &&
                    msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
                    fputc('\n', stdout);
                break;
            default:
                goto fail;
            }
        }
        *resp = aresp;
        return (PAM_SUCCESS);
     fail:
            for (i = 0; i < n; ++i) {
                    if (aresp[i].resp != NULL) {
                            memset(aresp[i].resp, 0, strlen(aresp[i].resp));
                            free(aresp[i].resp);
                    }
            }
            memset(aresp, 0, n * sizeof *aresp);
        *resp = NULL;
        return (PAM_CONV_ERR);
    }

Prev | Home | Next
Sample PAM Module |  | Further Reading

This, and other documents, can be downloaded from ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

For questions about FreeBSD, read the documentation before contacting <questions@FreeBSD.org>.
For questions about this documentation, e-mail <doc@FreeBSD.org>.