1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of
5 * the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
15 * MA 02111-1307 USA
16 */
17/*
18 * Part of Very Secure FTPd
19 * Licence: GPL v2
20 * Author: Chris Evans
21 * parseconf.c
22 *
23 * Routines and support to load in a file full of tunable variables and
24 * settings, populating corresponding runtime variables.
25 */
26
27#include "parseconf.h"
28#include "tunables.h"
29#include "str.h"
30#include "filestr.h"
31#include "defs.h"
32#include "sysutil.h"
33#include "utility.h"
34
35static const char* s_p_saved_filename;
36static int s_strings_copied;
37
38/* File local functions */
39static void handle_config_setting(struct mystr* p_setting_str,
40                                  struct mystr* p_value_str,
41                                  int errs_fatal);
42
43static void copy_string_settings(void);
44
45/* Tables mapping setting names to runtime variables */
46/* Boolean settings */
47static struct parseconf_bool_setting
48{
49  const char* p_setting_name;
50  int* p_variable;
51}
52parseconf_bool_array[] =
53{
54  { "anonymous_enable", &tunable_anonymous_enable },
55  { "local_enable", &tunable_local_enable },
56  { "pasv_enable", &tunable_pasv_enable },
57  { "port_enable", &tunable_port_enable },
58  { "chroot_local_user", &tunable_chroot_local_user },
59  { "write_enable", &tunable_write_enable },
60  { "anon_upload_enable", &tunable_anon_upload_enable },
61  { "anon_mkdir_write_enable", &tunable_anon_mkdir_write_enable },
62  { "anon_other_write_enable", &tunable_anon_other_write_enable },
63  { "chown_uploads", &tunable_chown_uploads },
64  { "connect_from_port_20", &tunable_connect_from_port_20 },
65  { "xferlog_enable", &tunable_xferlog_enable },
66  { "dirmessage_enable", &tunable_dirmessage_enable },
67  { "anon_world_readable_only", &tunable_anon_world_readable_only },
68  { "async_abor_enable", &tunable_async_abor_enable },
69  { "ascii_upload_enable", &tunable_ascii_upload_enable },
70  { "ascii_download_enable", &tunable_ascii_download_enable },
71  { "one_process_model", &tunable_one_process_model },
72  { "xferlog_std_format", &tunable_xferlog_std_format },
73  { "pasv_promiscuous", &tunable_pasv_promiscuous },
74  { "deny_email_enable", &tunable_deny_email_enable },
75  { "chroot_list_enable", &tunable_chroot_list_enable },
76  { "setproctitle_enable", &tunable_setproctitle_enable },
77  { "text_userdb_names", &tunable_text_userdb_names },
78  { "ls_recurse_enable", &tunable_ls_recurse_enable },
79  { "log_ftp_protocol", &tunable_log_ftp_protocol },
80  { "guest_enable", &tunable_guest_enable },
81  { "userlist_enable", &tunable_userlist_enable },
82  { "userlist_deny", &tunable_userlist_deny },
83  { "use_localtime", &tunable_use_localtime },
84  { "check_shell", &tunable_check_shell },
85  { "hide_ids", &tunable_hide_ids },
86  { "listen", &tunable_listen },
87  { "port_promiscuous", &tunable_port_promiscuous },
88  { "passwd_chroot_enable", &tunable_passwd_chroot_enable },
89  { "no_anon_password", &tunable_no_anon_password },
90  { "tcp_wrappers", &tunable_tcp_wrappers },
91  { "use_sendfile", &tunable_use_sendfile },
92  { "force_dot_files", &tunable_force_dot_files },
93  { "listen_ipv6", &tunable_listen_ipv6 },
94  { "dual_log_enable", &tunable_dual_log_enable },
95  { "syslog_enable", &tunable_syslog_enable },
96  { "background", &tunable_background },
97  { "virtual_use_local_privs", &tunable_virtual_use_local_privs },
98  { "session_support", &tunable_session_support },
99  { "download_enable", &tunable_download_enable },
100  { "dirlist_enable", &tunable_dirlist_enable },
101  { "chmod_enable", &tunable_chmod_enable },
102  { "secure_email_list_enable", &tunable_secure_email_list_enable },
103  { "run_as_launching_user", &tunable_run_as_launching_user },
104  { "no_log_lock", &tunable_no_log_lock },
105  { "ssl_enable", &tunable_ssl_enable },
106  { "allow_anon_ssl", &tunable_allow_anon_ssl },
107  { "force_local_logins_ssl", &tunable_force_local_logins_ssl },
108  { "force_local_data_ssl", &tunable_force_local_data_ssl },
109  { "ssl_sslv2", &tunable_sslv2 },
110  { "ssl_sslv3", &tunable_sslv3 },
111  { "ssl_tlsv1", &tunable_tlsv1 },
112  { "tilde_user_enable", &tunable_tilde_user_enable },
113  { "enable_iconv", &tunable_enable_iconv },	// Jiahao
114  { "force_anon_logins_ssl", &tunable_force_anon_logins_ssl },
115  { "force_anon_data_ssl", &tunable_force_anon_data_ssl },
116  { "mdtm_write", &tunable_mdtm_write },
117  { "lock_upload_files", &tunable_lock_upload_files },
118  { "pasv_addr_resolve", &tunable_pasv_addr_resolve },
119  { 0, 0 }
120};
121
122static struct parseconf_uint_setting
123{
124  const char* p_setting_name;
125  unsigned int* p_variable;
126}
127parseconf_uint_array[] =
128{
129  { "accept_timeout", &tunable_accept_timeout },
130  { "connect_timeout", &tunable_connect_timeout },
131  { "local_umask", &tunable_local_umask },
132  { "anon_umask", &tunable_anon_umask },
133  { "ftp_data_port", &tunable_ftp_data_port },
134  { "idle_session_timeout", &tunable_idle_session_timeout },
135  { "data_connection_timeout", &tunable_data_connection_timeout },
136  { "pasv_min_port", &tunable_pasv_min_port },
137  { "pasv_max_port", &tunable_pasv_max_port },
138  { "anon_max_rate", &tunable_anon_max_rate },
139  { "local_max_rate", &tunable_local_max_rate },
140  { "listen_port", &tunable_listen_port },
141  { "max_clients", &tunable_max_clients },
142  { "file_open_mode", &tunable_file_open_mode },
143  { "max_per_ip", &tunable_max_per_ip },
144  { "trans_chunk_size", &tunable_trans_chunk_size },
145  { 0, 0 }
146};
147
148static struct parseconf_str_setting
149{
150  const char* p_setting_name;
151  const char** p_variable;
152}
153parseconf_str_array[] =
154{
155  { "secure_chroot_dir", &tunable_secure_chroot_dir },
156  { "ftp_username", &tunable_ftp_username },
157  { "chown_username", &tunable_chown_username },
158  { "xferlog_file", &tunable_xferlog_file },
159  { "vsftpd_log_file", &tunable_vsftpd_log_file },
160  { "message_file", &tunable_message_file },
161  { "nopriv_user", &tunable_nopriv_user },
162  { "ftpd_banner", &tunable_ftpd_banner },
163  { "banned_email_file", &tunable_banned_email_file },
164  { "chroot_list_file", &tunable_chroot_list_file },
165  { "pam_service_name", &tunable_pam_service_name },
166  { "guest_username", &tunable_guest_username },
167  { "userlist_file", &tunable_userlist_file },
168  { "anon_root", &tunable_anon_root },
169  { "local_root", &tunable_local_root },
170  { "banner_file", &tunable_banner_file },
171  { "pasv_address", &tunable_pasv_address },
172  { "listen_address", &tunable_listen_address },
173  { "user_config_dir", &tunable_user_config_dir },
174  { "listen_address6", &tunable_listen_address6 },
175  { "cmds_allowed", &tunable_cmds_allowed },
176  { "hide_file", &tunable_hide_file },
177  { "deny_file", &tunable_deny_file },
178  { "user_sub_token", &tunable_user_sub_token },
179  { "email_password_file", &tunable_email_password_file },
180  { "rsa_cert_file", &tunable_rsa_cert_file },
181  { "dsa_cert_file", &tunable_dsa_cert_file },
182  { "ssl_ciphers", &tunable_ssl_ciphers },
183  { "local_charset", &tunable_local_charset },		// Jiahao
184  { "remote_charset", &tunable_remote_charset },	// Jiahao
185  { "rsa_private_key_file", &tunable_rsa_private_key_file },
186  { "dsa_private_key_file", &tunable_dsa_private_key_file },
187  { 0, 0 }
188};
189
190void
191vsf_parseconf_load_file(const char* p_filename, int errs_fatal)
192{
193  struct mystr config_file_str = INIT_MYSTR;
194  struct mystr config_setting_str = INIT_MYSTR;
195  struct mystr config_value_str = INIT_MYSTR;
196  unsigned int str_pos = 0;
197  int retval;
198  if (!p_filename)
199  {
200    p_filename = s_p_saved_filename;
201  }
202  else
203  {
204    if (s_p_saved_filename)
205    {
206      vsf_sysutil_free((char*)s_p_saved_filename);
207    }
208    s_p_saved_filename = vsf_sysutil_strdup(p_filename);
209  }
210  if (!p_filename)
211  {
212    bug("null filename in vsf_parseconf_load_file");
213  }
214  if (!s_strings_copied)
215  {
216    s_strings_copied = 1;
217    /* A minor hack to make sure all strings are malloc()'ed so we can free
218     * them at some later date. Specifically handles strings embedded in the
219     * binary.
220     */
221    copy_string_settings();
222  }
223  retval = str_fileread(&config_file_str, p_filename, VSFTP_CONF_FILE_MAX);
224  if (vsf_sysutil_retval_is_error(retval))
225  {
226    if (errs_fatal)
227    {
228      die2("cannot open config file:", p_filename);
229    }
230    else
231    {
232      return;
233    }
234  }
235  while (str_getline(&config_file_str, &config_setting_str, &str_pos))
236  {
237    if (str_isempty(&config_setting_str) ||
238        str_get_char_at(&config_setting_str, 0) == '#')
239    {
240      continue;
241    }
242    /* Split into name=value pair */
243    str_split_char(&config_setting_str, &config_value_str, '=');
244    handle_config_setting(&config_setting_str, &config_value_str, errs_fatal);
245  }
246  str_free(&config_file_str);
247  str_free(&config_setting_str);
248  str_free(&config_value_str);
249}
250
251static void
252handle_config_setting(struct mystr* p_setting_str, struct mystr* p_value_str,
253                      int errs_fatal)
254{
255  /* Is it a string setting? */
256  {
257    const struct parseconf_str_setting* p_str_setting = parseconf_str_array;
258    while (p_str_setting->p_setting_name != 0)
259    {
260      if (str_equal_text(p_setting_str, p_str_setting->p_setting_name))
261      {
262        /* Got it */
263        const char** p_curr_setting = p_str_setting->p_variable;
264        if (*p_curr_setting)
265        {
266          vsf_sysutil_free((char*)*p_curr_setting);
267        }
268        if (str_isempty(p_value_str))
269        {
270          *p_curr_setting = 0;
271        }
272        else
273        {
274          *p_curr_setting = str_strdup(p_value_str);
275        }
276        return;
277      }
278      p_str_setting++;
279    }
280  }
281  if (str_isempty(p_value_str))
282  {
283    if (errs_fatal)
284    {
285      die2("missing value in config file for: ", str_getbuf(p_setting_str));
286    }
287    else
288    {
289      return;
290    }
291  }
292  /* Is it a boolean value? */
293  {
294    const struct parseconf_bool_setting* p_bool_setting = parseconf_bool_array;
295    while (p_bool_setting->p_setting_name != 0)
296    {
297      if (str_equal_text(p_setting_str, p_bool_setting->p_setting_name))
298      {
299        /* Got it */
300        str_upper(p_value_str);
301        if (str_equal_text(p_value_str, "YES") ||
302            str_equal_text(p_value_str, "TRUE") ||
303            str_equal_text(p_value_str, "1"))
304        {
305          *(p_bool_setting->p_variable) = 1;
306        }
307        else if (str_equal_text(p_value_str, "NO") ||
308                 str_equal_text(p_value_str, "FALSE") ||
309                 str_equal_text(p_value_str, "0"))
310        {
311          *(p_bool_setting->p_variable) = 0;
312        }
313        else if (errs_fatal)
314        {
315          die2("bad bool value in config file for: ",
316               str_getbuf(p_setting_str));
317        }
318        return;
319      }
320      p_bool_setting++;
321    }
322  }
323  /* Is it an unsigned integer setting? */
324  {
325    const struct parseconf_uint_setting* p_uint_setting = parseconf_uint_array;
326    while (p_uint_setting->p_setting_name != 0)
327    {
328      if (str_equal_text(p_setting_str, p_uint_setting->p_setting_name))
329      {
330        /* Got it */
331        /* If the value starts with 0, assume it's an octal value */
332        if (!str_isempty(p_value_str) &&
333            str_get_char_at(p_value_str, 0) == '0')
334        {
335          *(p_uint_setting->p_variable) = str_octal_to_uint(p_value_str);
336        }
337        else
338        {
339          *(p_uint_setting->p_variable) = str_atoi(p_value_str);
340        }
341        return;
342      }
343      p_uint_setting++;
344    }
345  }
346  if (errs_fatal)
347  {
348    die2("unrecognised variable in config file: ", str_getbuf(p_setting_str));
349  }
350}
351
352static void
353copy_string_settings(void)
354{
355  const struct parseconf_str_setting* p_str_setting = parseconf_str_array;
356  while (p_str_setting->p_setting_name != 0)
357  {
358    if (*p_str_setting->p_variable != 0)
359    {
360      *p_str_setting->p_variable =
361          vsf_sysutil_strdup(*p_str_setting->p_variable);
362    }
363    p_str_setting++;
364  }
365}
366
367