2 * Part of Very Secure FTPd
7 * Routines and support to load in a file full of tunable variables and
8 * settings, populating corresponding runtime variables.
11 #include "parseconf.h"
19 static const char* s_p_saved_filename
;
21 /* Tables mapping setting names to runtime variables */
22 /* Boolean settings */
23 static struct parseconf_bool_setting
25 const char* p_setting_name
;
28 parseconf_bool_array
[] =
30 { "anonymous_enable", &tunable_anonymous_enable
},
31 { "local_enable", &tunable_local_enable
},
32 { "pasv_enable", &tunable_pasv_enable
},
33 { "port_enable", &tunable_port_enable
},
34 { "chroot_local_user", &tunable_chroot_local_user
},
35 { "write_enable", &tunable_write_enable
},
36 { "anon_upload_enable", &tunable_anon_upload_enable
},
37 { "anon_mkdir_write_enable", &tunable_anon_mkdir_write_enable
},
38 { "anon_other_write_enable", &tunable_anon_other_write_enable
},
39 { "anon_allow_writable_root", &tunable_anon_allow_writable_root
},
40 { "chown_uploads", &tunable_chown_uploads
},
41 { "connect_from_port_20", &tunable_connect_from_port_20
},
42 { "xferlog_enable", &tunable_xferlog_enable
},
43 { "dirmessage_enable", &tunable_dirmessage_enable
},
44 { "anon_world_readable_only", &tunable_anon_world_readable_only
},
45 { "async_abor_enable", &tunable_async_abor_enable
},
46 { "ascii_upload_enable", &tunable_ascii_upload_enable
},
47 { "ascii_download_enable", &tunable_ascii_download_enable
},
48 { "one_process_model", &tunable_one_process_model
},
49 { "xferlog_std_format", &tunable_xferlog_std_format
},
50 { "pasv_promiscuous", &tunable_pasv_promiscuous
},
51 { "deny_email_enable", &tunable_deny_email_enable
},
52 { "chroot_list_enable", &tunable_chroot_list_enable
},
53 { "setproctitle_enable", &tunable_setproctitle_enable
},
54 { "text_userdb_names", &tunable_text_userdb_names
},
55 { "ls_recurse_enable", &tunable_ls_recurse_enable
},
56 { "log_ftp_protocol", &tunable_log_ftp_protocol
},
57 { "guest_enable", &tunable_guest_enable
},
58 { "userlist_enable", &tunable_userlist_enable
},
59 { "userlist_deny", &tunable_userlist_deny
},
60 { "use_localtime", &tunable_use_localtime
},
61 { "check_shell", &tunable_check_shell
},
62 { "hide_ids", &tunable_hide_ids
},
63 { "listen", &tunable_listen
},
64 { "port_promiscuous", &tunable_port_promiscuous
},
65 { "passwd_chroot_enable", &tunable_passwd_chroot_enable
},
66 { "no_anon_password", &tunable_no_anon_password
},
67 { "tcp_wrappers", &tunable_tcp_wrappers
},
68 { "use_sendfile", &tunable_use_sendfile
},
69 { "force_dot_files", &tunable_force_dot_files
},
70 { "listen_ipv6", &tunable_listen_ipv6
},
71 { "dual_log_enable", &tunable_dual_log_enable
},
72 { "syslog_enable", &tunable_syslog_enable
},
73 { "background", &tunable_background
},
74 { "virtual_use_local_privs", &tunable_virtual_use_local_privs
},
75 { "session_support", &tunable_session_support
},
76 { "download_enable", &tunable_download_enable
},
77 { "dirlist_enable", &tunable_dirlist_enable
},
78 { "chmod_enable", &tunable_chmod_enable
},
79 { "secure_email_list_enable", &tunable_secure_email_list_enable
},
80 { "run_as_launching_user", &tunable_run_as_launching_user
},
81 { "no_log_lock", &tunable_no_log_lock
},
82 { "ssl_enable", &tunable_ssl_enable
},
83 { "allow_anon_ssl", &tunable_allow_anon_ssl
},
84 { "force_local_logins_ssl", &tunable_force_local_logins_ssl
},
85 { "force_local_data_ssl", &tunable_force_local_data_ssl
},
86 { "ssl_sslv2", &tunable_sslv2
},
87 { "ssl_sslv3", &tunable_sslv3
},
88 { "ssl_tlsv1", &tunable_tlsv1
},
89 { "tilde_user_enable", &tunable_tilde_user_enable
},
90 { "force_anon_logins_ssl", &tunable_force_anon_logins_ssl
},
91 { "force_anon_data_ssl", &tunable_force_anon_data_ssl
},
92 { "mdtm_write", &tunable_mdtm_write
},
93 { "lock_upload_files", &tunable_lock_upload_files
},
94 { "pasv_addr_resolve", &tunable_pasv_addr_resolve
},
95 { "debug_ssl", &tunable_debug_ssl
},
96 { "require_cert", &tunable_require_cert
},
97 { "validate_cert", &tunable_validate_cert
},
98 { "strict_ssl_read_eof", &tunable_strict_ssl_read_eof
},
99 { "strict_ssl_write_shutdown", &tunable_strict_ssl_write_shutdown
},
100 { "ssl_request_cert", &tunable_ssl_request_cert
},
101 { "delete_failed_uploads", &tunable_delete_failed_uploads
},
102 { "implicit_ssl", &tunable_implicit_ssl
},
103 { "ptrace_sandbox", &tunable_ptrace_sandbox
},
104 { "require_ssl_reuse", &tunable_require_ssl_reuse
},
105 { "isolate", &tunable_isolate
},
106 { "isolate_network", &tunable_isolate_network
},
107 { "ftp_enable", &tunable_ftp_enable
},
108 { "http_enable", &tunable_http_enable
},
109 { "seccomp_sandbox", &tunable_seccomp_sandbox
},
110 { "allow_writeable_chroot", &tunable_allow_writeable_chroot
},
114 static struct parseconf_uint_setting
116 const char* p_setting_name
;
117 unsigned int* p_variable
;
119 parseconf_uint_array
[] =
121 { "accept_timeout", &tunable_accept_timeout
},
122 { "connect_timeout", &tunable_connect_timeout
},
123 { "local_umask", &tunable_local_umask
},
124 { "anon_umask", &tunable_anon_umask
},
125 { "ftp_data_port", &tunable_ftp_data_port
},
126 { "idle_session_timeout", &tunable_idle_session_timeout
},
127 { "data_connection_timeout", &tunable_data_connection_timeout
},
128 { "pasv_min_port", &tunable_pasv_min_port
},
129 { "pasv_max_port", &tunable_pasv_max_port
},
130 { "anon_max_rate", &tunable_anon_max_rate
},
131 { "local_max_rate", &tunable_local_max_rate
},
132 { "listen_port", &tunable_listen_port
},
133 { "max_clients", &tunable_max_clients
},
134 { "file_open_mode", &tunable_file_open_mode
},
135 { "max_per_ip", &tunable_max_per_ip
},
136 { "trans_chunk_size", &tunable_trans_chunk_size
},
137 { "delay_failed_login", &tunable_delay_failed_login
},
138 { "delay_successful_login", &tunable_delay_successful_login
},
139 { "max_login_fails", &tunable_max_login_fails
},
140 { "chown_upload_mode", &tunable_chown_upload_mode
},
144 static struct parseconf_str_setting
146 const char* p_setting_name
;
147 const char** p_variable
;
149 parseconf_str_array
[] =
151 { "secure_chroot_dir", &tunable_secure_chroot_dir
},
152 { "ftp_username", &tunable_ftp_username
},
153 { "chown_username", &tunable_chown_username
},
154 { "xferlog_file", &tunable_xferlog_file
},
155 { "vsftpd_log_file", &tunable_vsftpd_log_file
},
156 { "message_file", &tunable_message_file
},
157 { "nopriv_user", &tunable_nopriv_user
},
158 { "ftpd_banner", &tunable_ftpd_banner
},
159 { "banned_email_file", &tunable_banned_email_file
},
160 { "chroot_list_file", &tunable_chroot_list_file
},
161 { "pam_service_name", &tunable_pam_service_name
},
162 { "guest_username", &tunable_guest_username
},
163 { "userlist_file", &tunable_userlist_file
},
164 { "anon_root", &tunable_anon_root
},
165 { "local_root", &tunable_local_root
},
166 { "banner_file", &tunable_banner_file
},
167 { "pasv_address", &tunable_pasv_address
},
168 { "listen_address", &tunable_listen_address
},
169 { "user_config_dir", &tunable_user_config_dir
},
170 { "listen_address6", &tunable_listen_address6
},
171 { "cmds_allowed", &tunable_cmds_allowed
},
172 { "hide_file", &tunable_hide_file
},
173 { "deny_file", &tunable_deny_file
},
174 { "user_sub_token", &tunable_user_sub_token
},
175 { "email_password_file", &tunable_email_password_file
},
176 { "rsa_cert_file", &tunable_rsa_cert_file
},
177 { "dsa_cert_file", &tunable_dsa_cert_file
},
178 { "ssl_ciphers", &tunable_ssl_ciphers
},
179 { "rsa_private_key_file", &tunable_rsa_private_key_file
},
180 { "dsa_private_key_file", &tunable_dsa_private_key_file
},
181 { "ca_certs_file", &tunable_ca_certs_file
},
182 { "cmds_denied", &tunable_cmds_denied
},
183 { "passwd_file", &tunable_passwd_file
},
188 vsf_parseconf_load_file(const char* p_filename
, int errs_fatal
)
190 struct mystr config_file_str
= INIT_MYSTR
;
191 struct mystr config_setting_str
= INIT_MYSTR
;
192 struct mystr config_value_str
= INIT_MYSTR
;
193 unsigned int str_pos
= 0;
197 p_filename
= s_p_saved_filename
;
201 if (s_p_saved_filename
)
203 vsf_sysutil_free((char*)s_p_saved_filename
);
205 s_p_saved_filename
= vsf_sysutil_strdup(p_filename
);
209 bug("null filename in vsf_parseconf_load_file");
211 retval
= str_fileread(&config_file_str
, p_filename
, VSFTP_CONF_FILE_MAX
);
212 if (vsf_sysutil_retval_is_error(retval
))
216 die2("cannot read config file: ", p_filename
);
220 str_free(&config_file_str
);
225 struct vsf_sysutil_statbuf
* p_statbuf
= 0;
226 retval
= vsf_sysutil_stat(p_filename
, &p_statbuf
);
227 /* Security: check current user owns the config file. These are sanity
228 * checks for the admin, and are NOT designed to be checks safe from
231 if (vsf_sysutil_retval_is_error(retval
) ||
232 vsf_sysutil_statbuf_get_uid(p_statbuf
) != vsf_sysutil_getuid() ||
233 !vsf_sysutil_statbuf_is_regfile(p_statbuf
))
235 die("config file not owned by correct user, or not a file");
237 vsf_sysutil_free(p_statbuf
);
239 while (str_getline(&config_file_str
, &config_setting_str
, &str_pos
))
241 if (str_isempty(&config_setting_str
) ||
242 str_get_char_at(&config_setting_str
, 0) == '#' ||
243 str_all_space(&config_setting_str
))
247 vsf_parseconf_load_setting(str_getbuf(&config_setting_str
), errs_fatal
);
249 str_free(&config_file_str
);
250 str_free(&config_setting_str
);
251 str_free(&config_value_str
);
255 vsf_parseconf_load_setting(const char* p_setting
, int errs_fatal
)
257 static struct mystr s_setting_str
;
258 static struct mystr s_value_str
;
259 while (vsf_sysutil_isspace(*p_setting
))
263 str_alloc_text(&s_setting_str
, p_setting
);
264 str_split_char(&s_setting_str
, &s_value_str
, '=');
265 /* Is it a string setting? */
267 const struct parseconf_str_setting
* p_str_setting
= parseconf_str_array
;
268 while (p_str_setting
->p_setting_name
!= 0)
270 if (str_equal_text(&s_setting_str
, p_str_setting
->p_setting_name
))
273 const char** p_curr_setting
= p_str_setting
->p_variable
;
276 vsf_sysutil_free((char*) *p_curr_setting
);
278 if (str_isempty(&s_value_str
))
284 *p_curr_setting
= str_strdup(&s_value_str
);
291 if (str_isempty(&s_value_str
))
295 die2("missing value in config file for: ", str_getbuf(&s_setting_str
));
302 /* Is it a boolean value? */
304 const struct parseconf_bool_setting
* p_bool_setting
= parseconf_bool_array
;
305 while (p_bool_setting
->p_setting_name
!= 0)
307 if (str_equal_text(&s_setting_str
, p_bool_setting
->p_setting_name
))
310 str_upper(&s_value_str
);
311 if (str_equal_text(&s_value_str
, "YES") ||
312 str_equal_text(&s_value_str
, "TRUE") ||
313 str_equal_text(&s_value_str
, "1"))
315 *(p_bool_setting
->p_variable
) = 1;
317 else if (str_equal_text(&s_value_str
, "NO") ||
318 str_equal_text(&s_value_str
, "FALSE") ||
319 str_equal_text(&s_value_str
, "0"))
321 *(p_bool_setting
->p_variable
) = 0;
325 die2("bad bool value in config file for: ",
326 str_getbuf(&s_setting_str
));
333 /* Is it an unsigned integer setting? */
335 const struct parseconf_uint_setting
* p_uint_setting
= parseconf_uint_array
;
336 while (p_uint_setting
->p_setting_name
!= 0)
338 if (str_equal_text(&s_setting_str
, p_uint_setting
->p_setting_name
))
341 /* If the value starts with 0, assume it's an octal value */
342 if (!str_isempty(&s_value_str
) &&
343 str_get_char_at(&s_value_str
, 0) == '0')
345 *(p_uint_setting
->p_variable
) = str_octal_to_uint(&s_value_str
);
349 /* TODO: we could reject negatives instead of converting them? */
350 *(p_uint_setting
->p_variable
) = (unsigned int) str_atoi(&s_value_str
);
359 die2("unrecognised variable in config file: ", str_getbuf(&s_setting_str
));