1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
/*
* auth.c
*
* Created by buzzert <buzzert@buzzert.net> 2019-01-19
*/
#include "auth.h"
#include <pthread.h>
#include <pwd.h>
#include <security/pam_appl.h>
#include <semaphore.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
struct auth_handle_t {
void *context;
auth_callbacks_t callbacks;
sem_t prompt_semaphore;
auth_prompt_response_t *prompt_response;
};
int process_message(const struct pam_message *msg, struct pam_response *resp, struct auth_handle_t *handle)
{
switch (msg->msg_style) {
case PAM_PROMPT_ECHO_ON:
case PAM_PROMPT_ECHO_OFF: {
handle->callbacks.prompt_handler(msg->msg, handle->context);
sem_wait(&handle->prompt_semaphore);
auth_prompt_response_t *response = handle->prompt_response;
resp->resp = response->response_buffer;
resp->resp_retcode = response->response_code;
break;
}
case PAM_ERROR_MSG:
handle->callbacks.error_handler(msg->msg, handle->context);
break;
case PAM_TEXT_INFO:
handle->callbacks.info_handler(msg->msg, handle->context);
break;
}
return PAM_SUCCESS;
}
int perform_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *data)
{
*resp = calloc(num_msg, sizeof(struct pam_response));
struct auth_handle_t *handle = (struct auth_handle_t *)data;
for (unsigned i = 0; i < num_msg; ++i) {
process_message(msg[i], resp[i], handle);
}
return PAM_SUCCESS;
}
static void* auth_thread_main(void *arg)
{
struct pam_conv conv;
conv.conv = perform_conversation;
conv.appdata_ptr = arg;
// Get current username
struct passwd *pwd = getpwuid(getuid());
const char *username = pwd->pw_name;
if (username == NULL || strlen(username) == 0) {
fprintf(stderr, "Couldn't get name for the current user\n");
// todo: report to callback
}
// Start PAM authentication
pam_handle_t *pam = NULL;
pam_start(
"login",
username,
&conv,
&pam
);
bool authenticating = true;
struct auth_handle_t *handle = (struct auth_handle_t *)arg;
while (authenticating) {
int status = pam_authenticate(pam, 0);
handle->callbacks.result_handler(status, handle->context);
if (status == PAM_SUCCESS) {
authenticating = false;
}
}
pam_end(pam, 0);
return NULL;
}
struct auth_handle_t* auth_begin_authentication(auth_callbacks_t callbacks, void *context)
{
struct auth_handle_t *handle = malloc(sizeof(struct auth_handle_t));
handle->callbacks = callbacks;
handle->context = context;
handle->prompt_response = NULL;
sem_init(&handle->prompt_semaphore, 0, 0);
pthread_t auth_thread;
if (pthread_create(&auth_thread, NULL, auth_thread_main, handle)) {
fprintf(stderr, "Error creating auth thread\n");
}
return handle;
}
void auth_attempt_authentication(struct auth_handle_t *handle, auth_prompt_response_t response)
{
if (handle->prompt_response == NULL) {
handle->prompt_response = malloc(sizeof(auth_prompt_response_t));
}
handle->prompt_response = memcpy(handle->prompt_response, &response, sizeof(auth_prompt_response_t));
sem_post(&handle->prompt_semaphore);
}
|