Coverage Report

Created: 2025-11-10 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dropbear/src/cli-readconf.c
Line
Count
Source
1
/*
2
 * Dropbear - a SSH2 server
3
 *
4
 * Copyright (c) 2023 TJ Kolev
5
 * All rights reserved.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
 * SOFTWARE. */
24
25
#include "dbutil.h"
26
#include "runopts.h"
27
28
#if DROPBEAR_USE_SSH_CONFIG
29
30
8.04k
#define TOKEN_CHARS " =\t\n"
31
32
static const size_t MAX_CONF_LINE = 200;
33
34
typedef enum {
35
  opHost,
36
  opHostName,
37
  opHostPort,
38
  opLoginUser,
39
  opIdentityFile,
40
} cfg_option;
41
42
static const struct {
43
  const char *name;
44
  cfg_option option;
45
}
46
config_options[] = {
47
  /* Start of config section. */
48
  { "host", opHost },
49
50
  { "hostname", opHostName },
51
  { "port", opHostPort },
52
  { "user", opLoginUser },
53
  { "identityfile", opIdentityFile },
54
};
55
56
354
void read_config_file(char* filename, FILE* config_file, cli_runopts* options) {
57
354
  char *line = NULL;
58
354
  int linenum = 0;
59
354
  buffer *buf = NULL;
60
354
  char* cfg_key;
61
354
  char* cfg_val;
62
354
  char* saveptr;
63
354
  int in_host_section = 0;
64
65
354
  DEBUG1(("Reading '%.200s'", filename));
66
67
354
  buf = buf_new(MAX_CONF_LINE);
68
354
  line = buf->data;
69
5.34k
  while (buf_getline(buf, config_file) == DROPBEAR_SUCCESS) {
70
5.17k
    char* commentStart = NULL;
71
5.17k
    cfg_option cfg_opt;
72
5.17k
    int found;
73
5.17k
    size_t i;
74
    /* Update line number counter. */
75
5.17k
    linenum++;
76
77
    /* Add nul terminator */
78
5.17k
    if (buf->len == buf->size) {
79
0
      dropbear_exit("Long line %s:%d", filename, linenum);
80
0
    }
81
5.17k
    buf_setpos(buf, buf->len);
82
5.17k
    buf_putbyte(buf, '\0');
83
5.17k
    buf_setpos(buf, 0);
84
85
5.17k
    commentStart = strchr(line, '#');
86
5.17k
    if (NULL != commentStart) {
87
206
      *commentStart = '\0'; /* Drop the comments. */
88
206
    }
89
90
5.17k
    cfg_key = strtok_r(line, TOKEN_CHARS, &saveptr);
91
5.17k
    if (NULL == cfg_key) {
92
2.12k
      continue;
93
2.12k
    }
94
95
3.04k
    found = 0;
96
11.9k
    for (i = 0; i < ARRAY_SIZE(config_options); i++) {
97
11.8k
      if (0 == strcasecmp(cfg_key, config_options[i].name)) {
98
2.87k
        cfg_opt = config_options[i].option;
99
2.87k
        found = 1;
100
2.87k
        break;
101
2.87k
      }
102
11.8k
    }
103
104
3.04k
    if (!found) {
105
175
      dropbear_exit("Unsupported option %s at %s:%d", cfg_key, filename, linenum);
106
175
    }
107
108
109
2.87k
    cfg_val = strtok_r(NULL, TOKEN_CHARS, &saveptr);
110
2.87k
    if (NULL == cfg_val) {
111
10
      dropbear_exit("Missing value for %s at %s:%d", cfg_key, filename, linenum);
112
10
    }
113
114
2.86k
    if (in_host_section) {
115
2.19k
      switch (cfg_opt) {
116
1
        case opHost: {
117
          /* Hit the next host section. Done reading config. */
118
1
          goto outloop;
119
0
        }
120
195
        case opHostName: {
121
          /* The host name is the alias given on the command line.
122
           * Set the actual remote host specified in the config.
123
           */
124
195
          m_free(options->remotehost);
125
195
          options->remotehost = m_strdup(cfg_val);
126
195
          options->remotehostfixed = 1; /* Subsequent command line parsing should leave it alone. */
127
195
          break;
128
0
        }
129
130
335
        case opHostPort: {
131
335
          m_free(options->remoteport);
132
335
          options->remoteport = m_strdup(cfg_val);
133
335
          break;
134
0
        }
135
136
459
        case opLoginUser: {
137
459
          m_free(options->username);
138
459
          options->username = m_strdup(cfg_val);
139
459
          break;
140
0
        }
141
142
1.20k
        case opIdentityFile: {
143
1.20k
#if DROPBEAR_CLI_PUBKEY_AUTH
144
1.20k
          char* key_file_path;
145
1.20k
          if (strncmp(cfg_val, "~/", 2) == 0) {
146
260
            key_file_path = expand_homedir_path(cfg_val);
147
949
          } else if (cfg_val[0] != '/') {
148
499
            char* config_dir = dirname(filename);
149
499
            int path_len = strlen(config_dir) + strlen(cfg_val) + 10;
150
499
            key_file_path = m_malloc(path_len);
151
499
            snprintf(key_file_path, path_len, "%s/%s", config_dir, cfg_val);
152
499
          } else {
153
450
            key_file_path = m_strdup(cfg_val);
154
450
          }
155
1.20k
          loadidentityfile(key_file_path, 1);
156
1.20k
          m_free(key_file_path);
157
#else
158
          dropbear_exit("identityfile isn't supported in %s", filename);
159
#endif
160
1.20k
          break;
161
0
        }
162
2.19k
      }
163
2.19k
    }
164
664
    else
165
664
    {
166
664
      if (opHost != cfg_opt || 0 != strcmp(cfg_val, options->remotehost)) {
167
        /* Not our host section. */
168
560
        continue;
169
560
      }
170
104
      in_host_section = 1;
171
104
    }
172
2.86k
  }
173
169
outloop:
174
169
  buf_free(buf);
175
169
}
176
177
#endif /* DROPBEAR_USE_SSH_CONFIG */