I want to try to make access via D to PAM. I'm trying to write basic things. I would like to know how to best transform access to callback functions? For example, so that there is no need to cast to a type and use binding to `extern`, move all this to a library?

```d
extern(C):

struct pam_message {
    int msg_style;
    const(char) *msg;
}

struct pam_response {
    char *resp;
    int resp_retcode;
}

alias conversation = int function(int num_msg, const pam_message **msg, pam_response **resp, void *appdata_ptr);

struct pam_conv {
    conversation *conv;
    void *appdata_ptr;
}

struct pam_handle;
alias pam_handle_t = pam_handle;

const (char) *pam_strerror(pam_handle_t *pamh, int errnum);

int pam_start(const(char) *service_name, const(char) *user, const pam_conv *pam_conversation, pam_handle_t **pamh);
int pam_authenticate(pam_handle_t *pamh, int flags);
int pam_end(pam_handle_t *pamh, int pam_status);
```

Below is the code that implements basic simple authentication. Is it possible to move `conversation_func` into a shell so as not to use type casting? What is the best way to implement this?

```d
struct pam_data {
    string password;
}

extern(C) {
int conversation_func(int num_msg, const pam_message **msg, pam_response **resp, void *appdata_ptr) {
    pam_data *data = cast(pam_data*)appdata_ptr;

*resp = cast(pam_response *)malloc(num_msg * pam_response.sizeof);
    if (*resp == null) {
        return PAM_BUF_ERR;
    }

    for (int i = 0; i < num_msg; i++) {
        switch (msg[i].msg_style) {
            case PAM_PROMPT_ECHO_ON:
            case PAM_PROMPT_ECHO_OFF:
                (*resp)[i].resp = strdup(data.password.toStringz);
                (*resp)[i].resp_retcode = 0;
                break;
            default:
                (*resp)[i].resp = null;
                (*resp)[i].resp_retcode = 0;
                break;
        }
    }

    return PAM_SUCCESS;
}
}

int authenticate_user(string username, string password) {
    pam_handle_t *pamh = null;
    int retval = 0;

    pam_data data = { password };
    void *appdata_ptr = &data;

pam_conv conv = { cast(conversation*)&conversation_func, appdata_ptr };

    retval = pam_start("login", username.toStringz, &conv, &pamh);
    if (retval != PAM_SUCCESS) {
writefln("pam_start: %s", pam_strerror(pamh, retval).to!string);
        return 1;
    }

    retval = pam_authenticate(pamh, 0);
    if (retval != PAM_SUCCESS) {
writefln("Authentication failure: %s", pam_strerror(pamh, retval).to!string);
        pam_end(pamh, retval);
        return 2;
    }

    retval = pam_end(pamh, PAM_SUCCESS);
    if (retval != PAM_SUCCESS) {
writefln("pam_end: %s", pam_strerror(pamh, retval).to!string);
        return 3;
    }

    return 0;
}

int main(string[] args) {
    string username = args[1];
    string password = args[2];

    int result = authenticate_user(username, password);
    if (result == 0) {
        writeln("Authentication succeeded!");
    } else {
        writefln("Authentication failed with code: %d", result);
    }

    return EXIT_SUCCESS;
}
```

Reply via email to