0eea11adc1efcab9685c7c927d6a3f82360da40a
[apps/agl-service-data-persistence.git] / pam_agl / pam_agl.c
1 #include <fcntl.h>
2 #include <stdarg.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <uuid/uuid.h>
9 #include <json-c/json.h>
10
11 #define PAM_SM_AUTH
12 #define PAM_SM_ACCOUNT
13 #define PAM_SM_SESSION
14 #define PAM_SM_PASSWORD
15 #include <security/pam_modules.h>
16 #include <security/pam_appl.h>
17
18 #define DATABASE_FILE "/etc/agl/keys.json"
19
20 #define BLOCK_SIZE 4096
21 typedef struct header_
22 {
23         char mn[4];
24         size_t size;
25 } header;
26
27 int is_valid_mn(const char* v)
28 {
29         return v && v[0] == 'I' && v[1] == 'D' && v[2] == 'K' && v[3] == 'Y';
30 }
31
32 char* get_file_content(const char* path)
33 {
34         char* buffer;
35         long length;
36         FILE* f;
37         
38         buffer = NULL;
39         length = 0;
40         
41         f = fopen(path, "rb");
42         if (f)
43         {
44                 fseek(f, 0, SEEK_END);
45                 length = ftell(f);
46                 fseek(f, 0, SEEK_SET);
47                 buffer = malloc(length + 1);
48                 if (buffer)
49                 {
50                         if (fread (buffer, 1, length, f) != length)
51                         {
52                                 free(buffer);
53                                 buffer = NULL;
54                         }
55                         else buffer[length] = 0;
56                 }
57                 fclose (f);
58         }
59         
60         return buffer;
61 }
62
63 void pam_putenv_ex(pam_handle_t* pamh, const char* name, const char* value)
64 {
65         char result[4096];
66         strcpy(result, name);
67
68         int offset = strlen(name);
69         result[offset] = '=';
70
71         strcpy(result + offset + 1, value);
72
73         pam_putenv(pamh, result);
74 }
75
76 int read_device(const char* device, char** idkey)
77 {
78         int fd;
79         ssize_t sz;
80         header h;
81                 
82         printf("[PAM DEBUG] check_device %s...\n", device);
83         fd = open(device, O_RDONLY);
84         if (fd == -1)
85         {
86                 printf("[PAM DEBUG] Failed to open the device %s!\n", device);
87                 return PAM_SERVICE_ERR;
88         }
89
90         sz = read(fd, &h, sizeof(header));
91         if (sz != sizeof(header) || !is_valid_mn(h.mn) || h.size < 1) { close(fd); printf("[PAM DEBUG]: bad header!\n"); return PAM_SERVICE_ERR; }
92         printf("[PAM DEBUG]: data size=%lu\n", h.size);
93
94         *idkey = (char*)malloc(h.size + 1);
95         if (!*idkey) { close(fd); printf("[PAM DEBUG] Bad alloc!\n"); return PAM_SERVICE_ERR; }
96
97         memset(*idkey, 0, h.size + 1);
98         sz = read(fd, *idkey, h.size);
99         close(fd);
100         if (sz != h.size) { free(idkey); printf("[PAM DEBUG] Bad data read!\n"); return PAM_SERVICE_ERR; }
101         return PAM_SUCCESS;
102 }
103
104 int authenticate(pam_handle_t* pamh, const char* uuid)
105 {
106         char* file_content;
107         struct json_object* database;
108         struct json_object* key;
109
110         file_content = get_file_content(DATABASE_FILE);
111         if (!file_content)
112         {
113                 printf("[PAM DEBUG] Failed to read database file (%s)\n", DATABASE_FILE);
114                 return PAM_SERVICE_ERR;
115         }
116         
117         database = json_tokener_parse(file_content);
118         if (!database)
119         {
120                 printf("[PAM DEBUG] Failed to parse the database\n");
121                 return PAM_SERVICE_ERR;
122         }
123         
124         if (json_object_object_get_ex(database, uuid, &key))
125         {
126                 printf("[PAM] Key found!\n");
127                 printf("[PAM DEBUG] pam_set_item(\"%s\")\n", uuid);
128                 pam_set_item(pamh, PAM_USER, uuid);
129                         
130                 const char* pam_authtok;
131                 if (pam_get_item(pamh, PAM_AUTHTOK, (const void**)&pam_authtok) == PAM_SUCCESS && !pam_authtok)
132                         pam_set_item(pamh, PAM_AUTHTOK, uuid);
133                 
134                 json_object_put(database);
135                 free(file_content);
136                 return PAM_SUCCESS;
137         }
138         
139         printf("[PAM] Key not found!\n");
140         free(file_content);
141         if (database) json_object_put(database);
142         return PAM_AUTH_ERR;
143 }
144
145 int check_device(pam_handle_t* pamh, const char* device)
146 {
147         char* idkey;
148         int ret;
149         
150         ret = read_device(device, &idkey);
151         if (ret != PAM_SUCCESS) return ret;
152         
153         printf("[PAM DEBUG] Data read:\n%s\n", idkey);
154         
155         json_object* idkey_json = json_tokener_parse(idkey);
156         if (!idkey_json)
157         {
158                 free(idkey);
159                 printf("[PAM DEBUG] Failed to parse json data!\n");
160                 return PAM_SERVICE_ERR;
161         }
162
163         json_object* uuid_json;
164         if(!json_object_object_get_ex(idkey_json, "uuid", &uuid_json))
165         {
166                 free(idkey);
167                 printf("[PAM DEBUG] The json does not contains a valid uuid\n");
168                 return PAM_SERVICE_ERR;
169         }
170
171         const char* uuid = json_object_get_string(uuid_json);
172         printf("[PAM DEBUG] uuid: %s\n", uuid);
173         
174         ret = authenticate(pamh, uuid);
175         free(idkey);
176         json_object_put(idkey_json);
177         return ret;
178 }
179
180 void log_pam(const char* fname, int flags, int argc, const char** argv, const char* device)
181 {
182         printf("[PAM DEBUG] ---------- %s ----------\n", fname);
183         printf("[PAM DEBUG] flags: %d\n", flags);
184         for(int i = 0; i < argc; ++i)
185         {
186                 printf("[PAM DEBUG] argv[%d]: %s\n", i, argv[i]);
187         }
188         printf("[PAM DEBUG] device: %s\n", device);
189         printf("[PAM DEBUG] ----------------------------------------\n");
190 }
191
192 /*!
193         @brief The pam_sm_authenticate function is the service module's implementation
194         of the pam_authenticate(3) interface.
195         This function performs the task of authenticating the user.
196
197         @param[in] pamh Unknown.
198         @param[in] flags PAM_SILENT and/or PAM_DISALLOW_NULL_AUTHTOK.
199         @return PAM_SUCCESS if ok.
200 */
201 PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh, int flags, int argc, const char** argv)
202 {
203         const char* device = pam_getenv(pamh, "DEVICE");
204         log_pam("pam_sm_authenticate", flags, argc, argv, device);
205         return check_device(pamh, device);
206 }
207
208 PAM_EXTERN int pam_sm_setcred(pam_handle_t* pamh, int flags, int argc, const char** argv)
209 {
210         log_pam("pam_sm_setcred", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
211         return PAM_SUCCESS;
212 }
213
214 PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t* pamh, int flags, int argc, const char** argv)
215 {
216         log_pam("pam_sm_acct_mgmt", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
217         return PAM_SUCCESS;
218 }
219
220 PAM_EXTERN int pam_sm_open_session(pam_handle_t* pamh, int flags, int argc, const char** argv)
221 {
222         log_pam("pam_sm_open_session", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
223         return PAM_SUCCESS;
224 }
225
226 PAM_EXTERN int pam_sm_close_session(pam_handle_t* pamh, int flags, int argc, const char** argv)
227 {
228         log_pam("pam_sm_close_session", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
229         return PAM_SUCCESS;
230 }
231
232 PAM_EXTERN int pam_sm_chauthtok(pam_handle_t* pamh, int flags, int argc, const char** argv)
233 {
234         log_pam("pam_sm_chauthtok", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
235         return PAM_SUCCESS;
236 }