1 /* Copyright 2003-2008 Wang, Chun-Pin All rights reserved. */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <limits.h>
7 #include <sys/param.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11 #include <syslog.h>
12
13 #include "config.h"
14 #include "pathnames.h"
15 #include "smbftpd.h"
16 #include "auth.h"
17 #include "restrict.h"
18
19 extern smbftpd_conf_t smbftpd_conf;
20 extern smbftpd_share_t *smbftpd_shares;
21
22 typedef enum opt_type_t {
23 OPT_TYPE_UNKNOWN = 0,
24 OPT_TYPE_INT = 1,
25 OPT_TYPE_OCTAL,
26 OPT_TYPE_STR,
27 OPT_TYPE_SET,
28 OPT_TYPE_YES_NO,
29 OPT_TYPE_MODE,
30 OPT_TYPE_PATH,
31 OPT_TYPE_SSL,
32 OPT_TYPE_SPECIAL /* this is a special option type. The option have
33 to assign 2 conf member or take special handling. */
34 } opt_type_t;
35
36 /* List of all option in config file */
37 typedef struct conf_opt_list_t {
38 char *opt_str;
39 opt_type_t opt_type;
40 void *smbftpd_conf_member;
41 } conf_opt_list_t;
42
43 static conf_opt_list_t all_conf_list[] = {
44 {"ChrootSet", OPT_TYPE_SET, &(smbftpd_conf.chroot_set)},
45 {"MaxDownloadRate", OPT_TYPE_SET, &(smbftpd_conf.max_download_rate)},
46 {"MaxUploadRate", OPT_TYPE_SET, &(smbftpd_conf.max_upload_rate)},
47 {"ShareConfPath", OPT_TYPE_PATH, &(smbftpd_conf.share_conf_path)},
48 {"TransferLog", OPT_TYPE_STR, &(smbftpd_conf.transfer_log_path)},
49 {"ServerName", OPT_TYPE_STR, &(smbftpd_conf.server_name)},
50 {"ListenOnAddress", OPT_TYPE_STR, &(smbftpd_conf.listen_on_address)},
51 {"Port", OPT_TYPE_STR, &(smbftpd_conf.port)},
52 {"ForcePassiveIP", OPT_TYPE_STR, &(smbftpd_conf.force_passive_ip)},
53 {"ExceptionList", OPT_TYPE_STR, &(smbftpd_conf.exception_list)},
54 {"PidFile", OPT_TYPE_STR, &(smbftpd_conf.pid_file)},
55 {"NoLoginList", OPT_TYPE_STR, &(smbftpd_conf.no_login_list)},
56 {"VirtualUserMapping", OPT_TYPE_STR, &(smbftpd_conf.virtual_user_mapping)},
57 {"VirtualUserAuthMethod",OPT_TYPE_STR, &(smbftpd_conf.virtual_user_auth_method)},
58 {"VirtualUserAuthConfig",OPT_TYPE_STR, &(smbftpd_conf.virtual_user_auth_config)},
59 {"CharsetEncoding", OPT_TYPE_STR, &(smbftpd_conf.charset_encoding)},
60 {"DefaultMode", OPT_TYPE_MODE, &(smbftpd_conf.default_mode)},
61 {"SupportUTF8Client", OPT_TYPE_YES_NO, &(smbftpd_conf.support_utf8_client)},
62 {"UsingUTF8FileSystem", OPT_TYPE_YES_NO, &(smbftpd_conf.using_utf8_filesystem)},
63 {"ShowProgramVersion", OPT_TYPE_YES_NO, &(smbftpd_conf.show_program_version)},
64 {"DebugMode", OPT_TYPE_YES_NO, &(smbftpd_conf.debug_mode)},
65 {"LogCommand", OPT_TYPE_YES_NO, &(smbftpd_conf.log_command)},
66 {"DoWtmpLog", OPT_TYPE_YES_NO, &(smbftpd_conf.do_wtmp_log)},
67 {"AnonymousLogin", OPT_TYPE_YES_NO, &(smbftpd_conf.anonymous_login)},
68 {"AnonymousOnly", OPT_TYPE_YES_NO, &(smbftpd_conf.anonymous_only)},
69 {"AnonymousReadOnly", OPT_TYPE_YES_NO, &(smbftpd_conf.anonymous_readonly)},
70 {"EmptyPasswdLogin", OPT_TYPE_YES_NO, &(smbftpd_conf.empty_passwd_login)},
71 {"ShowSymlinks", OPT_TYPE_YES_NO, &(smbftpd_conf.show_symlinks)},
72 {"ShowDotFiles", OPT_TYPE_YES_NO, &(smbftpd_conf.show_dot_files)},
73 {"RequireValidShell", OPT_TYPE_YES_NO, &(smbftpd_conf.require_valid_shell)},
74 {"DisableEPSV", OPT_TYPE_YES_NO, &(smbftpd_conf.disable_epsv)},
75 {"RestrictedPorts", OPT_TYPE_YES_NO, &(smbftpd_conf.restricted_ports)},
76 {"PassiveModePortRange", OPT_TYPE_SPECIAL, &(smbftpd_conf.passive_port_high)},
77 {"Umask", OPT_TYPE_OCTAL, &(smbftpd_conf.umask)},
78 {"MaxConnection", OPT_TYPE_INT, &(smbftpd_conf.max_connection)},
79 {"MaxConnectionPerIP", OPT_TYPE_INT, &(smbftpd_conf.max_connection_per_ip)},
80 {"TimeOut", OPT_TYPE_INT, &(smbftpd_conf.timeout)},
81 {"MaxTimeOut", OPT_TYPE_INT, &(smbftpd_conf.max_timeout)},
82
83 // SSL/TLS Options
84 {"SecurityPolicy", OPT_TYPE_SSL, &(smbftpd_conf.security_policy)},
85 {"EncryptionType", OPT_TYPE_SSL, &(smbftpd_conf.encryption_type)},
86 {"NormalUserMustSecure", OPT_TYPE_YES_NO, &(smbftpd_conf.normal_user_must_secure)},
87 {"AnonymDisableSecure", OPT_TYPE_YES_NO, &(smbftpd_conf.anonym_disable_secure)},
88 {"SSLCertFile", OPT_TYPE_PATH, &(smbftpd_conf.ssl_cert_file)},
89 {"SSLKeyFile", OPT_TYPE_PATH, &(smbftpd_conf.ssl_key_file)},
90
91 {NULL, 0, NULL}
92 };
93
94 /**
95 * Initial the default value of smbconf
96 */
config_init()97 void config_init()
98 {
99 char hostname[MAXHOSTNAMELEN];
100
101 bzero(hostname, sizeof(hostname));
102 bzero(&smbftpd_conf, sizeof(smbftpd_conf));
103 if (gethostname(hostname, sizeof(hostname)) == 0) {
104 smbftpd_conf.server_name = strdup(hostname);
105 } else {
106 smbftpd_conf.server_name = strdup("Unkown");
107 }
108 smbftpd_conf.port = strdup("ftp");
109 smbftpd_conf.umask = 022;
110 smbftpd_conf.timeout = 900;
111 smbftpd_conf.max_timeout = 7200;
112 smbftpd_conf.show_program_version = 1;
113 smbftpd_conf.default_mode = MODE_NORMAL;
114 smbftpd_conf.restricted_ports = 1;
115 smbftpd_conf.show_dot_files = 1;
116 smbftpd_conf.require_valid_shell = 1;
117 smbftpd_conf.no_login_list = strdup("500");
118 smbftpd_conf.anonymous_readonly = 1;
119
120 // SSL/TLS options
121 smbftpd_conf.security_policy = SECURITY_POLICY_NOSECURE;
122 smbftpd_conf.encryption_type = ENCRYPTION_TYPE_SSL | ENCRYPTION_TYPE_TLS;
123 smbftpd_conf.ssl_cert_file = strdup(PATH_SSL_CERT_FILE);
124 smbftpd_conf.ssl_key_file = strdup(PATH_SSL_KEY_FILE);
125 }
126
127 /**
128 * Option/value handler for smbftpd_config_parser() function.
129 *
130 * We will assign the option/value to smbftpd_conf
131 *
132 * @param option Option name
133 * @param opt_arg Option value
134 *
135 * @return 0: Success
136 * -1: Failed
137 */
smbftpd_config_handler(char * option,char * opt_arg)138 static int smbftpd_config_handler(char *option, char *opt_arg)
139 {
140 conf_opt_list_t *opt_list = NULL;
141 struct stat statBuf;
142 char *szArg1, *szArg2;
143 int error = -1, i;
144
145 for (i = 0; all_conf_list[i].opt_str; i++) {
146 if (strcasecmp(option, all_conf_list[i].opt_str) == 0) {
147 opt_list = &all_conf_list[i];
148 break;
149 }
150 }
151
152 if (!opt_list) {
153 syslog(LOG_ERR, "%s (%d) Skip unknown option %s", __FILE__, __LINE__, option);
154 return 0;
155 }
156
157 switch (opt_list->opt_type) {
158 case OPT_TYPE_OCTAL:
159 *((int *)(opt_list->smbftpd_conf_member)) = (int)strtol(opt_arg, (char **)NULL, 8);
160 if (*((int *)(opt_list->smbftpd_conf_member)) <= 0) {
161 syslog(LOG_ERR, "%s (%d) bad number of config option %s",
162 __FILE__, __LINE__, opt_list->opt_str);
163 goto Error;
164 }
165 break;
166 case OPT_TYPE_INT:
167 *((int *)(opt_list->smbftpd_conf_member)) = (int)strtol(opt_arg, (char **)NULL, 10);
168 if (*((int *)(opt_list->smbftpd_conf_member)) <= 0) {
169 syslog(LOG_ERR, "%s (%d) bad number of config option %s",
170 __FILE__, __LINE__, opt_list->opt_str);
171 goto Error;
172 }
173 break;
174 case OPT_TYPE_SPECIAL:
175 if (strcasecmp(option, "PassiveModePortRange") == 0) {
176 int c;
177 unsigned int lowport, highport;
178
179 c = sscanf(opt_arg, "%u-%u", &lowport, &highport);
180 if (c != 2 || lowport < 1024U || highport > 65535U || highport < lowport) {
181 syslog(LOG_ERR, "%s (%d) Bad port range %s", __FILE__, __LINE__, opt_arg);
182 goto Error;
183 }
184 smbftpd_conf.passive_port_low = lowport;
185 smbftpd_conf.passive_port_high = highport;
186 }
187 break;
188 case OPT_TYPE_PATH:
189 if (0 != stat(opt_arg, &statBuf) || !S_ISREG(statBuf.st_mode)) {
190 syslog(LOG_ERR, "%s (%d) The option %s (%s) does not exist",
191 __FILE__, __LINE__, opt_list->opt_str, opt_arg);
192 goto Error;
193 }
194 /* Fall down */
195 case OPT_TYPE_STR:
196 if (*((char **)opt_list->smbftpd_conf_member)) {
197 free(*((char **)opt_list->smbftpd_conf_member));
198 }
199 *((char **)opt_list->smbftpd_conf_member) = strdup(opt_arg);
200 if (*((char **)opt_list->smbftpd_conf_member) == NULL) {
201 syslog(LOG_ERR, "%s (%d) Ran out of memory.", __FILE__, __LINE__);
202 goto Error;
203 }
204 break;
205 case OPT_TYPE_YES_NO:
206 if (strcasecmp(opt_arg, "yes") == 0) {
207 *((int *)opt_list->smbftpd_conf_member) = 1;
208 } else {
209 *((int *)opt_list->smbftpd_conf_member) = 0;
210 }
211 break;
212 case OPT_TYPE_MODE:
213 if (strcasecmp(opt_arg, "SMB") == 0) {
214 *((int *)opt_list->smbftpd_conf_member) = 1;
215 } else {
216 *((int *)opt_list->smbftpd_conf_member) = 0;
217 }
218 break;
219 case OPT_TYPE_SET:
220 szArg1 = strtok(opt_arg, " \t");
221 szArg2 = strtok(NULL, " \t");
222 if (szArg1 && szArg2) {
223 struct opt_set *p;
224 p = calloc(sizeof(struct opt_set), 1);
225 p->key = strdup(szArg1);
226 p->value = strdup(szArg2);
227 if (p->key == NULL || p->value == NULL) {
228 syslog(LOG_ERR, "%s (%d) Ran out of memory.", __FILE__, __LINE__);
229 goto Error;
230 }
231 p->next = *((struct opt_set **)opt_list->smbftpd_conf_member);
232 *((struct opt_set **)opt_list->smbftpd_conf_member) = p;
233 } else {
234 syslog(LOG_ERR, "%s (%d) bad syntax of config option %s",
235 __FILE__, __LINE__, opt_list->opt_str);
236 goto Error;
237 }
238 break;
239 case OPT_TYPE_SSL:
240 if (strcasecmp(opt_list->opt_str, "SecurityPolicy") == 0) {
241 if (strcasecmp(opt_arg, "secure") == 0) {
242 *((int *)opt_list->smbftpd_conf_member) = SECURITY_POLICY_SECURE;
243 } else if (strcasecmp(opt_arg, "nosecure") == 0) {
244 *((int *)opt_list->smbftpd_conf_member) = SECURITY_POLICY_NOSECURE;
245 } else {
246 *((int *)opt_list->smbftpd_conf_member) = SECURITY_POLICY_SECURE | SECURITY_POLICY_NOSECURE;
247 }
248 } else if (strcasecmp(opt_list->opt_str, "EncryptionType") == 0) {
249 if (strcasecmp(opt_arg, "tls") == 0) {
250 *((int *)opt_list->smbftpd_conf_member) = ENCRYPTION_TYPE_TLS;
251 } else if (strcasecmp(opt_arg, "ssl") == 0) {
252 *((int *)opt_list->smbftpd_conf_member) = ENCRYPTION_TYPE_SSL;
253 } else {
254 *((int *)opt_list->smbftpd_conf_member) = ENCRYPTION_TYPE_TLS | ENCRYPTION_TYPE_SSL;
255 }
256 } else {
257 syslog(LOG_ERR, "%s (%d) bad syntax of config option %s",
258 __FILE__, __LINE__, opt_list->opt_str);
259 goto Error;
260 }
261
262 break;
263 case OPT_TYPE_UNKNOWN:
264 break;
265 }
266
267 error = 0;
268 Error:
269 return error;
270 }
271
272 /**
273 * Read smbftpd.conf, smbftpd_share.conf, smbftpd_(auth mothod).conf.
274 * When failed, we will release the config that is read into memory.
275 *
276 * @param conf_path The path to smbftpd.conf
277 *
278 * @return 0: Success
279 * -1: Failed
280 */
config_read(char * conf_path)281 int config_read(char *conf_path)
282 {
283 int error = -1;
284
285 if (NULL == conf_path) {
286 syslog(LOG_ERR, "%s (%d) Please specify the config file", __FILE__, __LINE__);
287 goto Error;
288 }
289
290 if (0 != smbftpd_config_parser(conf_path, smbftpd_config_handler)) {
291 syslog(LOG_ERR, "%s (%d) Failed to parse %s", __FILE__, __LINE__, conf_path);
292 goto Error;
293 }
294
295 // Check and enum shares for SMB mode
296 if (smbftpd_conf.default_mode == MODE_SMB ||
297 (smbftpd_conf.default_mode == MODE_NORMAL && smbftpd_conf.exception_list)) {
298 if (smbftpd_conf.share_conf_path == NULL) {
299 syslog(LOG_ERR, "%s (%d) Enable SMB mode but failed to find samba config file.",
300 __FILE__, __LINE__);
301 goto Error;
302 } else if (0 != smbftpd_share_enum(smbftpd_conf.share_conf_path, &smbftpd_shares)) {
303 syslog(LOG_ERR, "%s (%d) Failed to enumerate shares", __FILE__, __LINE__);
304 goto Error;
305 }
306 }
307
308 // Check timeout and max timeout.
309 if (smbftpd_conf.timeout > smbftpd_conf.max_timeout) {
310 syslog(LOG_ERR, "%s (%d) The MaxTimeOut should be bigger than TimeOut.",
311 __FILE__, __LINE__);
312 goto Error;
313 }
314
315 // Check virtual user mapping config
316 if (smbftpd_conf.virtual_user_mapping && (!smbftpd_conf.virtual_user_auth_method ||
317 !smbftpd_conf.virtual_user_auth_config)) {
318 syslog(LOG_ERR, "%s (%d) VirtualUserMapping is set. But There is "
319 "no VirtualUserAuthMethod or VirtualUserAuthConfig", __FILE__, __LINE__);
320 goto Error;
321 }
322
323 // Parse authentication config file
324 if (smbftpd_conf.virtual_user_mapping) {
325 if (0 != smbftpd_auth_config_parse(smbftpd_conf.virtual_user_auth_method,
326 smbftpd_conf.virtual_user_auth_config)) {
327 goto Error;
328 }
329 } else {
330 #ifdef USE_PAM
331 if (0 != smbftpd_auth_config_parse("pam", NULL)) {
332 goto Error;
333 }
334 #else
335 if (0 != smbftpd_auth_config_parse("unix", NULL)) {
336 goto Error;
337 }
338 #endif
339 }
340
341 #ifdef WITH_ICONV
342 if (smbftpd_conf.support_utf8_client || smbftpd_conf.using_utf8_filesystem) {
343 if (!smbftpd_conf.charset_encoding) {
344 syslog(LOG_ERR, "%s (%d) In order to support UTF8 client/filesystem, you must set the CharsetEncoding.",
345 __FILE__, __LINE__);
346 goto Error;
347 }
348 }
349 #endif
350 // Open Unicode convert
351 if (smbftpd_conf.charset_encoding) {
352 #ifdef WITH_ICONV
353 if (0 != smbftpd_unicode_open(smbftpd_conf.charset_encoding)) {
354 goto Error;
355 }
356 #else
357 syslog(LOG_ERR, "%s (%d) iconv is not supported. Disable CharsetEncoding.", __FILE__, __LINE__);
358 #endif
359 }
360
361 if (smbftpd_conf.max_connection && smbftpd_conf.max_connection_per_ip) {
362 if (0 != smbftpd_iptrack_alloc(smbftpd_conf.max_connection)) {
363 syslog(LOG_ERR, "%s (%d) Failed to alloc space for max connection per ip table.", __FILE__, __LINE__);
364 goto Error;
365 }
366 }
367
368 error = 0;
369 Error:
370 if (error != 0) {
371 config_release();
372 }
373 return error;
374 }
375
376
377 /**
378 * Free the struct opt_set
379 *
380 * @param pSet
381 */
opt_set_free(struct opt_set * pSet)382 static void opt_set_free(struct opt_set *pSet)
383 {
384 while (pSet) {
385 struct opt_set *p = pSet;
386 pSet = p->next;
387 if (p->key) {
388 free(p->key);
389 }
390 if (p->value) {
391 free(p->value);
392 }
393 free(p);
394 }
395 }
396
397 /**
398 * Free the smbftpd_conf. We will call smbftpd_auth_config_free() and
399 * smbftpd_share_free() to free authenticaion method and smbftpd_shares;
400 */
config_release()401 void config_release()
402 {
403 conf_opt_list_t *conf = all_conf_list;
404
405 while (conf->opt_str) {
406 switch (conf->opt_type) {
407 case OPT_TYPE_SET:
408 opt_set_free(*((struct opt_set **)conf->smbftpd_conf_member));
409 *(char **)conf->smbftpd_conf_member = NULL;
410 break;
411 case OPT_TYPE_PATH:
412 case OPT_TYPE_STR:
413 if (*(char **)conf->smbftpd_conf_member != NULL) {
414 free(*((char **)conf->smbftpd_conf_member));
415 *(char **)conf->smbftpd_conf_member = NULL;
416 }
417 break;
418 default:
419 if (conf->smbftpd_conf_member) {
420 *(int **)conf->smbftpd_conf_member = 0;
421 }
422 break;
423 }
424 conf++;
425 }
426
427 smbftpd_share_free(&smbftpd_shares);
428
429 bzero(&smbftpd_conf, sizeof(smbftpd_conf));
430
431 smbftpd_auth_config_free();
432 smbftpd_share_free(&smbftpd_shares);
433 #ifdef WITH_ICONV
434 smbftpd_unicode_close();
435 #endif
436 smbftpd_iptrack_free();
437 }
438
439