Coverage Report

Created: 2026-07-25 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}