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;
}
```