1 /* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "buffer.h"
5 #include "hostpid.h"
6 #include "settings-parser.h"
7 #include "service-settings.h"
8 #include "mail-storage-settings.h"
9 #include "smtp-submit-settings.h"
10 #include "imap-settings.h"
11 
12 #include <stddef.h>
13 #include <unistd.h>
14 
15 static bool imap_settings_verify(void *_set, pool_t pool,
16 				 const char **error_r);
17 
18 /* <settings checks> */
19 static struct file_listener_settings imap_unix_listeners_array[] = {
20 	{ "login/imap", 0666, "", "" },
21 	{ "imap-master", 0600, "", "" }
22 };
23 static struct file_listener_settings *imap_unix_listeners[] = {
24 	&imap_unix_listeners_array[0],
25 	&imap_unix_listeners_array[1]
26 };
27 static buffer_t imap_unix_listeners_buf = {
28 	{ { imap_unix_listeners, sizeof(imap_unix_listeners) } }
29 };
30 /* </settings checks> */
31 
32 struct service_settings imap_service_settings = {
33 	.name = "imap",
34 	.protocol = "imap",
35 	.type = "",
36 	.executable = "imap",
37 	.user = "",
38 	.group = "",
39 	.privileged_group = "",
40 	.extra_groups = "$default_internal_group",
41 	.chroot = "",
42 
43 	.drop_priv_before_exec = FALSE,
44 
45 	.process_min_avail = 0,
46 	.process_limit = 1024,
47 	.client_limit = 1,
48 	.service_count = 1,
49 	.idle_kill = 0,
50 	.vsz_limit = UOFF_T_MAX,
51 
52 	.unix_listeners = { { &imap_unix_listeners_buf,
53 			      sizeof(imap_unix_listeners[0]) } },
54 	.fifo_listeners = ARRAY_INIT,
55 	.inet_listeners = ARRAY_INIT
56 };
57 
58 #undef DEF
59 #undef DEFLIST
60 #define DEF(type, name) \
61 	SETTING_DEFINE_STRUCT_##type(#name, name, struct imap_settings)
62 #define DEFLIST(field, name, defines) \
63 	{ .type = SET_DEFLIST, .key = name, \
64 	  .offset = offsetof(struct imap_settings, field), \
65 	  .list_info = defines }
66 
67 static const struct setting_define imap_setting_defines[] = {
68 	DEF(BOOL, verbose_proctitle),
69 	DEF(STR_VARS, rawlog_dir),
70 
71 	DEF(SIZE, imap_max_line_length),
72 	DEF(TIME, imap_idle_notify_interval),
73 	DEF(STR, imap_capability),
74 	DEF(STR, imap_client_workarounds),
75 	DEF(STR, imap_logout_format),
76 	DEF(STR, imap_id_send),
77 	DEF(STR, imap_id_log),
78 	DEF(ENUM, imap_fetch_failure),
79 	DEF(BOOL, imap_metadata),
80 	DEF(BOOL, imap_literal_minus),
81 	DEF(TIME, imap_hibernate_timeout),
82 
83 	DEF(STR, imap_urlauth_host),
84 	DEF(IN_PORT, imap_urlauth_port),
85 
86 	SETTING_DEFINE_LIST_END
87 };
88 
89 static const struct imap_settings imap_default_settings = {
90 	.verbose_proctitle = FALSE,
91 	.rawlog_dir = "",
92 
93 	/* RFC-2683 recommends at least 8000 bytes. Some clients however don't
94 	   break large message sets to multiple commands, so we're pretty
95 	   liberal by default. */
96 	.imap_max_line_length = 64*1024,
97 	.imap_idle_notify_interval = 2*60,
98 	.imap_capability = "",
99 	.imap_client_workarounds = "",
100 	.imap_logout_format = "in=%i out=%o deleted=%{deleted} "
101 		"expunged=%{expunged} trashed=%{trashed} "
102 		"hdr_count=%{fetch_hdr_count} hdr_bytes=%{fetch_hdr_bytes} "
103 		"body_count=%{fetch_body_count} body_bytes=%{fetch_body_bytes}",
104 	.imap_id_send = "name *",
105 	.imap_id_log = "",
106 	.imap_fetch_failure = "disconnect-immediately:disconnect-after:no-after",
107 	.imap_metadata = FALSE,
108 	.imap_literal_minus = FALSE,
109 	.imap_hibernate_timeout = 0,
110 
111 	.imap_urlauth_host = "",
112 	.imap_urlauth_port = 143
113 };
114 
115 static const struct setting_parser_info *imap_setting_dependencies[] = {
116 	&mail_user_setting_parser_info,
117 	&smtp_submit_setting_parser_info,
118 	NULL
119 };
120 
121 const struct setting_parser_info imap_setting_parser_info = {
122 	.module_name = "imap",
123 	.defines = imap_setting_defines,
124 	.defaults = &imap_default_settings,
125 
126 	.type_offset = SIZE_MAX,
127 	.struct_size = sizeof(struct imap_settings),
128 
129 	.parent_offset = SIZE_MAX,
130 
131 	.check_func = imap_settings_verify,
132 	.dependencies = imap_setting_dependencies
133 };
134 
135 /* <settings checks> */
136 struct imap_client_workaround_list {
137 	const char *name;
138 	enum imap_client_workarounds num;
139 };
140 
141 static const struct imap_client_workaround_list imap_client_workaround_list[] = {
142 	{ "delay-newmail", WORKAROUND_DELAY_NEWMAIL },
143 	{ "tb-extra-mailbox-sep", WORKAROUND_TB_EXTRA_MAILBOX_SEP },
144 	{ "tb-lsub-flags", WORKAROUND_TB_LSUB_FLAGS },
145 	{ NULL, 0 }
146 };
147 
148 static int
imap_settings_parse_workarounds(struct imap_settings * set,const char ** error_r)149 imap_settings_parse_workarounds(struct imap_settings *set,
150 				const char **error_r)
151 {
152         enum imap_client_workarounds client_workarounds = 0;
153         const struct imap_client_workaround_list *list;
154 	const char *const *str;
155 
156         str = t_strsplit_spaces(set->imap_client_workarounds, " ,");
157 	for (; *str != NULL; str++) {
158 		list = imap_client_workaround_list;
159 		for (; list->name != NULL; list++) {
160 			if (strcasecmp(*str, list->name) == 0) {
161 				client_workarounds |= list->num;
162 				break;
163 			}
164 		}
165 		if (list->name == NULL) {
166 			*error_r = t_strdup_printf("imap_client_workarounds: "
167 				"Unknown workaround: %s", *str);
168 			return -1;
169 		}
170 	}
171 	set->parsed_workarounds = client_workarounds;
172 	return 0;
173 }
174 
175 
176 static bool
imap_settings_verify(void * _set,pool_t pool ATTR_UNUSED,const char ** error_r)177 imap_settings_verify(void *_set, pool_t pool ATTR_UNUSED, const char **error_r)
178 {
179 	struct imap_settings *set = _set;
180 
181 	if (imap_settings_parse_workarounds(set, error_r) < 0)
182 		return FALSE;
183 
184 	if (strcmp(set->imap_fetch_failure, "disconnect-immediately") == 0)
185 		set->parsed_fetch_failure = IMAP_CLIENT_FETCH_FAILURE_DISCONNECT_IMMEDIATELY;
186 	else if (strcmp(set->imap_fetch_failure, "disconnect-after") == 0)
187 		set->parsed_fetch_failure = IMAP_CLIENT_FETCH_FAILURE_DISCONNECT_AFTER;
188 	else if (strcmp(set->imap_fetch_failure, "no-after") == 0)
189 		set->parsed_fetch_failure = IMAP_CLIENT_FETCH_FAILURE_NO_AFTER;
190 	else {
191 		*error_r = t_strdup_printf("Unknown imap_fetch_failure: %s",
192 					   set->imap_fetch_failure);
193 		return FALSE;
194 	}
195 	return TRUE;
196 }
197 /* </settings checks> */
198