parseconf.c 12 KB

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