/src/mosquitto/plugins/password-file/password_parse.c
Line | Count | Source |
1 | | /* |
2 | | Copyright (c) 2011-2021 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.h" |
26 | | #include "password_file.h" |
27 | | |
28 | | |
29 | | int password_file__parse(struct password_file_data *data) |
30 | 1.03k | { |
31 | 1.03k | FILE *pwfile; |
32 | 1.03k | struct mosquitto__unpwd *unpwd = NULL; |
33 | 1.03k | char *username, *password; |
34 | 1.03k | char *saveptr = NULL; |
35 | 1.03k | char *buf; |
36 | 1.03k | int buflen = 256; |
37 | 1.03k | int rc = MOSQ_ERR_INVAL; |
38 | | |
39 | 1.03k | buf = mosquitto_malloc((size_t)buflen); |
40 | 1.03k | if(buf == NULL){ |
41 | 0 | mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Out of memory."); |
42 | 0 | return MOSQ_ERR_NOMEM; |
43 | 0 | } |
44 | | |
45 | 1.03k | pwfile = mosquitto_fopen(data->password_file, "rt", true); |
46 | 1.03k | if(!pwfile){ |
47 | 0 | mosquitto_log_printf(MOSQ_LOG_ERR, "password-file: Error: Unable to open pwfile \"%s\".", data->password_file); |
48 | 0 | mosquitto_FREE(buf); |
49 | 0 | return MOSQ_ERR_UNKNOWN; |
50 | 0 | } |
51 | | |
52 | 20.3k | while(!feof(pwfile)){ |
53 | 20.0k | if(mosquitto_fgets(&buf, &buflen, pwfile)){ |
54 | 18.3k | unpwd = NULL; |
55 | | |
56 | 18.3k | if(buf[0] == '#'){ |
57 | 201 | continue; |
58 | 201 | } |
59 | 18.1k | if(!strchr(buf, ':')){ |
60 | 3.10k | continue; |
61 | 3.10k | } |
62 | | |
63 | 15.0k | username = strtok_r(buf, ":", &saveptr); |
64 | 15.0k | if(username){ |
65 | 15.0k | username = mosquitto_trimblanks(username); |
66 | 15.0k | if(strlen(username) > 65535){ |
67 | 3 | mosquitto_log_printf(MOSQ_LOG_ERR, "password-file: Error: Invalid line in password file '%s', username too long.", data->password_file); |
68 | 3 | goto error; |
69 | 3 | } |
70 | 15.0k | if(strlen(username) <= 0){ |
71 | 12 | mosquitto_log_printf(MOSQ_LOG_ERR, "password-file: Error: Empty username in password file '%s'.", data->password_file); |
72 | 12 | goto error; |
73 | 12 | } |
74 | | |
75 | 14.9k | HASH_FIND(hh, data->unpwd, username, strlen(username), unpwd); |
76 | 14.9k | if(unpwd){ |
77 | 20 | unpwd = NULL; |
78 | 20 | mosquitto_log_printf(MOSQ_LOG_ERR, "password-file: Error: Duplicate user '%s' in password file '%s'.", username, data->password_file); |
79 | 20 | goto error; |
80 | 20 | } |
81 | | |
82 | 14.9k | unpwd = mosquitto_calloc(1, sizeof(struct mosquitto__unpwd)); |
83 | 14.9k | if(!unpwd){ |
84 | 0 | goto error; |
85 | 0 | } |
86 | | |
87 | 14.9k | unpwd->username = mosquitto_strdup(username); |
88 | 14.9k | if(!unpwd->username){ |
89 | 0 | rc = MOSQ_ERR_NOMEM; |
90 | 0 | goto error; |
91 | 0 | } |
92 | 14.9k | password = strtok_r(NULL, ":", &saveptr); |
93 | 14.9k | if(password){ |
94 | 14.7k | password = mosquitto_trimblanks(password); |
95 | | |
96 | 14.7k | if(strlen(password) > 65535){ |
97 | 7 | mosquitto_log_printf(MOSQ_LOG_ERR, "password-file: Error: Invalid line in password file '%s', password too long.", data->password_file); |
98 | 7 | goto error; |
99 | 7 | } |
100 | | |
101 | 14.7k | if(mosquitto_pw_new(&unpwd->pw, MOSQ_PW_DEFAULT) |
102 | 14.7k | || mosquitto_pw_decode(unpwd->pw, password)){ |
103 | | |
104 | 474 | mosquitto_log_printf(MOSQ_LOG_ERR, "password-file: Error: Unable to decode line in password file '%s'.", data->password_file); |
105 | 474 | goto error; |
106 | 474 | } |
107 | | |
108 | 14.2k | HASH_ADD_KEYPTR(hh, data->unpwd, unpwd->username, strlen(unpwd->username), unpwd); |
109 | 14.2k | }else{ |
110 | 204 | mosquitto_log_printf(MOSQ_LOG_ERR, "password-file: Error: Invalid line in password file '%s': %s", data->password_file, buf); |
111 | 204 | goto error; |
112 | 204 | } |
113 | 14.9k | } |
114 | 15.0k | } |
115 | 20.0k | } |
116 | 316 | fclose(pwfile); |
117 | 316 | mosquitto_FREE(buf); |
118 | | |
119 | 316 | return MOSQ_ERR_SUCCESS; |
120 | 720 | error: |
121 | 720 | if(unpwd){ |
122 | 685 | mosquitto_pw_cleanup(unpwd->pw); |
123 | 685 | mosquitto_FREE(unpwd->username); |
124 | 685 | mosquitto_FREE(unpwd); |
125 | 685 | } |
126 | 720 | mosquitto_FREE(buf); |
127 | 720 | fclose(pwfile); |
128 | 720 | return rc; |
129 | 1.03k | } |
130 | | |
131 | | |
132 | | void password_file__cleanup(struct password_file_data *data) |
133 | 3.16k | { |
134 | 3.16k | struct mosquitto__unpwd *u, *tmp = NULL; |
135 | | |
136 | 3.16k | if(!data){ |
137 | 0 | return; |
138 | 0 | } |
139 | | |
140 | 14.2k | HASH_ITER(hh, data->unpwd, u, tmp){ |
141 | 14.2k | HASH_DEL(data->unpwd, u); |
142 | 14.2k | mosquitto_pw_cleanup(u->pw); |
143 | 14.2k | mosquitto_FREE(u->username); |
144 | 14.2k | mosquitto_FREE(u); |
145 | 14.2k | } |
146 | 3.16k | } |
147 | | |
148 | | |
149 | | int password_file__reload(int event, void *event_data, void *userdata) |
150 | 0 | { |
151 | 0 | struct password_file_data *data = userdata; |
152 | |
|
153 | 0 | UNUSED(event); |
154 | 0 | UNUSED(event_data); |
155 | |
|
156 | 0 | password_file__cleanup(data); |
157 | 0 | return password_file__parse(data); |
158 | 0 | } |