Wrapper for PAM

Alexander Zhirov azhirov1991 at gmail.com
Thu Oct 3 22:54:53 UTC 2024


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


More information about the Digitalmars-d-learn mailing list