database: export correct name
[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 int read_device(const char* device, char** idkey)
64 {
65         int fd;
66         ssize_t sz;
67         header h;
68                 
69         printf("[PAM DEBUG] check_device %s...\n", device);
70         fd = open(device, O_RDONLY);
71         if (fd == -1)
72         {
73                 printf("[PAM DEBUG] Failed to open the device %s!\n", device);
74                 return PAM_SERVICE_ERR;
75         }
76
77         sz = read(fd, &h, sizeof(header));
78         if (sz != sizeof(header) || !is_valid_mn(h.mn) || h.size < 1) { close(fd); printf("[PAM DEBUG]: bad header!\n"); return PAM_SERVICE_ERR; }
79         printf("[PAM DEBUG]: data size=%lu\n", h.size);
80
81         *idkey = (char*)malloc(h.size + 1);
82         if (!*idkey) { close(fd); printf("[PAM DEBUG] Bad alloc!\n"); return PAM_SERVICE_ERR; }
83
84         memset(*idkey, 0, h.size + 1);
85         sz = read(fd, *idkey, h.size);
86         close(fd);
87         if (sz != h.size) { free(idkey); printf("[PAM DEBUG] Bad data read!\n"); return PAM_SERVICE_ERR; }
88         return PAM_SUCCESS;
89 }
90
91 int authenticate(pam_handle_t* pamh, const char* uuid)
92 {
93         char* file_content;
94         struct json_object* database;
95         struct json_object* key;
96
97         file_content = get_file_content(DATABASE_FILE);
98         if (!file_content)
99         {
100                 printf("[PAM DEBUG] Failed to read database file (%s)\n", DATABASE_FILE);
101                 return PAM_SERVICE_ERR;
102         }
103         
104         database = json_tokener_parse(file_content);
105         if (!database)
106         {
107                 printf("[PAM DEBUG] Failed to parse the database\n");
108                 return PAM_SERVICE_ERR;
109         }
110         
111         if (json_object_object_get_ex(database, uuid, &key))
112         {
113                 printf("[PAM] Key found!\n");
114                 printf("[PAM DEBUG] pam_set_item(\"%s\")\n", uuid);
115                 pam_set_item(pamh, PAM_USER, uuid);
116                         
117                 const char* pam_authtok;
118                 if (pam_get_item(pamh, PAM_AUTHTOK, (const void**)&pam_authtok) == PAM_SUCCESS && !pam_authtok)
119                         pam_set_item(pamh, PAM_AUTHTOK, uuid);
120                 
121                 json_object_put(database);
122                 free(file_content);
123                 return PAM_SUCCESS;
124         }
125         
126         printf("[PAM] Key not found!\n");
127         free(file_content);
128         if (database) json_object_put(database);
129         return PAM_AUTH_ERR;
130 }
131
132 int check_device(pam_handle_t* pamh, const char* device)
133 {
134         char* idkey;
135         int ret;
136         
137         ret = read_device(device, &idkey);
138         if (ret != PAM_SUCCESS) return ret;
139         
140         printf("[PAM DEBUG] Data read:\n%s\n", idkey);
141         
142         json_object* idkey_json = json_tokener_parse(idkey);
143         if (!idkey_json)
144         {
145                 free(idkey);
146                 printf("[PAM DEBUG] Failed to parse json data!\n");
147                 return PAM_SERVICE_ERR;
148         }
149
150         json_object* uuid_json;
151         if(!json_object_object_get_ex(idkey_json, "uuid", &uuid_json))
152         {
153                 free(idkey);
154                 printf("[PAM DEBUG] The json does not contains a valid uuid\n");
155                 return PAM_SERVICE_ERR;
156         }
157
158         const char* uuid = json_object_get_string(uuid_json);
159         printf("[PAM DEBUG] uuid: %s\n", uuid);
160         
161         ret = authenticate(pamh, uuid);
162         free(idkey);
163         json_object_put(idkey_json);
164         return ret;
165 }
166
167 void log_pam(const char* fname, int flags, int argc, const char** argv, const char* device)
168 {
169         printf("[PAM DEBUG] ---------- %s ----------\n", fname);
170         printf("[PAM DEBUG] flags: %d\n", flags);
171         for(int i = 0; i < argc; ++i)
172         {
173                 printf("[PAM DEBUG] argv[%d]: %s\n", i, argv[i]);
174         }
175         printf("[PAM DEBUG] device: %s\n", device);
176         printf("[PAM DEBUG] ----------------------------------------\n");
177 }
178
179 /*!
180         @brief The pam_sm_authenticate function is the service module's implementation
181         of the pam_authenticate(3) interface.
182         This function performs the task of authenticating the user.
183
184         @param[in] pamh Unknown.
185         @param[in] flags PAM_SILENT and/or PAM_DISALLOW_NULL_AUTHTOK.
186         @return PAM_SUCCESS if ok.
187 */
188 PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh, int flags, int argc, const char** argv)
189 {
190         const char* device = pam_getenv(pamh, "DEVICE");
191         log_pam("pam_sm_authenticate", flags, argc, argv, device);
192         return check_device(pamh, device);
193 }
194
195 PAM_EXTERN int pam_sm_setcred(pam_handle_t* pamh, int flags, int argc, const char** argv)
196 {
197         log_pam("pam_sm_setcred", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
198         return PAM_SUCCESS;
199 }
200
201 PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t* pamh, int flags, int argc, const char** argv)
202 {
203         log_pam("pam_sm_acct_mgmt", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
204         return PAM_SUCCESS;
205 }
206
207 PAM_EXTERN int pam_sm_open_session(pam_handle_t* pamh, int flags, int argc, const char** argv)
208 {
209         log_pam("pam_sm_open_session", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
210         return PAM_SUCCESS;
211 }
212
213 PAM_EXTERN int pam_sm_close_session(pam_handle_t* pamh, int flags, int argc, const char** argv)
214 {
215         log_pam("pam_sm_close_session", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
216         return PAM_SUCCESS;
217 }
218
219 PAM_EXTERN int pam_sm_chauthtok(pam_handle_t* pamh, int flags, int argc, const char** argv)
220 {
221         log_pam("pam_sm_chauthtok", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
222         return PAM_SUCCESS;
223 }