/src/dropbear/src/cli-readconf.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | #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 | 0 | void read_config_file(char* filename, FILE* config_file, cli_runopts* options) { |
57 | 0 | char *line = NULL; |
58 | 0 | int linenum = 0; |
59 | 0 | buffer *buf = NULL; |
60 | 0 | char* cfg_key; |
61 | 0 | char* cfg_val; |
62 | 0 | char* saveptr; |
63 | 0 | int in_host_section = 0; |
64 | |
|
65 | 0 | DEBUG1(("Reading '%.200s'", filename)); |
66 | |
|
67 | 0 | buf = buf_new(MAX_CONF_LINE); |
68 | 0 | line = buf->data; |
69 | 0 | while (buf_getline(buf, config_file) == DROPBEAR_SUCCESS) { |
70 | 0 | char* commentStart = NULL; |
71 | 0 | cfg_option cfg_opt; |
72 | 0 | int found; |
73 | 0 | size_t i; |
74 | | /* Update line number counter. */ |
75 | 0 | linenum++; |
76 | | |
77 | | /* Add nul terminator */ |
78 | 0 | if (buf->len == buf->size) { |
79 | 0 | dropbear_exit("Long line %s:%d", filename, linenum); |
80 | 0 | } |
81 | 0 | buf_setpos(buf, buf->len); |
82 | 0 | buf_putbyte(buf, '\0'); |
83 | 0 | buf_setpos(buf, 0); |
84 | |
|
85 | 0 | commentStart = strchr(line, '#'); |
86 | 0 | if (NULL != commentStart) { |
87 | 0 | *commentStart = '\0'; /* Drop the comments. */ |
88 | 0 | } |
89 | |
|
90 | 0 | cfg_key = strtok_r(line, TOKEN_CHARS, &saveptr); |
91 | 0 | if (NULL == cfg_key) { |
92 | 0 | continue; |
93 | 0 | } |
94 | | |
95 | 0 | found = 0; |
96 | 0 | for (i = 0; i < ARRAY_SIZE(config_options); i++) { |
97 | 0 | if (0 == strcasecmp(cfg_key, config_options[i].name)) { |
98 | 0 | cfg_opt = config_options[i].option; |
99 | 0 | found = 1; |
100 | 0 | break; |
101 | 0 | } |
102 | 0 | } |
103 | |
|
104 | 0 | if (!found) { |
105 | 0 | dropbear_exit("Unsupported option %s at %s:%d", cfg_key, filename, linenum); |
106 | 0 | } |
107 | | |
108 | | |
109 | 0 | cfg_val = strtok_r(NULL, TOKEN_CHARS, &saveptr); |
110 | 0 | if (NULL == cfg_val) { |
111 | 0 | dropbear_exit("Missing value for %s at %s:%d", cfg_key, filename, linenum); |
112 | 0 | } |
113 | | |
114 | 0 | if (in_host_section) { |
115 | 0 | switch (cfg_opt) { |
116 | 0 | case opHost: { |
117 | | /* Hit the next host section. Done reading config. */ |
118 | 0 | goto outloop; |
119 | 0 | } |
120 | 0 | 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 | 0 | m_free(options->remotehost); |
125 | 0 | options->remotehost = m_strdup(cfg_val); |
126 | 0 | options->remotehostfixed = 1; /* Subsequent command line parsing should leave it alone. */ |
127 | 0 | break; |
128 | 0 | } |
129 | | |
130 | 0 | case opHostPort: { |
131 | 0 | m_free(options->remoteport); |
132 | 0 | options->remoteport = m_strdup(cfg_val); |
133 | 0 | break; |
134 | 0 | } |
135 | | |
136 | 0 | case opLoginUser: { |
137 | 0 | m_free(options->username); |
138 | 0 | options->username = m_strdup(cfg_val); |
139 | 0 | break; |
140 | 0 | } |
141 | | |
142 | 0 | case opIdentityFile: { |
143 | 0 | #if DROPBEAR_CLI_PUBKEY_AUTH |
144 | 0 | char* key_file_path; |
145 | 0 | if (strncmp(cfg_val, "~/", 2) == 0) { |
146 | 0 | key_file_path = expand_homedir_path(cfg_val); |
147 | 0 | } else if (cfg_val[0] != '/') { |
148 | 0 | char* config_dir = dirname(filename); |
149 | 0 | int path_len = strlen(config_dir) + strlen(cfg_val) + 10; |
150 | 0 | key_file_path = m_malloc(path_len); |
151 | 0 | snprintf(key_file_path, path_len, "%s/%s", config_dir, cfg_val); |
152 | 0 | } else { |
153 | 0 | key_file_path = m_strdup(cfg_val); |
154 | 0 | } |
155 | 0 | loadidentityfile(key_file_path, 1); |
156 | 0 | m_free(key_file_path); |
157 | | #else |
158 | | dropbear_exit("identityfile isn't supported in %s", filename); |
159 | | #endif |
160 | 0 | break; |
161 | 0 | } |
162 | 0 | } |
163 | 0 | } |
164 | 0 | else |
165 | 0 | { |
166 | 0 | if (opHost != cfg_opt || 0 != strcmp(cfg_val, options->remotehost)) { |
167 | | /* Not our host section. */ |
168 | 0 | continue; |
169 | 0 | } |
170 | 0 | in_host_section = 1; |
171 | 0 | } |
172 | 0 | } |
173 | 0 | outloop: |
174 | 0 | buf_free(buf); |
175 | 0 | } |
176 | | |
177 | | #endif /* DROPBEAR_USE_SSH_CONFIG */ |