/*
** Standalone PAM authentication script
** Based on Solar Designer's PAM authentication mechanism in apop3d
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <security/pam_appl.h>

typedef const void *pam_item_t;

typedef struct{
    char *user;
    char *pass;
} pam_userpass_t;

static int pam_userpass_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) {
    pam_userpass_t *userpass = (pam_userpass_t *)appdata_ptr;
    char *string;
    int i;

    if (!(*resp = malloc(num_msg * sizeof(struct pam_response))))
        return PAM_CONV_ERR;

    for (i = 0; i < num_msg; i++) {
        string = NULL;
        switch (msg[i]->msg_style) {
        case PAM_PROMPT_ECHO_ON:
            string = userpass->user;
        case PAM_PROMPT_ECHO_OFF:
            if (!string)
                string = userpass->pass;
            if (!(string = strdup(string)))
                break;
        case PAM_ERROR_MSG:
        case PAM_TEXT_INFO:
            (*resp)[i].resp_retcode = PAM_SUCCESS;
            (*resp)[i].resp = string;
            continue;
        }

        while (--i >= 0) {
            if (!(*resp)[i].resp) continue;
            memset((*resp)[i].resp, 0, strlen((*resp)[i].resp));
            free((*resp)[i].resp);
            (*resp)[i].resp = NULL;
        }

        free(*resp);
        *resp = NULL;

        return PAM_CONV_ERR;
    }

    return PAM_SUCCESS;
}

int auth_userpass(char *user, char *pass) {
    pam_handle_t *pamh;
    pam_userpass_t userpass;
    struct pam_conv conv = {pam_userpass_conv, &userpass};
    int status;

    userpass.user = user;
    userpass.pass = pass;

    if (pam_start("spasm", user, &conv, &pamh) != PAM_SUCCESS) {
            return -1;
    }

    if ((status = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
        pam_end(pamh, status);
        return -1;
    }

    if (pam_end(pamh, PAM_SUCCESS) != PAM_SUCCESS) {
        return -1;
    }

    return 0;
}

int main(int argc, char **argv) {
    int rc;

    rc = auth_userpass(argv[1], argv[2]);
    
    exit(rc);
}
