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 | #include <config.h>
|
31 |
|
32 | #include <stdio.h>
|
33 | #include <string.h>
|
34 |
|
35 | #include <mosquitto_broker.h>
|
36 | #include <memory_mosq.h>
|
37 | #include "util_mosq.h"
|
38 |
|
39 | static int _aclfile_parse(struct mosquitto_db *db);
|
40 | static int _unpwd_file_parse(struct mosquitto_db *db);
|
41 | static int _acl_cleanup(struct mosquitto_db *db, bool reload);
|
42 | static int _unpwd_cleanup(struct _mosquitto_unpwd **unpwd, bool reload);
|
43 | static int _psk_file_parse(struct mosquitto_db *db);
|
44 | #ifdef WITH_TLS
|
45 | static int _pw_digest(const char *password, const unsigned char *salt, unsigned int salt_len, unsigned char *hash, unsigned int *hash_len);
|
46 | static int _base64_decode(char *in, unsigned char **decoded, unsigned int *decoded_len);
|
47 | #endif
|
48 |
|
49 | int mosquitto_security_init_default(struct mosquitto_db *db, bool reload)
|
50 | {
|
51 | int rc;
|
52 |
|
53 |
|
54 | if(db->config->password_file){
|
55 | rc = _unpwd_file_parse(db);
|
56 | if(rc){
|
57 | _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error opening password file \"%s\".", db->config->password_file);
|
58 | return rc;
|
59 | }
|
60 | }
|
61 |
|
62 |
|
63 | if(db->config->acl_file){
|
64 | rc = _aclfile_parse(db);
|
65 | if(rc){
|
66 | _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error opening acl file \"%s\".", db->config->acl_file);
|
67 | return rc;
|
68 | }
|
69 | }
|
70 |
|
71 |
|
72 | if(db->config->psk_file){
|
73 | rc = _psk_file_parse(db);
|
74 | if(rc){
|
75 | _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error opening psk file \"%s\".", db->config->psk_file);
|
76 | return rc;
|
77 | }
|
78 | }
|
79 |
|
80 | return MOSQ_ERR_SUCCESS;
|
81 | }
|
82 |
|
83 | int mosquitto_security_cleanup_default(struct mosquitto_db *db, bool reload)
|
84 | {
|
85 | int rc;
|
86 | rc = _acl_cleanup(db, reload);
|
87 | if(rc != MOSQ_ERR_SUCCESS) return rc;
|
88 | rc = _unpwd_cleanup(&db->unpwd, reload);
|
89 | if(rc != MOSQ_ERR_SUCCESS) return rc;
|
90 | return _unpwd_cleanup(&db->psk_id, reload);
|
91 | }
|
92 |
|
93 |
|
94 | int _add_acl(struct mosquitto_db *db, const char *user, const char *topic, int access)
|
95 | {
|
96 | struct _mosquitto_acl_user *acl_user=NULL, *user_tail;
|
97 | struct _mosquitto_acl *acl, *acl_tail;
|
98 | char *local_topic;
|
99 | bool new_user = false;
|
100 |
|
101 | if(!db || !topic) return MOSQ_ERR_INVAL;
|
102 |
|
103 | local_topic = _mosquitto_strdup(topic);
|
104 | if(!local_topic){
|
105 | return MOSQ_ERR_NOMEM;
|
106 | }
|
107 |
|
108 | if(db->acl_list){
|
109 | user_tail = db->acl_list;
|
110 | while(user_tail){
|
111 | if(user == NULL){
|
112 | if(user_tail->username == NULL){
|
113 | acl_user = user_tail;
|
114 | break;
|
115 | }
|
116 | }else if(user_tail->username && !strcmp(user_tail->username, user)){
|
117 | acl_user = user_tail;
|
118 | break;
|
119 | }
|
120 | user_tail = user_tail->next;
|
121 | }
|
122 | }
|
123 | if(!acl_user){
|
124 | acl_user = _mosquitto_malloc(sizeof(struct _mosquitto_acl_user));
|
125 | if(!acl_user){
|
126 | _mosquitto_free(local_topic);
|
127 | return MOSQ_ERR_NOMEM;
|
128 | }
|
129 | new_user = true;
|
130 | if(user){
|
131 | acl_user->username = _mosquitto_strdup(user);
|
132 | if(!acl_user->username){
|
133 | _mosquitto_free(local_topic);
|
134 | _mosquitto_free(acl_user);
|
135 | return MOSQ_ERR_NOMEM;
|
136 | }
|
137 | }else{
|
138 | acl_user->username = NULL;
|
139 | }
|
140 | acl_user->next = NULL;
|
141 | acl_user->acl = NULL;
|
142 | }
|
143 |
|
144 | acl= _mosquitto_malloc(sizeof(struct _mosquitto_acl));
|
145 | if(!acl) return MOSQ_ERR_NOMEM;
|
146 | acl->access = access;
|
147 | acl->topic = local_topic;
|
148 | acl->next = NULL;
|
149 |
|
150 |
|
151 | if(acl_user->acl){
|
152 | acl_tail = acl_user->acl;
|
153 | while(acl_tail->next){
|
154 | acl_tail = acl_tail->next;
|
155 | }
|
156 | acl_tail->next = acl;
|
157 | }else{
|
158 | acl_user->acl = acl;
|
159 | }
|
160 |
|
161 | if(new_user){
|
162 |
|
163 | if(db->acl_list){
|
164 | user_tail = db->acl_list;
|
165 | while(user_tail->next){
|
166 | user_tail = user_tail->next;
|
167 | }
|
168 | user_tail->next = acl_user;
|
169 | }else{
|
170 | db->acl_list = acl_user;
|
171 | }
|
172 | }
|
173 |
|
174 | return MOSQ_ERR_SUCCESS;
|
175 | }
|
176 |
|
177 | int _add_acl_pattern(struct mosquitto_db *db, const char *topic, int access)
|
178 | {
|
179 | struct _mosquitto_acl *acl, *acl_tail;
|
180 | char *local_topic;
|
181 |
|
182 | if(!db || !topic) return MOSQ_ERR_INVAL;
|
183 |
|
184 | local_topic = _mosquitto_strdup(topic);
|
185 | if(!local_topic){
|
186 | return MOSQ_ERR_NOMEM;
|
187 | }
|
188 |
|
189 | acl = _mosquitto_malloc(sizeof(struct _mosquitto_acl));
|
190 | if(!acl) return MOSQ_ERR_NOMEM;
|
191 | acl->access = access;
|
192 | acl->topic = local_topic;
|
193 | acl->next = NULL;
|
194 |
|
195 | if(db->acl_patterns){
|
196 | acl_tail = db->acl_patterns;
|
197 | while(acl_tail->next){
|
198 | acl_tail = acl_tail->next;
|
199 | }
|
200 | acl_tail->next = acl;
|
201 | }else{
|
202 | db->acl_patterns = acl;
|
203 | }
|
204 |
|
205 | return MOSQ_ERR_SUCCESS;
|
206 | }
|
207 |
|
208 | int mosquitto_acl_check_default(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int access)
|
209 | {
|
210 | char *local_acl;
|
211 | struct _mosquitto_acl *acl_root;
|
212 | bool result;
|
213 | int i;
|
214 | int len, tlen, clen, ulen;
|
215 | int ccount, ucount;
|
216 | char *s;
|
217 |
|
218 | if(!db || !context || !topic) return MOSQ_ERR_INVAL;
|
219 | if(!db->acl_list && !db->acl_patterns) return MOSQ_ERR_SUCCESS;
|
220 | if(context->bridge) return MOSQ_ERR_SUCCESS;
|
221 | if(!context->acl_list && !db->acl_patterns) return MOSQ_ERR_ACL_DENIED;
|
222 |
|
223 | if(context->acl_list){
|
224 | acl_root = context->acl_list->acl;
|
225 | }else{
|
226 | acl_root = NULL;
|
227 | }
|
228 |
|
229 |
|
230 | while(acl_root){
|
231 |
|
232 |
|
233 |
|
234 | if(topic[0] == '$' && acl_root->topic[0] != '$'){
|
235 | acl_root = acl_root->next;
|
236 | continue;
|
237 | }
|
238 | mosquitto_topic_matches_sub(acl_root->topic, topic, &result);
|
239 | if(result){
|
240 | if(access & acl_root->access){
|
241 |
|
242 | return MOSQ_ERR_SUCCESS;
|
243 | }
|
244 | }
|
245 | acl_root = acl_root->next;
|
246 | }
|
247 |
|
248 | acl_root = db->acl_patterns;
|
249 |
|
250 | clen = strlen(context->id);
|
251 | while(acl_root){
|
252 | tlen = strlen(acl_root->topic);
|
253 |
|
254 | ccount = 0;
|
255 | s = acl_root->topic;
|
256 | while(s){
|
257 | s = strstr(s, "%c");
|
258 | if(s){
|
259 | ccount++;
|
260 | s+=2;
|
261 | }
|
262 | }
|
263 |
|
264 | ucount = 0;
|
265 | s = acl_root->topic;
|
266 | while(s){
|
267 | s = strstr(s, "%u");
|
268 | if(s){
|
269 | ucount++;
|
270 | s+=2;
|
271 | }
|
272 | }
|
273 |
|
274 | if(ucount && !context->username){
|
275 | continue;
|
276 | }
|
277 |
|
278 | ulen = strlen(context->username);
|
279 | len = tlen + ccount*(clen-2) + ucount*(ulen-2);
|
280 | local_acl = malloc(len+1);
|
281 | if(!local_acl) return 1;
|
282 | s = local_acl;
|
283 | for(i=0; i<tlen; i++){
|
284 | if(i<tlen-1 && acl_root->topic[i] == '%'){
|
285 | if(acl_root->topic[i+1] == 'c'){
|
286 | i++;
|
287 | strncpy(s, context->id, clen);
|
288 | s+=clen;
|
289 | continue;
|
290 | }else if(acl_root->topic[i+1] == 'u'){
|
291 | i++;
|
292 | strncpy(s, context->username, ulen);
|
293 | s+=ulen;
|
294 | continue;
|
295 | }
|
296 | }
|
297 | s[0] = acl_root->topic[i];
|
298 | s++;
|
299 | }
|
300 | local_acl[len] = '\0';
|
301 |
|
302 | mosquitto_topic_matches_sub(local_acl, topic, &result);
|
303 | if(result){
|
304 | if(access & acl_root->access){
|
305 |
|
306 | return MOSQ_ERR_SUCCESS;
|
307 | }
|
308 | }
|
309 |
|
310 | _mosquitto_free(local_acl);
|
311 |
|
312 | acl_root = acl_root->next;
|
313 | }
|
314 |
|
315 | return MOSQ_ERR_ACL_DENIED;
|
316 | }
|
317 |
|
318 | static int _aclfile_parse(struct mosquitto_db *db)
|
319 | {
|
320 | FILE *aclfile;
|
321 | char buf[1024];
|
322 | char *token;
|
323 | char *user = NULL;
|
324 | char *topic;
|
325 | char *access_s;
|
326 | int access;
|
327 | int rc;
|
328 | int slen;
|
329 | int topic_pattern;
|
330 | char *saveptr = NULL;
|
331 |
|
332 | if(!db || !db->config) return MOSQ_ERR_INVAL;
|
333 | if(!db->config->acl_file) return MOSQ_ERR_SUCCESS;
|
334 |
|
335 | aclfile = _mosquitto_fopen(db->config->acl_file, "rt");
|
336 | if(!aclfile){
|
337 | _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open acl_file \"%s\".", db->config->acl_file);
|
338 | return 1;
|
339 | }
|
340 |
|
341 |
|
342 |
|
343 |
|
344 | while(fgets(buf, 1024, aclfile)){
|
345 | slen = strlen(buf);
|
346 | while(slen > 0 && (buf[slen-1] == 10 || buf[slen-1] == 13)){
|
347 | buf[slen-1] = '\0';
|
348 | slen = strlen(buf);
|
349 | }
|
350 | if(buf[0] == '#'){
|
351 | continue;
|
352 | }
|
353 | token = strtok_r(buf, " ", &saveptr);
|
354 | if(token){
|
355 | if(!strcmp(token, "topic") || !strcmp(token, "pattern")){
|
356 | if(!strcmp(token, "topic")){
|
357 | topic_pattern = 0;
|
358 | }else{
|
359 | topic_pattern = 1;
|
360 | }
|
361 |
|
362 | access_s = strtok_r(NULL, " ", &saveptr);
|
363 | if(!access_s){
|
364 | _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty topic in acl_file.");
|
365 | if(user) _mosquitto_free(user);
|
366 | fclose(aclfile);
|
367 | return MOSQ_ERR_INVAL;
|
368 | }
|
369 | token = strtok_r(NULL, " ", &saveptr);
|
370 | if(token){
|
371 | topic = token;
|
372 | }else{
|
373 | topic = access_s;
|
374 | access_s = NULL;
|
375 | }
|
376 | if(access_s){
|
377 | if(!strcmp(access_s, "read")){
|
378 | access = MOSQ_ACL_READ;
|
379 | }else if(!strcmp(access_s, "write")){
|
380 | access = MOSQ_ACL_WRITE;
|
381 | }else{
|
382 | _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty invalid topic access type in acl_file.");
|
383 | if(user) _mosquitto_free(user);
|
384 | fclose(aclfile);
|
385 | return MOSQ_ERR_INVAL;
|
386 | }
|
387 | }else{
|
388 | access = MOSQ_ACL_READ | MOSQ_ACL_WRITE;
|
389 | }
|
390 | if(topic_pattern == 0){
|
391 | rc = _add_acl(db, user, topic, access);
|
392 | }else{
|
393 | rc = _add_acl_pattern(db, topic, access);
|
394 | }
|
395 | if(rc){
|
396 | fclose(aclfile);
|
397 | return rc;
|
398 | }
|
399 | }else if(!strcmp(token, "user")){
|
400 | token = strtok_r(NULL, " ", &saveptr);
|
401 | if(token){
|
402 | if(user) _mosquitto_free(user);
|
403 | user = _mosquitto_strdup(token);
|
404 | if(!user){
|
405 | fclose(aclfile);
|
406 | return MOSQ_ERR_NOMEM;
|
407 | }
|
408 | }else{
|
409 | _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Missing username in acl_file.");
|
410 | if(user) _mosquitto_free(user);
|
411 | fclose(aclfile);
|
412 | return 1;
|
413 | }
|
414 | }
|
415 | }
|
416 | }
|
417 |
|
418 | if(user) _mosquitto_free(user);
|
419 | fclose(aclfile);
|
420 |
|
421 | return MOSQ_ERR_SUCCESS;
|
422 | }
|
423 |
|
424 | static void _free_acl(struct _mosquitto_acl *acl)
|
425 | {
|
426 | if(!acl) return;
|
427 |
|
428 | if(acl->next){
|
429 | _free_acl(acl->next);
|
430 | }
|
431 | if(acl->topic){
|
432 | _mosquitto_free(acl->topic);
|
433 | }
|
434 | _mosquitto_free(acl);
|
435 | }
|
436 |
|
437 | static int _acl_cleanup(struct mosquitto_db *db, bool reload)
|
438 | {
|
439 | int i;
|
440 | struct _mosquitto_acl_user *user_tail;
|
441 |
|
442 | if(!db) return MOSQ_ERR_INVAL;
|
443 | if(!db->acl_list) return MOSQ_ERR_SUCCESS;
|
444 |
|
445 | |
446 |
|
447 |
|
448 |
|
449 |
|
450 |
|
451 | if(db->contexts){
|
452 | for(i=0; i<db->context_count; i++){
|
453 | if(db->contexts[i] && db->contexts[i]->acl_list){
|
454 | db->contexts[i]->acl_list = NULL;
|
455 | }
|
456 | }
|
457 | }
|
458 |
|
459 | while(db->acl_list){
|
460 | user_tail = db->acl_list->next;
|
461 |
|
462 | _free_acl(db->acl_list->acl);
|
463 | if(db->acl_list->username){
|
464 | _mosquitto_free(db->acl_list->username);
|
465 | }
|
466 | _mosquitto_free(db->acl_list);
|
467 |
|
468 | db->acl_list = user_tail;
|
469 | }
|
470 |
|
471 | if(db->acl_patterns){
|
472 | _free_acl(db->acl_patterns);
|
473 | db->acl_patterns = NULL;
|
474 | }
|
475 | return MOSQ_ERR_SUCCESS;
|
476 | }
|
477 |
|
478 | static int _pwfile_parse(const char *file, struct _mosquitto_unpwd **root)
|
479 | {
|
480 | FILE *pwfile;
|
481 | struct _mosquitto_unpwd *unpwd;
|
482 | char buf[256];
|
483 | char *username, *password;
|
484 | int len;
|
485 | char *saveptr = NULL;
|
486 |
|
487 | pwfile = _mosquitto_fopen(file, "rt");
|
488 | if(!pwfile){
|
489 | _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open pwfile \"%s\".", file);
|
490 | return 1;
|
491 | }
|
492 |
|
493 | while(!feof(pwfile)){
|
494 | if(fgets(buf, 256, pwfile)){
|
495 | username = strtok_r(buf, ":", &saveptr);
|
496 | if(username){
|
497 | unpwd = _mosquitto_calloc(1, sizeof(struct _mosquitto_unpwd));
|
498 | if(!unpwd){
|
499 | fclose(pwfile);
|
500 | return MOSQ_ERR_NOMEM;
|
501 | }
|
502 | unpwd->username = _mosquitto_strdup(username);
|
503 | if(!unpwd->username){
|
504 | _mosquitto_free(unpwd);
|
505 | fclose(pwfile);
|
506 | return MOSQ_ERR_NOMEM;
|
507 | }
|
508 | len = strlen(unpwd->username);
|
509 | while(unpwd->username[len-1] == 10 || unpwd->username[len-1] == 13){
|
510 | unpwd->username[len-1] = '\0';
|
511 | len = strlen(unpwd->username);
|
512 | }
|
513 | password = strtok_r(NULL, ":", &saveptr);
|
514 | if(password){
|
515 | unpwd->password = _mosquitto_strdup(password);
|
516 | if(!unpwd->password){
|
517 | fclose(pwfile);
|
518 | _mosquitto_free(unpwd->username);
|
519 | _mosquitto_free(unpwd);
|
520 | return MOSQ_ERR_NOMEM;
|
521 | }
|
522 | len = strlen(unpwd->password);
|
523 | while(len && (unpwd->password[len-1] == 10 || unpwd->password[len-1] == 13)){
|
524 | unpwd->password[len-1] = '\0';
|
525 | len = strlen(unpwd->password);
|
526 | }
|
527 | }
|
528 | HASH_ADD_KEYPTR(hh, *root, unpwd->username, strlen(unpwd->username), unpwd);
|
529 | }
|
530 | }
|
531 | }
|
532 | fclose(pwfile);
|
533 |
|
534 | return MOSQ_ERR_SUCCESS;
|
535 | }
|
536 |
|
537 | static int _unpwd_file_parse(struct mosquitto_db *db)
|
538 | {
|
539 | int rc;
|
540 | #ifdef WITH_TLS
|
541 | struct _mosquitto_unpwd *u, *tmp;
|
542 | char *token;
|
543 | unsigned char *salt;
|
544 | unsigned int salt_len;
|
545 | unsigned char *password;
|
546 | unsigned int password_len;
|
547 | #endif
|
548 |
|
549 | if(!db || !db->config) return MOSQ_ERR_INVAL;
|
550 |
|
551 | if(!db->config->password_file) return MOSQ_ERR_SUCCESS;
|
552 |
|
553 | rc = _pwfile_parse(db->config->password_file, &db->unpwd);
|
554 | #ifdef WITH_TLS
|
555 | if(rc) return rc;
|
556 |
|
557 | HASH_ITER(hh, db->unpwd, u, tmp){
|
558 |
|
559 | if(u->password){
|
560 | token = strtok(u->password, "$");
|
561 | if(token && !strcmp(token, "6")){
|
562 | token = strtok(NULL, "$");
|
563 | if(token){
|
564 | rc = _base64_decode(token, &salt, &salt_len);
|
565 | if(rc){
|
566 | _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to decode password salt for user %s.", u->username);
|
567 | return MOSQ_ERR_INVAL;
|
568 | }
|
569 | u->salt = salt;
|
570 | u->salt_len = salt_len;
|
571 | token = strtok(NULL, "$");
|
572 | if(token){
|
573 | rc = _base64_decode(token, &password, &password_len);
|
574 | if(rc){
|
575 | _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to decode password for user %s.", u->username);
|
576 | return MOSQ_ERR_INVAL;
|
577 | }
|
578 | _mosquitto_free(u->password);
|
579 | u->password = (char *)password;
|
580 | u->password_len = password_len;
|
581 | }else{
|
582 | _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s.", u->username);
|
583 | return MOSQ_ERR_INVAL;
|
584 | }
|
585 | }else{
|
586 | _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s.", u->username);
|
587 | return MOSQ_ERR_INVAL;
|
588 | }
|
589 | }else{
|
590 | _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s.", u->username);
|
591 | return MOSQ_ERR_INVAL;
|
592 | }
|
593 | }
|
594 | }
|
595 | #endif
|
596 | return rc;
|
597 | }
|
598 |
|
599 | static int _psk_file_parse(struct mosquitto_db *db)
|
600 | {
|
601 | int rc;
|
602 | struct _mosquitto_unpwd *u, *tmp;
|
603 |
|
604 | if(!db || !db->config) return MOSQ_ERR_INVAL;
|
605 |
|
606 |
|
607 | if(!db->config->psk_file) return MOSQ_ERR_SUCCESS;
|
608 |
|
609 | rc = _pwfile_parse(db->config->psk_file, &db->psk_id);
|
610 | if(rc) return rc;
|
611 |
|
612 | HASH_ITER(hh, db->psk_id, u, tmp){
|
613 |
|
614 | if(!u->password){
|
615 | _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty psk for identity \"%s\".", u->username);
|
616 | return MOSQ_ERR_INVAL;
|
617 | }
|
618 | if(strspn(u->password, "0123456789abcdefABCDEF") < strlen(u->password)){
|
619 | _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: psk for identity \"%s\" contains non-hexadecimal characters.", u->username);
|
620 | return MOSQ_ERR_INVAL;
|
621 | }
|
622 | }
|
623 | return MOSQ_ERR_SUCCESS;
|
624 | }
|
625 |
|
626 | int mosquitto_unpwd_check_default(struct mosquitto_db *db, const char *username, const char *password)
|
627 | {
|
628 | struct _mosquitto_unpwd *u, *tmp;
|
629 | #ifdef WITH_TLS
|
630 | unsigned char hash[EVP_MAX_MD_SIZE];
|
631 | unsigned int hash_len;
|
632 | int rc;
|
633 | #endif
|
634 |
|
635 | if(!db || !username) return MOSQ_ERR_INVAL;
|
636 | if(!db->unpwd) return MOSQ_ERR_SUCCESS;
|
637 |
|
638 | HASH_ITER(hh, db->unpwd, u, tmp){
|
639 | if(!strcmp(u->username, username)){
|
640 | if(u->password){
|
641 | if(password){
|
642 | #ifdef WITH_TLS
|
643 | rc = _pw_digest(password, u->salt, u->salt_len, hash, &hash_len);
|
644 | if(rc == MOSQ_ERR_SUCCESS){
|
645 | if(hash_len == u->password_len && !memcmp(u->password, hash, hash_len)){
|
646 | return MOSQ_ERR_SUCCESS;
|
647 | }else{
|
648 | return MOSQ_ERR_AUTH;
|
649 | }
|
650 | }else{
|
651 | return rc;
|
652 | }
|
653 | #else
|
654 | if(!strcmp(u->password, password)){
|
655 | return MOSQ_ERR_SUCCESS;
|
656 | }
|
657 | #endif
|
658 | }else{
|
659 | return MOSQ_ERR_AUTH;
|
660 | }
|
661 | }else{
|
662 | return MOSQ_ERR_SUCCESS;
|
663 | }
|
664 | }
|
665 | }
|
666 |
|
667 | return MOSQ_ERR_AUTH;
|
668 | }
|
669 |
|
670 | static int _unpwd_cleanup(struct _mosquitto_unpwd **root, bool reload)
|
671 | {
|
672 | struct _mosquitto_unpwd *u, *tmp;
|
673 |
|
674 | if(!root) return MOSQ_ERR_INVAL;
|
675 |
|
676 | HASH_ITER(hh, *root, u, tmp){
|
677 | HASH_DEL(*root, u);
|
678 | if(u->password) _mosquitto_free(u->password);
|
679 | if(u->username) _mosquitto_free(u->username);
|
680 | #ifdef WITH_TLS
|
681 | if(u->salt) _mosquitto_free(u->salt);
|
682 | #endif
|
683 | _mosquitto_free(u);
|
684 | }
|
685 |
|
686 | *root = NULL;
|
687 |
|
688 | return MOSQ_ERR_SUCCESS;
|
689 | }
|
690 |
|
691 |
|
692 |
|
693 |
|
694 |
|
695 |
|
696 |
|
697 | int mosquitto_security_apply_default(struct mosquitto_db *db)
|
698 | {
|
699 | struct _mosquitto_acl_user *acl_user_tail;
|
700 | bool allow_anonymous;
|
701 | int i;
|
702 |
|
703 | if(!db) return MOSQ_ERR_INVAL;
|
704 |
|
705 | allow_anonymous = db->config->allow_anonymous;
|
706 |
|
707 | if(db->contexts){
|
708 | for(i=0; i<db->context_count; i++){
|
709 | if(db->contexts[i]){
|
710 |
|
711 | if(!allow_anonymous && !db->contexts[i]->username){
|
712 | db->contexts[i]->state = mosq_cs_disconnecting;
|
713 | _mosquitto_socket_close(db->contexts[i]);
|
714 | continue;
|
715 | }
|
716 |
|
717 | if(mosquitto_unpwd_check_default(db, db->contexts[i]->username, db->contexts[i]->password) != MOSQ_ERR_SUCCESS){
|
718 | db->contexts[i]->state = mosq_cs_disconnecting;
|
719 | _mosquitto_socket_close(db->contexts[i]);
|
720 | continue;
|
721 | }
|
722 |
|
723 | if(db->acl_list){
|
724 | acl_user_tail = db->acl_list;
|
725 | while(acl_user_tail){
|
726 | if(acl_user_tail->username){
|
727 | if(db->contexts[i]->username){
|
728 | if(!strcmp(acl_user_tail->username, db->contexts[i]->username)){
|
729 | db->contexts[i]->acl_list = acl_user_tail;
|
730 | break;
|
731 | }
|
732 | }
|
733 | }else{
|
734 | if(!db->contexts[i]->username){
|
735 | db->contexts[i]->acl_list = acl_user_tail;
|
736 | break;
|
737 | }
|
738 | }
|
739 | acl_user_tail = acl_user_tail->next;
|
740 | }
|
741 | }
|
742 | }
|
743 | }
|
744 | }
|
745 | return MOSQ_ERR_SUCCESS;
|
746 | }
|
747 |
|
748 | int mosquitto_psk_key_get_default(struct mosquitto_db *db, const char *hint, const char *identity, char *key, int max_key_len)
|
749 | {
|
750 | struct _mosquitto_unpwd *u, *tmp;
|
751 |
|
752 | if(!db || !hint || !identity || !key) return MOSQ_ERR_INVAL;
|
753 | if(!db->psk_id) return MOSQ_ERR_AUTH;
|
754 |
|
755 | HASH_ITER(hh, db->psk_id, u, tmp){
|
756 | if(!strcmp(u->username, identity)){
|
757 | strncpy(key, u->password, max_key_len);
|
758 | return MOSQ_ERR_SUCCESS;
|
759 | }
|
760 | }
|
761 |
|
762 | return MOSQ_ERR_AUTH;
|
763 | }
|
764 |
|
765 | #ifdef WITH_TLS
|
766 | int _pw_digest(const char *password, const unsigned char *salt, unsigned int salt_len, unsigned char *hash, unsigned int *hash_len)
|
767 | {
|
768 | const EVP_MD *digest;
|
769 | EVP_MD_CTX context;
|
770 |
|
771 | digest = EVP_get_digestbyname("sha512");
|
772 | if(!digest){
|
773 |
|
774 | return 1;
|
775 | }
|
776 |
|
777 | EVP_MD_CTX_init(&context);
|
778 | EVP_DigestInit_ex(&context, digest, NULL);
|
779 | EVP_DigestUpdate(&context, password, strlen(password));
|
780 | EVP_DigestUpdate(&context, salt, salt_len);
|
781 |
|
782 | EVP_DigestFinal_ex(&context, hash, hash_len);
|
783 | EVP_MD_CTX_cleanup(&context);
|
784 |
|
785 | return MOSQ_ERR_SUCCESS;
|
786 | }
|
787 |
|
788 | int _base64_decode(char *in, unsigned char **decoded, unsigned int *decoded_len)
|
789 | {
|
790 | BIO *bmem, *b64;
|
791 |
|
792 | b64 = BIO_new(BIO_f_base64());
|
793 | BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
794 | bmem = BIO_new(BIO_s_mem());
|
795 | b64 = BIO_push(b64, bmem);
|
796 | BIO_write(bmem, in, strlen(in));
|
797 |
|
798 | if(BIO_flush(bmem) != 1){
|
799 | BIO_free_all(bmem);
|
800 | return 1;
|
801 | }
|
802 | *decoded = calloc(strlen(in), 1);
|
803 | *decoded_len = BIO_read(b64, *decoded, strlen(in));
|
804 | BIO_free_all(bmem);
|
805 |
|
806 | return 0;
|
807 | }
|
808 |
|
809 | #endif
|