Coverage Report

Created: 2025-08-26 06:48

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