database: export correct name
[apps/agl-service-data-persistence.git] / pam_agl / pam_agl_usb.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 int read_device(const char* device, char** idkey)
33 {
34         int fd;
35         ssize_t sz;
36         header h;
37                 
38         printf("[PAM DEBUG] check_device %s...\n", device);
39         fd = open(device, O_RDONLY);
40         if (fd == -1)
41         {
42                 printf("[PAM DEBUG] Failed to open the device %s!\n", device);
43                 return PAM_SERVICE_ERR;
44         }
45
46         sz = read(fd, &h, sizeof(header));
47         if (sz != sizeof(header) || !is_valid_mn(h.mn) || h.size < 1) { close(fd); printf("[PAM DEBUG]: bad header!\n"); return PAM_SERVICE_ERR; }
48         printf("[PAM DEBUG]: data size=%lu\n", h.size);
49
50         *idkey = (char*)malloc(h.size + 1);
51         if (!*idkey) { close(fd); printf("[PAM DEBUG] Bad alloc!\n"); return PAM_SERVICE_ERR; }
52
53         memset(*idkey, 0, h.size + 1);
54         sz = read(fd, *idkey, h.size);
55         close(fd);
56         if (sz != h.size) { free(idkey); printf("[PAM DEBUG] Bad data read!\n"); return PAM_SERVICE_ERR; }
57         return PAM_SUCCESS;
58 }
59
60 int authenticate(pam_handle_t* pamh, const char* uuid)
61 {
62         struct json_object* database;
63         struct json_object* usb;
64         struct json_object* key;
65
66         database = json_object_from_file(DATABASE_FILE);
67         if (!database)
68         {
69                 printf("[PAM DEBUG] Failed to parse the database\n");
70                 return PAM_SERVICE_ERR;
71         }
72         
73         if (json_object_object_get_ex(database, "usb", &usb))
74         {       
75                 if (json_object_object_get_ex(usb, uuid, &key))
76                 {
77                         printf("[PAM] Key found!\n");
78                         printf("[PAM DEBUG] pam_set_item(\"%s\")\n", uuid);
79                         pam_set_item(pamh, PAM_USER, uuid);
80                                 
81                         const char* pam_authtok;
82                         if (pam_get_item(pamh, PAM_AUTHTOK, (const void**)&pam_authtok) == PAM_SUCCESS && !pam_authtok)
83                                 pam_set_item(pamh, PAM_AUTHTOK, uuid);
84                         
85                         json_object_put(database);
86                         return PAM_SUCCESS;
87                 }
88         }
89         
90         printf("[PAM] Key not found!\n");
91         if (database) json_object_put(database);
92         return PAM_AUTH_ERR;
93 }
94
95 int check_device(pam_handle_t* pamh, const char* device)
96 {
97         char* idkey;
98         int ret;
99         
100         ret = read_device(device, &idkey);
101         if (ret != PAM_SUCCESS) return ret;
102         
103         printf("[PAM DEBUG] Data read:\n%s\n", idkey);
104         
105         json_object* idkey_json = json_tokener_parse(idkey);
106         if (!idkey_json)
107         {
108                 free(idkey);
109                 printf("[PAM DEBUG] Failed to parse json data!\n");
110                 return PAM_SERVICE_ERR;
111         }
112
113         json_object* uuid_json;
114         if(!json_object_object_get_ex(idkey_json, "uuid", &uuid_json))
115         {
116                 free(idkey);
117                 printf("[PAM DEBUG] The json does not contains a valid uuid\n");
118                 return PAM_SERVICE_ERR;
119         }
120
121         const char* uuid = json_object_get_string(uuid_json);
122         printf("[PAM DEBUG] uuid: %s\n", uuid);
123         
124         ret = authenticate(pamh, uuid);
125         free(idkey);
126         json_object_put(idkey_json);
127         return ret;
128 }
129
130 void log_pam(const char* fname, int flags, int argc, const char** argv, const char* device)
131 {
132         printf("[PAM DEBUG] ---------- %s ----------\n", fname);
133         printf("[PAM DEBUG] flags: %d\n", flags);
134         for(int i = 0; i < argc; ++i)
135         {
136                 printf("[PAM DEBUG] argv[%d]: %s\n", i, argv[i]);
137         }
138         printf("[PAM DEBUG] device: %s\n", device);
139         printf("[PAM DEBUG] ----------------------------------------\n");
140 }
141
142 /*!
143         @brief The pam_sm_authenticate function is the service module's implementation
144         of the pam_authenticate(3) interface.
145         This function performs the task of authenticating the user.
146
147         @param[in] pamh Unknown.
148         @param[in] flags PAM_SILENT and/or PAM_DISALLOW_NULL_AUTHTOK.
149         @return PAM_SUCCESS if ok.
150 */
151 PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh, int flags, int argc, const char** argv)
152 {
153         const char* device = pam_getenv(pamh, "DEVICE");
154         log_pam("pam_sm_authenticate", flags, argc, argv, device);
155         return check_device(pamh, device);
156 }
157
158 PAM_EXTERN int pam_sm_setcred(pam_handle_t* pamh, int flags, int argc, const char** argv)
159 {
160         log_pam("pam_sm_setcred", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
161         return PAM_SUCCESS;
162 }
163
164 PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t* pamh, int flags, int argc, const char** argv)
165 {
166         log_pam("pam_sm_acct_mgmt", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
167         return PAM_SUCCESS;
168 }
169
170 PAM_EXTERN int pam_sm_open_session(pam_handle_t* pamh, int flags, int argc, const char** argv)
171 {
172         log_pam("pam_sm_open_session", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
173         return PAM_SUCCESS;
174 }
175
176 PAM_EXTERN int pam_sm_close_session(pam_handle_t* pamh, int flags, int argc, const char** argv)
177 {
178         log_pam("pam_sm_close_session", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
179         return PAM_SUCCESS;
180 }
181
182 PAM_EXTERN int pam_sm_chauthtok(pam_handle_t* pamh, int flags, int argc, const char** argv)
183 {
184         log_pam("pam_sm_chauthtok", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
185         return PAM_SUCCESS;
186 }