UNPKG

20.6 kBtext/x-cView Raw
1/*
2Copyright (c) 2011-2013 Roger Light <roger@atchoo.org>
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
81. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
102. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
133. Neither the name of mosquitto nor the names of its
14 contributors may be used to endorse or promote products derived from
15 this software without specific prior written permission.
16
17THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27POSSIBILITY OF SUCH DAMAGE.
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
39static int _aclfile_parse(struct mosquitto_db *db);
40static int _unpwd_file_parse(struct mosquitto_db *db);
41static int _acl_cleanup(struct mosquitto_db *db, bool reload);
42static int _unpwd_cleanup(struct _mosquitto_unpwd **unpwd, bool reload);
43static int _psk_file_parse(struct mosquitto_db *db);
44#ifdef WITH_TLS
45static int _pw_digest(const char *password, const unsigned char *salt, unsigned int salt_len, unsigned char *hash, unsigned int *hash_len);
46static int _base64_decode(char *in, unsigned char **decoded, unsigned int *decoded_len);
47#endif
48
49int mosquitto_security_init_default(struct mosquitto_db *db, bool reload)
50{
51 int rc;
52
53 /* Load username/password data if required. */
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 /* Load acl data if required. */
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 /* Load psk data if required. */
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
83int 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
94int _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 /* Add acl to user acl list */
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 /* Add to end of list */
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
177int _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
208int 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 /* Loop through all ACLs for this client. */
230 while(acl_root){
231 /* Loop through the topic looking for matches to this ACL. */
232
233 /* If subscription starts with $, acl_root->topic must also start with $. */
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 /* And access is allowed. */
242 return MOSQ_ERR_SUCCESS;
243 }
244 }
245 acl_root = acl_root->next;
246 }
247
248 acl_root = db->acl_patterns;
249 /* Loop through all pattern ACLs. */
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; // FIXME
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 /* And access is allowed. */
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
318static 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 // topic [read|write] <topic>
342 // user <user>
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
424static 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
437static 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 /* As we're freeing ACLs, we must clear context->acl_list to ensure no
446 * invalid memory accesses take place later.
447 * This *requires* the ACLs to be reapplied after _acl_cleanup()
448 * is called if we are reloading the config. If this is not done, all
449 * access will be denied to currently connected clients.
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
478static 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
537static 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 /* Need to decode password into hashed data + salt. */
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
599static 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 /* We haven't been asked to parse a psk file. */
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 /* Check for hex only digits */
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
626int 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
670static 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/* Apply security settings after a reload.
692 * Includes:
693 * - Disconnecting anonymous users if appropriate
694 * - Disconnecting users with invalid passwords
695 * - Reapplying ACLs
696 */
697int 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 /* Check for anonymous clients when allow_anonymous is false */
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 /* Check for connected clients that are no longer authorised */
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 /* Check for ACLs and apply to user. */
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
748int 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
766int _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 // FIXME fprintf(stderr, "Error: Unable to create openssl digest.\n");
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 /* hash is assumed to be EVP_MAX_MD_SIZE bytes long. */
782 EVP_DigestFinal_ex(&context, hash, hash_len);
783 EVP_MD_CTX_cleanup(&context);
784
785 return MOSQ_ERR_SUCCESS;
786}
787
788int _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