1 /*
2 Copyright (c) 2011-2020 Roger Light <roger@atchoo.org>
3
4 All rights reserved. This program and the accompanying materials
5 are made available under the terms of the Eclipse Public License 2.0
6 and Eclipse Distribution License v1.0 which accompany this distribution.
7
8 The Eclipse Public License is available at
9 https://www.eclipse.org/legal/epl-2.0/
10 and the Eclipse Distribution License is available at
11 http://www.eclipse.org/org/documents/edl-v10.php.
12
13 SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
14
15 Contributors:
16 Roger Light - initial implementation and documentation.
17 */
18
19 #include "config.h"
20
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 #include "mosquitto_broker_internal.h"
26 #include "memory_mosq.h"
27 #include "mqtt_protocol.h"
28 #include "send_mosq.h"
29 #include "misc_mosq.h"
30 #include "util_mosq.h"
31
32 static int aclfile__parse(struct mosquitto__security_options *security_opts);
33 static int unpwd__file_parse(struct mosquitto__unpwd **unpwd, const char *password_file);
34 static int acl__cleanup(bool reload);
35 static int unpwd__cleanup(struct mosquitto__unpwd **unpwd, bool reload);
36 static int psk__file_parse(struct mosquitto__unpwd **psk_id, const char *psk_file);
37 #ifdef WITH_TLS
38 static int pw__digest(const char *password, const unsigned char *salt, unsigned int salt_len, unsigned char *hash, unsigned int *hash_len, enum mosquitto_pwhash_type hashtype, int iterations);
39 #endif
40 static int mosquitto_unpwd_check_default(int event, void *event_data, void *userdata);
41 static int mosquitto_acl_check_default(int event, void *event_data, void *userdata);
42
43
44
mosquitto_security_init_default(bool reload)45 int mosquitto_security_init_default(bool reload)
46 {
47 int rc;
48 int i;
49 char *pwf;
50 char *pskf = NULL;
51
52 UNUSED(reload);
53
54 /* Configure plugin identifier */
55 if(db.config->per_listener_settings){
56 for(i=0; i<db.config->listener_count; i++){
57 db.config->listeners[i].security_options.pid = mosquitto__calloc(1, sizeof(mosquitto_plugin_id_t));
58 if(db.config->listeners[i].security_options.pid == NULL){
59 log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
60 return MOSQ_ERR_NOMEM;
61 }
62 db.config->listeners[i].security_options.pid->listener = &db.config->listeners[i];
63 }
64 }else{
65 db.config->security_options.pid = mosquitto__calloc(1, sizeof(mosquitto_plugin_id_t));
66 if(db.config->security_options.pid == NULL){
67 log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
68 return MOSQ_ERR_NOMEM;
69 }
70 }
71
72 /* Load username/password data if required. */
73 if(db.config->per_listener_settings){
74 for(i=0; i<db.config->listener_count; i++){
75 pwf = db.config->listeners[i].security_options.password_file;
76 if(pwf){
77 rc = unpwd__file_parse(&db.config->listeners[i].security_options.unpwd, pwf);
78 if(rc){
79 log__printf(NULL, MOSQ_LOG_ERR, "Error opening password file \"%s\".", pwf);
80 return rc;
81 }
82 mosquitto_callback_register(db.config->listeners[i].security_options.pid,
83 MOSQ_EVT_BASIC_AUTH, mosquitto_unpwd_check_default, NULL, NULL);
84 }
85 }
86 }else{
87 if(db.config->security_options.password_file){
88 pwf = db.config->security_options.password_file;
89 if(pwf){
90 rc = unpwd__file_parse(&db.config->security_options.unpwd, pwf);
91 if(rc){
92 log__printf(NULL, MOSQ_LOG_ERR, "Error opening password file \"%s\".", pwf);
93 return rc;
94 }
95 }
96 mosquitto_callback_register(db.config->security_options.pid,
97 MOSQ_EVT_BASIC_AUTH, mosquitto_unpwd_check_default, NULL, NULL);
98 }
99 }
100
101 /* Load acl data if required. */
102 if(db.config->per_listener_settings){
103 for(i=0; i<db.config->listener_count; i++){
104 if(db.config->listeners[i].security_options.acl_file){
105 rc = aclfile__parse(&db.config->listeners[i].security_options);
106 if(rc){
107 log__printf(NULL, MOSQ_LOG_ERR, "Error opening acl file \"%s\".", db.config->listeners[i].security_options.acl_file);
108 return rc;
109 }
110 mosquitto_callback_register(db.config->listeners[i].security_options.pid,
111 MOSQ_EVT_ACL_CHECK, mosquitto_acl_check_default, NULL, NULL);
112 }
113 }
114 }else{
115 if(db.config->security_options.acl_file){
116 rc = aclfile__parse(&db.config->security_options);
117 if(rc){
118 log__printf(NULL, MOSQ_LOG_ERR, "Error opening acl file \"%s\".", db.config->security_options.acl_file);
119 return rc;
120 }
121 mosquitto_callback_register(db.config->security_options.pid,
122 MOSQ_EVT_ACL_CHECK, mosquitto_acl_check_default, NULL, NULL);
123 }
124 }
125
126 /* Load psk data if required. */
127 if(db.config->per_listener_settings){
128 for(i=0; i<db.config->listener_count; i++){
129 pskf = db.config->listeners[i].security_options.psk_file;
130 if(pskf){
131 rc = psk__file_parse(&db.config->listeners[i].security_options.psk_id, pskf);
132 if(rc){
133 log__printf(NULL, MOSQ_LOG_ERR, "Error opening psk file \"%s\".", pskf);
134 return rc;
135 }
136 }
137 }
138 }else{
139 pskf = db.config->security_options.psk_file;
140 if(pskf){
141 rc = psk__file_parse(&db.config->security_options.psk_id, pskf);
142 if(rc){
143 log__printf(NULL, MOSQ_LOG_ERR, "Error opening psk file \"%s\".", pskf);
144 return rc;
145 }
146 }
147 }
148
149 return MOSQ_ERR_SUCCESS;
150 }
151
mosquitto_security_cleanup_default(bool reload)152 int mosquitto_security_cleanup_default(bool reload)
153 {
154 int rc;
155 int i;
156
157 rc = acl__cleanup(reload);
158 if(rc != MOSQ_ERR_SUCCESS) return rc;
159
160 rc = unpwd__cleanup(&db.config->security_options.unpwd, reload);
161 if(rc != MOSQ_ERR_SUCCESS) return rc;
162
163 for(i=0; i<db.config->listener_count; i++){
164 if(db.config->listeners[i].security_options.unpwd){
165 rc = unpwd__cleanup(&db.config->listeners[i].security_options.unpwd, reload);
166 if(rc != MOSQ_ERR_SUCCESS) return rc;
167 }
168 }
169
170 rc = unpwd__cleanup(&db.config->security_options.psk_id, reload);
171 if(rc != MOSQ_ERR_SUCCESS) return rc;
172
173 for(i=0; i<db.config->listener_count; i++){
174 if(db.config->listeners[i].security_options.psk_id){
175 rc = unpwd__cleanup(&db.config->listeners[i].security_options.psk_id, reload);
176 if(rc != MOSQ_ERR_SUCCESS) return rc;
177 }
178 }
179
180 if(db.config->per_listener_settings){
181 for(i=0; i<db.config->listener_count; i++){
182 if(db.config->listeners[i].security_options.pid){
183 mosquitto_callback_unregister(db.config->listeners[i].security_options.pid,
184 MOSQ_EVT_BASIC_AUTH, mosquitto_unpwd_check_default, NULL);
185 mosquitto_callback_unregister(db.config->listeners[i].security_options.pid,
186 MOSQ_EVT_ACL_CHECK, mosquitto_acl_check_default, NULL);
187
188 mosquitto__free(db.config->listeners[i].security_options.pid);
189 }
190 }
191 }else{
192 if(db.config->security_options.pid){
193 mosquitto_callback_unregister(db.config->security_options.pid,
194 MOSQ_EVT_BASIC_AUTH, mosquitto_unpwd_check_default, NULL);
195 mosquitto_callback_unregister(db.config->security_options.pid,
196 MOSQ_EVT_ACL_CHECK, mosquitto_acl_check_default, NULL);
197
198 mosquitto__free(db.config->security_options.pid);
199 }
200 }
201 return MOSQ_ERR_SUCCESS;
202 }
203
204
add__acl(struct mosquitto__security_options * security_opts,const char * user,const char * topic,int access)205 static int add__acl(struct mosquitto__security_options *security_opts, const char *user, const char *topic, int access)
206 {
207 struct mosquitto__acl_user *acl_user=NULL, *user_tail;
208 struct mosquitto__acl *acl, *acl_tail;
209 char *local_topic;
210 bool new_user = false;
211
212 if(!security_opts || !topic) return MOSQ_ERR_INVAL;
213
214 local_topic = mosquitto__strdup(topic);
215 if(!local_topic){
216 return MOSQ_ERR_NOMEM;
217 }
218
219 if(security_opts->acl_list){
220 user_tail = security_opts->acl_list;
221 while(user_tail){
222 if(user == NULL){
223 if(user_tail->username == NULL){
224 acl_user = user_tail;
225 break;
226 }
227 }else if(user_tail->username && !strcmp(user_tail->username, user)){
228 acl_user = user_tail;
229 break;
230 }
231 user_tail = user_tail->next;
232 }
233 }
234 if(!acl_user){
235 acl_user = mosquitto__malloc(sizeof(struct mosquitto__acl_user));
236 if(!acl_user){
237 mosquitto__free(local_topic);
238 return MOSQ_ERR_NOMEM;
239 }
240 new_user = true;
241 if(user){
242 acl_user->username = mosquitto__strdup(user);
243 if(!acl_user->username){
244 mosquitto__free(local_topic);
245 mosquitto__free(acl_user);
246 return MOSQ_ERR_NOMEM;
247 }
248 }else{
249 acl_user->username = NULL;
250 }
251 acl_user->next = NULL;
252 acl_user->acl = NULL;
253 }
254
255 acl = mosquitto__malloc(sizeof(struct mosquitto__acl));
256 if(!acl){
257 mosquitto__free(local_topic);
258 mosquitto__free(acl_user->username);
259 mosquitto__free(acl_user);
260 return MOSQ_ERR_NOMEM;
261 }
262 acl->access = access;
263 acl->topic = local_topic;
264 acl->next = NULL;
265 acl->ccount = 0;
266 acl->ucount = 0;
267
268 /* Add acl to user acl list */
269 if(acl_user->acl){
270 acl_tail = acl_user->acl;
271 if(access == MOSQ_ACL_NONE){
272 /* Put "deny" acls at front of the list */
273 acl->next = acl_tail;
274 acl_user->acl = acl;
275 }else{
276 while(acl_tail->next){
277 acl_tail = acl_tail->next;
278 }
279 acl_tail->next = acl;
280 }
281 }else{
282 acl_user->acl = acl;
283 }
284
285 if(new_user){
286 /* Add to end of list */
287 if(security_opts->acl_list){
288 user_tail = security_opts->acl_list;
289 while(user_tail->next){
290 user_tail = user_tail->next;
291 }
292 user_tail->next = acl_user;
293 }else{
294 security_opts->acl_list = acl_user;
295 }
296 }
297
298 return MOSQ_ERR_SUCCESS;
299 }
300
add__acl_pattern(struct mosquitto__security_options * security_opts,const char * topic,int access)301 static int add__acl_pattern(struct mosquitto__security_options *security_opts, const char *topic, int access)
302 {
303 struct mosquitto__acl *acl, *acl_tail;
304 char *local_topic;
305 char *s;
306
307 if(!security_opts| !topic) return MOSQ_ERR_INVAL;
308
309 local_topic = mosquitto__strdup(topic);
310 if(!local_topic){
311 return MOSQ_ERR_NOMEM;
312 }
313
314 acl = mosquitto__malloc(sizeof(struct mosquitto__acl));
315 if(!acl){
316 mosquitto__free(local_topic);
317 return MOSQ_ERR_NOMEM;
318 }
319 acl->access = access;
320 acl->topic = local_topic;
321 acl->next = NULL;
322
323 acl->ccount = 0;
324 s = local_topic;
325 while(s){
326 s = strstr(s, "%c");
327 if(s){
328 acl->ccount++;
329 s+=2;
330 }
331 }
332
333 acl->ucount = 0;
334 s = local_topic;
335 while(s){
336 s = strstr(s, "%u");
337 if(s){
338 acl->ucount++;
339 s+=2;
340 }
341 }
342
343 if(acl->ccount == 0 && acl->ucount == 0){
344 log__printf(NULL, MOSQ_LOG_WARNING,
345 "Warning: ACL pattern '%s' does not contain '%%c' or '%%u'.",
346 topic);
347 }
348
349 if(security_opts->acl_patterns){
350 acl_tail = security_opts->acl_patterns;
351 if(access == MOSQ_ACL_NONE){
352 /* Put "deny" acls at front of the list */
353 acl->next = acl_tail;
354 security_opts->acl_patterns = acl;
355 }else{
356 while(acl_tail->next){
357 acl_tail = acl_tail->next;
358 }
359 acl_tail->next = acl;
360 }
361 }else{
362 security_opts->acl_patterns = acl;
363 }
364
365 return MOSQ_ERR_SUCCESS;
366 }
367
mosquitto_acl_check_default(int event,void * event_data,void * userdata)368 static int mosquitto_acl_check_default(int event, void *event_data, void *userdata)
369 {
370 struct mosquitto_evt_acl_check *ed = event_data;
371 char *local_acl;
372 struct mosquitto__acl *acl_root;
373 bool result;
374 size_t i;
375 size_t len, tlen, clen, ulen;
376 char *s;
377 struct mosquitto__security_options *security_opts = NULL;
378
379 UNUSED(event);
380 UNUSED(userdata);
381
382 if(ed->client->bridge) return MOSQ_ERR_SUCCESS;
383 if(ed->access == MOSQ_ACL_SUBSCRIBE || ed->access == MOSQ_ACL_UNSUBSCRIBE) return MOSQ_ERR_SUCCESS; /* FIXME - implement ACL subscription strings. */
384
385 if(db.config->per_listener_settings){
386 if(!ed->client->listener) return MOSQ_ERR_ACL_DENIED;
387 security_opts = &ed->client->listener->security_options;
388 }else{
389 security_opts = &db.config->security_options;
390 }
391 if(!security_opts->acl_file && !security_opts->acl_list && !security_opts->acl_patterns){
392 return MOSQ_ERR_PLUGIN_DEFER;
393 }
394
395 if(!ed->client->acl_list && !security_opts->acl_patterns) return MOSQ_ERR_ACL_DENIED;
396
397 if(ed->client->acl_list){
398 acl_root = ed->client->acl_list->acl;
399 }else{
400 acl_root = NULL;
401 }
402
403 /* Loop through all ACLs for this client. ACL denials are iterated over first. */
404 while(acl_root){
405 /* Loop through the topic looking for matches to this ACL. */
406
407 /* If subscription starts with $, acl_root->topic must also start with $. */
408 if(ed->topic[0] == '$' && acl_root->topic[0] != '$'){
409 acl_root = acl_root->next;
410 continue;
411 }
412 mosquitto_topic_matches_sub(acl_root->topic, ed->topic, &result);
413 if(result){
414 if(acl_root->access == MOSQ_ACL_NONE){
415 /* Access was explicitly denied for this topic. */
416 return MOSQ_ERR_ACL_DENIED;
417 }
418 if(ed->access & acl_root->access){
419 /* And access is allowed. */
420 return MOSQ_ERR_SUCCESS;
421 }
422 }
423 acl_root = acl_root->next;
424 }
425
426 acl_root = security_opts->acl_patterns;
427
428 if(acl_root){
429 /* We are using pattern based acls. Check whether the username or
430 * client id contains a + or # and if so deny access.
431 *
432 * Without this, a malicious client may configure its username/client
433 * id to bypass ACL checks (or have a username/client id that cannot
434 * publish or receive messages to its own place in the hierarchy).
435 */
436 if(ed->client->username && strpbrk(ed->client->username, "+#")){
437 log__printf(NULL, MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous username \"%s\"", ed->client->username);
438 return MOSQ_ERR_ACL_DENIED;
439 }
440
441 if(ed->client->id && strpbrk(ed->client->id, "+#")){
442 log__printf(NULL, MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous client id \"%s\"", ed->client->id);
443 return MOSQ_ERR_ACL_DENIED;
444 }
445 }
446
447 /* Loop through all pattern ACLs. ACL denial patterns are iterated over first. */
448 if(!ed->client->id) return MOSQ_ERR_ACL_DENIED;
449 clen = strlen(ed->client->id);
450
451 while(acl_root){
452 tlen = strlen(acl_root->topic);
453
454 if(acl_root->ucount && !ed->client->username){
455 acl_root = acl_root->next;
456 continue;
457 }
458
459 if(ed->client->username){
460 ulen = strlen(ed->client->username);
461 len = tlen + (size_t)acl_root->ccount*(clen-2) + (size_t)acl_root->ucount*(ulen-2);
462 }else{
463 ulen = 0;
464 len = tlen + (size_t)acl_root->ccount*(clen-2);
465 }
466 local_acl = mosquitto__malloc(len+1);
467 if(!local_acl) return MOSQ_ERR_NOMEM;
468 s = local_acl;
469 for(i=0; i<tlen; i++){
470 if(i<tlen-1 && acl_root->topic[i] == '%'){
471 if(acl_root->topic[i+1] == 'c'){
472 i++;
473 strncpy(s, ed->client->id, clen);
474 s+=clen;
475 continue;
476 }else if(ed->client->username && acl_root->topic[i+1] == 'u'){
477 i++;
478 strncpy(s, ed->client->username, ulen);
479 s+=ulen;
480 continue;
481 }
482 }
483 s[0] = acl_root->topic[i];
484 s++;
485 }
486 local_acl[len] = '\0';
487
488 mosquitto_topic_matches_sub(local_acl, ed->topic, &result);
489 mosquitto__free(local_acl);
490 if(result){
491 if(acl_root->access == MOSQ_ACL_NONE){
492 /* Access was explicitly denied for this topic pattern. */
493 return MOSQ_ERR_ACL_DENIED;
494 }
495 if(ed->access & acl_root->access){
496 /* And access is allowed. */
497 return MOSQ_ERR_SUCCESS;
498 }
499 }
500
501 acl_root = acl_root->next;
502 }
503
504 return MOSQ_ERR_ACL_DENIED;
505 }
506
507
aclfile__parse(struct mosquitto__security_options * security_opts)508 static int aclfile__parse(struct mosquitto__security_options *security_opts)
509 {
510 FILE *aclfptr = NULL;
511 char *token;
512 char *user = NULL;
513 char *topic;
514 char *access_s;
515 int access;
516 int rc = MOSQ_ERR_SUCCESS;
517 size_t slen;
518 int topic_pattern;
519 char *saveptr = NULL;
520 char *buf = NULL;
521 int buflen = 256;
522
523 if(!db.config) return MOSQ_ERR_INVAL;
524 if(!security_opts) return MOSQ_ERR_INVAL;
525 if(!security_opts->acl_file) return MOSQ_ERR_SUCCESS;
526
527 buf = mosquitto__malloc((size_t)buflen);
528 if(buf == NULL){
529 log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
530 return MOSQ_ERR_NOMEM;
531 }
532
533 aclfptr = mosquitto__fopen(security_opts->acl_file, "rt", false);
534 if(!aclfptr){
535 mosquitto__free(buf);
536 log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open acl_file \"%s\".", security_opts->acl_file);
537 return MOSQ_ERR_UNKNOWN;
538 }
539
540 /* topic [read|write] <topic>
541 * user <user>
542 */
543
544 while(fgets_extending(&buf, &buflen, aclfptr)){
545 slen = strlen(buf);
546 while(slen > 0 && isspace(buf[slen-1])){
547 buf[slen-1] = '\0';
548 slen = strlen(buf);
549 }
550 if(buf[0] == '#'){
551 continue;
552 }
553 token = strtok_r(buf, " ", &saveptr);
554 if(token){
555 if(!strcmp(token, "topic") || !strcmp(token, "pattern")){
556 if(!strcmp(token, "topic")){
557 topic_pattern = 0;
558 }else{
559 topic_pattern = 1;
560 }
561
562 access_s = strtok_r(NULL, " ", &saveptr);
563 if(!access_s){
564 log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty topic in acl_file \"%s\".", security_opts->acl_file);
565 rc = MOSQ_ERR_INVAL;
566 break;
567 }
568 token = strtok_r(NULL, "", &saveptr);
569 if(token){
570 topic = misc__trimblanks(token);
571 }else{
572 topic = access_s;
573 access_s = NULL;
574 }
575 if(access_s){
576 if(!strcmp(access_s, "read")){
577 access = MOSQ_ACL_READ;
578 }else if(!strcmp(access_s, "write")){
579 access = MOSQ_ACL_WRITE;
580 }else if(!strcmp(access_s, "readwrite")){
581 access = MOSQ_ACL_READ | MOSQ_ACL_WRITE;
582 }else if(!strcmp(access_s, "deny")){
583 access = MOSQ_ACL_NONE;
584 }else{
585 log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid topic access type \"%s\" in acl_file \"%s\".", access_s, security_opts->acl_file);
586 rc = MOSQ_ERR_INVAL;
587 break;
588 }
589 }else{
590 access = MOSQ_ACL_READ | MOSQ_ACL_WRITE;
591 }
592 rc = mosquitto_sub_topic_check(topic);
593 if(rc != MOSQ_ERR_SUCCESS){
594 log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid ACL topic \"%s\" in acl_file \"%s\".", topic, security_opts->acl_file);
595 rc = MOSQ_ERR_INVAL;
596 break;
597 }
598
599 if(topic_pattern == 0){
600 rc = add__acl(security_opts, user, topic, access);
601 }else{
602 rc = add__acl_pattern(security_opts, topic, access);
603 }
604 if(rc){
605 break;
606 }
607 }else if(!strcmp(token, "user")){
608 token = strtok_r(NULL, "", &saveptr);
609 if(token){
610 token = misc__trimblanks(token);
611 if(slen == 0){
612 log__printf(NULL, MOSQ_LOG_ERR, "Error: Missing username in acl_file \"%s\".", security_opts->acl_file);
613 rc = MOSQ_ERR_INVAL;
614 break;
615 }
616 mosquitto__free(user);
617 user = mosquitto__strdup(token);
618 if(!user){
619 rc = MOSQ_ERR_NOMEM;
620 break;
621 }
622 }else{
623 log__printf(NULL, MOSQ_LOG_ERR, "Error: Missing username in acl_file \"%s\".", security_opts->acl_file);
624 rc = MOSQ_ERR_INVAL;
625 break;
626 }
627 }else{
628 log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid line in acl_file \"%s\": %s.", security_opts->acl_file, buf);
629 rc = MOSQ_ERR_INVAL;
630 break;
631 }
632 }
633 }
634
635 mosquitto__free(buf);
636 mosquitto__free(user);
637 fclose(aclfptr);
638
639 return rc;
640 }
641
free__acl(struct mosquitto__acl * acl)642 static void free__acl(struct mosquitto__acl *acl)
643 {
644 if(!acl) return;
645
646 if(acl->next){
647 free__acl(acl->next);
648 }
649 mosquitto__free(acl->topic);
650 mosquitto__free(acl);
651 }
652
653
acl__cleanup_single(struct mosquitto__security_options * security_opts)654 static void acl__cleanup_single(struct mosquitto__security_options *security_opts)
655 {
656 struct mosquitto__acl_user *user_tail;
657
658 while(security_opts->acl_list){
659 user_tail = security_opts->acl_list->next;
660
661 free__acl(security_opts->acl_list->acl);
662 mosquitto__free(security_opts->acl_list->username);
663 mosquitto__free(security_opts->acl_list);
664
665 security_opts->acl_list = user_tail;
666 }
667
668 if(security_opts->acl_patterns){
669 free__acl(security_opts->acl_patterns);
670 security_opts->acl_patterns = NULL;
671 }
672 }
673
674
acl__cleanup(bool reload)675 static int acl__cleanup(bool reload)
676 {
677 struct mosquitto *context, *ctxt_tmp = NULL;
678 int i;
679
680 UNUSED(reload);
681
682 /* As we're freeing ACLs, we must clear context->acl_list to ensure no
683 * invalid memory accesses take place later.
684 * This *requires* the ACLs to be reapplied after acl__cleanup()
685 * is called if we are reloading the config. If this is not done, all
686 * access will be denied to currently connected clients.
687 */
688 HASH_ITER(hh_id, db.contexts_by_id, context, ctxt_tmp){
689 context->acl_list = NULL;
690 }
691
692 if(db.config->per_listener_settings){
693 for(i=0; i<db.config->listener_count; i++){
694 acl__cleanup_single(&db.config->listeners[i].security_options);
695 }
696 }else{
697 acl__cleanup_single(&db.config->security_options);
698 }
699
700 return MOSQ_ERR_SUCCESS;
701 }
702
703
acl__find_acls(struct mosquitto * context)704 int acl__find_acls(struct mosquitto *context)
705 {
706 struct mosquitto__acl_user *acl_tail;
707 struct mosquitto__security_options *security_opts;
708
709 /* Associate user with its ACL, assuming we have ACLs loaded. */
710 if(db.config->per_listener_settings){
711 if(!context->listener){
712 return MOSQ_ERR_INVAL;
713 }
714 security_opts = &context->listener->security_options;
715 }else{
716 security_opts = &db.config->security_options;
717 }
718
719 if(security_opts->acl_list){
720 acl_tail = security_opts->acl_list;
721 while(acl_tail){
722 if(context->username){
723 if(acl_tail->username && !strcmp(context->username, acl_tail->username)){
724 context->acl_list = acl_tail;
725 break;
726 }
727 }else{
728 if(acl_tail->username == NULL){
729 context->acl_list = acl_tail;
730 break;
731 }
732 }
733 acl_tail = acl_tail->next;
734 }
735 }else{
736 context->acl_list = NULL;
737 }
738
739 return MOSQ_ERR_SUCCESS;
740 }
741
742
pwfile__parse(const char * file,struct mosquitto__unpwd ** root)743 static int pwfile__parse(const char *file, struct mosquitto__unpwd **root)
744 {
745 FILE *pwfile;
746 struct mosquitto__unpwd *unpwd;
747 char *username, *password;
748 char *saveptr = NULL;
749 char *buf;
750 int buflen = 256;
751
752 buf = mosquitto__malloc((size_t)buflen);
753 if(buf == NULL){
754 log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
755 return MOSQ_ERR_NOMEM;
756 }
757
758 pwfile = mosquitto__fopen(file, "rt", false);
759 if(!pwfile){
760 log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open pwfile \"%s\".", file);
761 mosquitto__free(buf);
762 return MOSQ_ERR_UNKNOWN;
763 }
764
765 while(!feof(pwfile)){
766 if(fgets_extending(&buf, &buflen, pwfile)){
767 if(buf[0] == '#') continue;
768 if(!strchr(buf, ':')) continue;
769
770 username = strtok_r(buf, ":", &saveptr);
771 if(username){
772 unpwd = mosquitto__calloc(1, sizeof(struct mosquitto__unpwd));
773 if(!unpwd){
774 fclose(pwfile);
775 mosquitto__free(buf);
776 return MOSQ_ERR_NOMEM;
777 }
778 username = misc__trimblanks(username);
779 if(strlen(username) > 65535){
780 log__printf(NULL, MOSQ_LOG_NOTICE, "Warning: Invalid line in password file '%s', username too long.", file);
781 mosquitto__free(unpwd);
782 continue;
783 }
784
785 unpwd->username = mosquitto__strdup(username);
786 if(!unpwd->username){
787 mosquitto__free(unpwd);
788 mosquitto__free(buf);
789 fclose(pwfile);
790 return MOSQ_ERR_NOMEM;
791 }
792 password = strtok_r(NULL, ":", &saveptr);
793 if(password){
794 password = misc__trimblanks(password);
795
796 if(strlen(password) > 65535){
797 log__printf(NULL, MOSQ_LOG_NOTICE, "Warning: Invalid line in password file '%s', password too long.", file);
798 mosquitto__free(unpwd->username);
799 mosquitto__free(unpwd);
800 continue;
801 }
802
803 unpwd->password = mosquitto__strdup(password);
804 if(!unpwd->password){
805 fclose(pwfile);
806 mosquitto__free(unpwd->username);
807 mosquitto__free(unpwd);
808 mosquitto__free(buf);
809 return MOSQ_ERR_NOMEM;
810 }
811
812 HASH_ADD_KEYPTR(hh, *root, unpwd->username, strlen(unpwd->username), unpwd);
813 }else{
814 log__printf(NULL, MOSQ_LOG_NOTICE, "Warning: Invalid line in password file '%s': %s", file, buf);
815 mosquitto__free(unpwd->username);
816 mosquitto__free(unpwd);
817 }
818 }
819 }
820 }
821 fclose(pwfile);
822 mosquitto__free(buf);
823
824 return MOSQ_ERR_SUCCESS;
825 }
826
827
unpwd__free_item(struct mosquitto__unpwd ** unpwd,struct mosquitto__unpwd * item)828 void unpwd__free_item(struct mosquitto__unpwd **unpwd, struct mosquitto__unpwd *item)
829 {
830 mosquitto__free(item->username);
831 mosquitto__free(item->password);
832 #ifdef WITH_TLS
833 mosquitto__free(item->salt);
834 #endif
835 HASH_DEL(*unpwd, item);
836 mosquitto__free(item);
837 }
838
839
840 #ifdef WITH_TLS
unpwd__decode_passwords(struct mosquitto__unpwd ** unpwd)841 static int unpwd__decode_passwords(struct mosquitto__unpwd **unpwd)
842 {
843 struct mosquitto__unpwd *u, *tmp = NULL;
844 char *token;
845 unsigned char *salt;
846 unsigned int salt_len;
847 unsigned char *password;
848 unsigned int password_len;
849 int rc;
850 enum mosquitto_pwhash_type hashtype;
851
852 HASH_ITER(hh, *unpwd, u, tmp){
853 /* Need to decode password into hashed data + salt. */
854 if(u->password == NULL){
855 log__printf(NULL, MOSQ_LOG_ERR, "Error: Missing password hash for user %s, removing entry.", u->username);
856 unpwd__free_item(unpwd, u);
857 continue;
858 }
859
860 token = strtok(u->password, "$");
861 if(token == NULL){
862 log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s, removing entry.", u->username);
863 unpwd__free_item(unpwd, u);
864 continue;
865 }
866
867 if(!strcmp(token, "6")){
868 hashtype = pw_sha512;
869 }else if(!strcmp(token, "7")){
870 hashtype = pw_sha512_pbkdf2;
871 }else{
872 log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash type for user %s, removing entry.", u->username);
873 unpwd__free_item(unpwd, u);
874 continue;
875 }
876
877 if(hashtype == pw_sha512_pbkdf2){
878 token = strtok(NULL, "$");
879 if(token == NULL){
880 log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s, removing entry.", u->username);
881 unpwd__free_item(unpwd, u);
882 continue;
883 }
884 u->iterations = atoi(token);
885 if(u->iterations < 1){
886 log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid hash iterations for user %s, removing entry.", u->username);
887 unpwd__free_item(unpwd, u);
888 continue;
889 }
890 }
891
892 token = strtok(NULL, "$");
893 if(token == NULL){
894 log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s, removing entry.", u->username);
895 unpwd__free_item(unpwd, u);
896 continue;
897 }
898 rc = base64__decode(token, &salt, &salt_len);
899 if(rc == MOSQ_ERR_SUCCESS && salt_len == 12){
900 u->salt = salt;
901 u->salt_len = salt_len;
902 token = strtok(NULL, "$");
903 if(token){
904 rc = base64__decode(token, &password, &password_len);
905 if(rc == MOSQ_ERR_SUCCESS && password_len == 64){
906 mosquitto__free(u->password);
907 u->password = (char *)password;
908 u->password_len = password_len;
909 u->hashtype = hashtype;
910 }else{
911 log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to decode password for user %s, removing entry.", u->username);
912 unpwd__free_item(unpwd, u);
913 }
914 }else{
915 log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s, removing entry.", u->username);
916 unpwd__free_item(unpwd, u);
917 }
918 }else{
919 log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to decode password salt for user %s, removing entry.", u->username);
920 unpwd__free_item(unpwd, u);
921 }
922 }
923
924 return MOSQ_ERR_SUCCESS;
925 }
926 #endif
927
928
unpwd__file_parse(struct mosquitto__unpwd ** unpwd,const char * password_file)929 static int unpwd__file_parse(struct mosquitto__unpwd **unpwd, const char *password_file)
930 {
931 int rc;
932 if(!unpwd) return MOSQ_ERR_INVAL;
933
934 if(!password_file) return MOSQ_ERR_SUCCESS;
935
936 rc = pwfile__parse(password_file, unpwd);
937
938 #ifdef WITH_TLS
939 if(rc) return rc;
940 rc = unpwd__decode_passwords(unpwd);
941 #endif
942
943 return rc;
944 }
945
psk__file_parse(struct mosquitto__unpwd ** psk_id,const char * psk_file)946 static int psk__file_parse(struct mosquitto__unpwd **psk_id, const char *psk_file)
947 {
948 int rc;
949 struct mosquitto__unpwd *u, *tmp = NULL;
950
951 if(!db.config || !psk_id) return MOSQ_ERR_INVAL;
952
953 /* We haven't been asked to parse a psk file. */
954 if(!psk_file) return MOSQ_ERR_SUCCESS;
955
956 rc = pwfile__parse(psk_file, psk_id);
957 if(rc) return rc;
958
959 HASH_ITER(hh, (*psk_id), u, tmp){
960 /* Check for hex only digits */
961 if(!u->password){
962 log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty psk for identity \"%s\".", u->username);
963 return MOSQ_ERR_INVAL;
964 }
965 if(strspn(u->password, "0123456789abcdefABCDEF") < strlen(u->password)){
966 log__printf(NULL, MOSQ_LOG_ERR, "Error: psk for identity \"%s\" contains non-hexadecimal characters.", u->username);
967 return MOSQ_ERR_INVAL;
968 }
969 }
970 return MOSQ_ERR_SUCCESS;
971 }
972
973
974 #ifdef WITH_TLS
mosquitto__memcmp_const(const void * a,const void * b,size_t len)975 static int mosquitto__memcmp_const(const void *a, const void *b, size_t len)
976 {
977 size_t i;
978 int rc = 0;
979
980 if(!a || !b) return 1;
981
982 for(i=0; i<len; i++){
983 if( ((char *)a)[i] != ((char *)b)[i] ){
984 rc = 1;
985 }
986 }
987 return rc;
988 }
989 #endif
990
991
mosquitto_unpwd_check_default(int event,void * event_data,void * userdata)992 static int mosquitto_unpwd_check_default(int event, void *event_data, void *userdata)
993 {
994 struct mosquitto_evt_basic_auth *ed = event_data;
995 struct mosquitto__unpwd *u;
996 struct mosquitto__unpwd *unpwd_ref;
997 #ifdef WITH_TLS
998 unsigned char hash[EVP_MAX_MD_SIZE];
999 unsigned int hash_len;
1000 int rc;
1001 #endif
1002
1003 UNUSED(event);
1004 UNUSED(userdata);
1005
1006 if(ed->client->username == NULL){
1007 return MOSQ_ERR_PLUGIN_DEFER;
1008 }
1009
1010 if(db.config->per_listener_settings){
1011 if(ed->client->bridge) return MOSQ_ERR_SUCCESS;
1012 if(!ed->client->listener) return MOSQ_ERR_INVAL;
1013 unpwd_ref = ed->client->listener->security_options.unpwd;
1014 }else{
1015 unpwd_ref = db.config->security_options.unpwd;
1016 }
1017
1018 HASH_FIND(hh, unpwd_ref, ed->client->username, strlen(ed->client->username), u);
1019 if(u){
1020 if(u->password){
1021 if(ed->client->password){
1022 #ifdef WITH_TLS
1023 rc = pw__digest(ed->client->password, u->salt, u->salt_len, hash, &hash_len, u->hashtype, u->iterations);
1024 if(rc == MOSQ_ERR_SUCCESS){
1025 if(hash_len == u->password_len && !mosquitto__memcmp_const(u->password, hash, hash_len)){
1026 return MOSQ_ERR_SUCCESS;
1027 }else{
1028 return MOSQ_ERR_AUTH;
1029 }
1030 }else{
1031 return rc;
1032 }
1033 #else
1034 if(!strcmp(u->password, ed->client->password)){
1035 return MOSQ_ERR_SUCCESS;
1036 }
1037 #endif
1038 }else{
1039 return MOSQ_ERR_AUTH;
1040 }
1041 }else{
1042 return MOSQ_ERR_SUCCESS;
1043 }
1044 }
1045
1046 return MOSQ_ERR_AUTH;
1047 }
1048
unpwd__cleanup(struct mosquitto__unpwd ** root,bool reload)1049 static int unpwd__cleanup(struct mosquitto__unpwd **root, bool reload)
1050 {
1051 struct mosquitto__unpwd *u, *tmp = NULL;
1052
1053 UNUSED(reload);
1054
1055 if(!root) return MOSQ_ERR_INVAL;
1056
1057 HASH_ITER(hh, *root, u, tmp){
1058 HASH_DEL(*root, u);
1059 mosquitto__free(u->password);
1060 mosquitto__free(u->username);
1061 #ifdef WITH_TLS
1062 mosquitto__free(u->salt);
1063 #endif
1064 mosquitto__free(u);
1065 }
1066
1067 *root = NULL;
1068
1069 return MOSQ_ERR_SUCCESS;
1070 }
1071
1072
1073 #ifdef WITH_TLS
security__disconnect_auth(struct mosquitto * context)1074 static void security__disconnect_auth(struct mosquitto *context)
1075 {
1076 if(context->protocol == mosq_p_mqtt5){
1077 send__disconnect(context, MQTT_RC_ADMINISTRATIVE_ACTION, NULL);
1078 }
1079 mosquitto__set_state(context, mosq_cs_disconnecting);
1080 do_disconnect(context, MOSQ_ERR_AUTH);
1081 }
1082 #endif
1083
1084 /* Apply security settings after a reload.
1085 * Includes:
1086 * - Disconnecting anonymous users if appropriate
1087 * - Disconnecting users with invalid passwords
1088 * - Reapplying ACLs
1089 */
mosquitto_security_apply_default(void)1090 int mosquitto_security_apply_default(void)
1091 {
1092 struct mosquitto *context, *ctxt_tmp = NULL;
1093 struct mosquitto__acl_user *acl_user_tail;
1094 bool allow_anonymous;
1095 struct mosquitto__security_options *security_opts = NULL;
1096 #ifdef WITH_TLS
1097 int i;
1098 X509 *client_cert = NULL;
1099 X509_NAME *name;
1100 X509_NAME_ENTRY *name_entry;
1101 ASN1_STRING *name_asn1 = NULL;
1102 struct mosquitto__listener *listener;
1103 BIO *subject_bio;
1104 char *data_start;
1105 size_t name_length;
1106 char *subject;
1107 #endif
1108
1109 #ifdef WITH_TLS
1110 for(i=0; i<db.config->listener_count; i++){
1111 listener = &db.config->listeners[i];
1112 if(listener && listener->ssl_ctx && listener->certfile && listener->keyfile && listener->crlfile && listener->require_certificate){
1113 if(net__tls_server_ctx(listener)){
1114 return MOSQ_ERR_TLS;
1115 }
1116
1117 if(net__tls_load_verify(listener)){
1118 return MOSQ_ERR_TLS;
1119 }
1120 }
1121 }
1122 #endif
1123
1124 HASH_ITER(hh_id, db.contexts_by_id, context, ctxt_tmp){
1125 if(context->bridge){
1126 continue;
1127 }
1128
1129 /* Check for anonymous clients when allow_anonymous is false */
1130 if(db.config->per_listener_settings){
1131 if(context->listener){
1132 allow_anonymous = context->listener->security_options.allow_anonymous;
1133 }else{
1134 /* Client not currently connected, so defer judgement until it does connect */
1135 allow_anonymous = true;
1136 }
1137 }else{
1138 allow_anonymous = db.config->security_options.allow_anonymous;
1139 }
1140
1141 if(!allow_anonymous && !context->username){
1142 mosquitto__set_state(context, mosq_cs_disconnecting);
1143 do_disconnect(context, MOSQ_ERR_AUTH);
1144 continue;
1145 }
1146
1147 /* Check for connected clients that are no longer authorised */
1148 #ifdef WITH_TLS
1149 if(context->listener && context->listener->ssl_ctx && (context->listener->use_identity_as_username || context->listener->use_subject_as_username)){
1150 /* Client must have either a valid certificate, or valid PSK used as a username. */
1151 if(!context->ssl){
1152 if(context->protocol == mosq_p_mqtt5){
1153 send__disconnect(context, MQTT_RC_ADMINISTRATIVE_ACTION, NULL);
1154 }
1155 mosquitto__set_state(context, mosq_cs_disconnecting);
1156 do_disconnect(context, MOSQ_ERR_AUTH);
1157 continue;
1158 }
1159 #ifdef FINAL_WITH_TLS_PSK
1160 if(context->listener->psk_hint){
1161 /* Client should have provided an identity to get this far. */
1162 if(!context->username){
1163 security__disconnect_auth(context);
1164 continue;
1165 }
1166 }else
1167 #endif /* FINAL_WITH_TLS_PSK */
1168 {
1169 /* Free existing credentials and then recover them. */
1170 mosquitto__free(context->username);
1171 context->username = NULL;
1172 mosquitto__free(context->password);
1173 context->password = NULL;
1174
1175 client_cert = SSL_get_peer_certificate(context->ssl);
1176 if(!client_cert){
1177 security__disconnect_auth(context);
1178 continue;
1179 }
1180 name = X509_get_subject_name(client_cert);
1181 if(!name){
1182 X509_free(client_cert);
1183 client_cert = NULL;
1184 security__disconnect_auth(context);
1185 continue;
1186 }
1187 if (context->listener->use_identity_as_username) { /* use_identity_as_username */
1188 i = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
1189 if(i == -1){
1190 X509_free(client_cert);
1191 client_cert = NULL;
1192 security__disconnect_auth(context);
1193 continue;
1194 }
1195 name_entry = X509_NAME_get_entry(name, i);
1196 if(name_entry){
1197 name_asn1 = X509_NAME_ENTRY_get_data(name_entry);
1198 if (name_asn1 == NULL) {
1199 X509_free(client_cert);
1200 client_cert = NULL;
1201 security__disconnect_auth(context);
1202 continue;
1203 }
1204 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1205 context->username = mosquitto__strdup((char *) ASN1_STRING_data(name_asn1));
1206 #else
1207 context->username = mosquitto__strdup((char *) ASN1_STRING_get0_data(name_asn1));
1208 #endif
1209 if(!context->username){
1210 X509_free(client_cert);
1211 client_cert = NULL;
1212 security__disconnect_auth(context);
1213 continue;
1214 }
1215 /* Make sure there isn't an embedded NUL character in the CN */
1216 if ((size_t)ASN1_STRING_length(name_asn1) != strlen(context->username)) {
1217 X509_free(client_cert);
1218 client_cert = NULL;
1219 security__disconnect_auth(context);
1220 continue;
1221 }
1222 }
1223 } else { /* use_subject_as_username */
1224 subject_bio = BIO_new(BIO_s_mem());
1225 X509_NAME_print_ex(subject_bio, X509_get_subject_name(client_cert), 0, XN_FLAG_RFC2253);
1226 data_start = NULL;
1227 name_length = (size_t)BIO_get_mem_data(subject_bio, &data_start);
1228 subject = mosquitto__malloc(sizeof(char)*name_length+1);
1229 if(!subject){
1230 BIO_free(subject_bio);
1231 X509_free(client_cert);
1232 client_cert = NULL;
1233 security__disconnect_auth(context);
1234 continue;
1235 }
1236 memcpy(subject, data_start, name_length);
1237 subject[name_length] = '\0';
1238 BIO_free(subject_bio);
1239 context->username = subject;
1240 }
1241 if(!context->username){
1242 X509_free(client_cert);
1243 client_cert = NULL;
1244 security__disconnect_auth(context);
1245 continue;
1246 }
1247 X509_free(client_cert);
1248 client_cert = NULL;
1249 }
1250 }else
1251 #endif
1252 {
1253 /* Username/password check only if the identity/subject check not used */
1254 if(mosquitto_unpwd_check(context) != MOSQ_ERR_SUCCESS){
1255 mosquitto__set_state(context, mosq_cs_disconnecting);
1256 do_disconnect(context, MOSQ_ERR_AUTH);
1257 continue;
1258 }
1259 }
1260
1261
1262 /* Check for ACLs and apply to user. */
1263 if(db.config->per_listener_settings){
1264 if(context->listener){
1265 security_opts = &context->listener->security_options;
1266 }else{
1267 if(context->state != mosq_cs_active){
1268 mosquitto__set_state(context, mosq_cs_disconnecting);
1269 do_disconnect(context, MOSQ_ERR_AUTH);
1270 continue;
1271 }
1272 }
1273 }else{
1274 security_opts = &db.config->security_options;
1275 }
1276
1277 if(security_opts && security_opts->acl_list){
1278 acl_user_tail = security_opts->acl_list;
1279 while(acl_user_tail){
1280 if(acl_user_tail->username){
1281 if(context->username){
1282 if(!strcmp(acl_user_tail->username, context->username)){
1283 context->acl_list = acl_user_tail;
1284 break;
1285 }
1286 }
1287 }else{
1288 if(!context->username){
1289 context->acl_list = acl_user_tail;
1290 break;
1291 }
1292 }
1293 acl_user_tail = acl_user_tail->next;
1294 }
1295 }
1296 }
1297 return MOSQ_ERR_SUCCESS;
1298 }
1299
mosquitto_psk_key_get_default(struct mosquitto * context,const char * hint,const char * identity,char * key,int max_key_len)1300 int mosquitto_psk_key_get_default(struct mosquitto *context, const char *hint, const char *identity, char *key, int max_key_len)
1301 {
1302 struct mosquitto__unpwd *u, *tmp = NULL;
1303 struct mosquitto__unpwd *psk_id_ref = NULL;
1304
1305 if(!hint || !identity || !key) return MOSQ_ERR_INVAL;
1306
1307 if(db.config->per_listener_settings){
1308 if(!context->listener) return MOSQ_ERR_INVAL;
1309 psk_id_ref = context->listener->security_options.psk_id;
1310 }else{
1311 psk_id_ref = db.config->security_options.psk_id;
1312 }
1313 if(!psk_id_ref) return MOSQ_ERR_PLUGIN_DEFER;
1314
1315 HASH_ITER(hh, psk_id_ref, u, tmp){
1316 if(!strcmp(u->username, identity)){
1317 strncpy(key, u->password, (size_t)max_key_len);
1318 return MOSQ_ERR_SUCCESS;
1319 }
1320 }
1321
1322 return MOSQ_ERR_AUTH;
1323 }
1324
1325 #ifdef WITH_TLS
pw__digest(const char * password,const unsigned char * salt,unsigned int salt_len,unsigned char * hash,unsigned int * hash_len,enum mosquitto_pwhash_type hashtype,int iterations)1326 int pw__digest(const char *password, const unsigned char *salt, unsigned int salt_len, unsigned char *hash, unsigned int *hash_len, enum mosquitto_pwhash_type hashtype, int iterations)
1327 {
1328 const EVP_MD *digest;
1329 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1330 EVP_MD_CTX context;
1331 #else
1332 EVP_MD_CTX *context;
1333 #endif
1334
1335 digest = EVP_get_digestbyname("sha512");
1336 if(!digest){
1337 /* FIXME fprintf(stderr, "Error: Unable to create openssl digest.\n"); */
1338 return 1;
1339 }
1340
1341 if(hashtype == pw_sha512){
1342 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1343 EVP_MD_CTX_init(&context);
1344 EVP_DigestInit_ex(&context, digest, NULL);
1345 EVP_DigestUpdate(&context, password, strlen(password));
1346 EVP_DigestUpdate(&context, salt, salt_len);
1347 /* hash is assumed to be EVP_MAX_MD_SIZE bytes long. */
1348 EVP_DigestFinal_ex(&context, hash, hash_len);
1349 EVP_MD_CTX_cleanup(&context);
1350 #else
1351 context = EVP_MD_CTX_new();
1352 EVP_DigestInit_ex(context, digest, NULL);
1353 EVP_DigestUpdate(context, password, strlen(password));
1354 EVP_DigestUpdate(context, salt, salt_len);
1355 /* hash is assumed to be EVP_MAX_MD_SIZE bytes long. */
1356 EVP_DigestFinal_ex(context, hash, hash_len);
1357 EVP_MD_CTX_free(context);
1358 #endif
1359 }else{
1360 *hash_len = EVP_MAX_MD_SIZE;
1361 PKCS5_PBKDF2_HMAC(password, (int)strlen(password),
1362 salt, (int)salt_len, iterations,
1363 digest, (int)(*hash_len), hash);
1364 }
1365
1366 return MOSQ_ERR_SUCCESS;
1367 }
1368
1369 #endif
1370