Line data Source code
1 4 : int config_bind(CONFIGURATION* config, char* directive, char* params){
2 4 : char* tokenize_line = NULL;
3 4 : char* token = NULL;
4 :
5 4 : char* bindhost = NULL;
6 4 : char* port = NULL;
7 :
8 : #ifndef CMAIL_NO_TLS
9 4 : TLSMODE tls_mode = TLS_NONE;
10 4 : char* tls_keyfile = NULL;
11 4 : char* tls_certfile = NULL;
12 4 : char* tls_priorities = NULL;
13 4 : char* tls_dh_paramfile = NULL;
14 : #endif
15 :
16 4 : int listen_fd = -1;
17 4 : int listener_slot = -1;
18 4 : LISTENER settings = {
19 : #ifndef CMAIL_NO_TLS
20 : .tls_require = false,
21 : #endif
22 : .announce_domain = "cmail-popd"
23 : };
24 4 : LISTENER* listener_data = NULL;
25 :
26 : //tokenize line
27 4 : bindhost = strtok_r(params, " ", &tokenize_line);
28 : do{
29 32 : token = strtok_r(NULL, " ", &tokenize_line);
30 32 : if(token){
31 28 : if(!port){
32 4 : port = token;
33 : }
34 24 : else if(!strncmp(token, "announce=", 9)){
35 4 : settings.announce_domain = token + 9;
36 : }
37 : #ifndef CMAIL_NO_TLS
38 20 : else if(!strncmp(token, "cert=", 5)){
39 4 : tls_certfile = token + 5;
40 : }
41 16 : else if(!strncmp(token, "key=", 4)){
42 4 : tls_keyfile = token + 4;
43 : }
44 12 : else if(!strncmp(token, "ciphers=", 8)){
45 4 : tls_priorities = token + 8;
46 : }
47 8 : else if(!strncmp(token, "dhparams=", 9)){
48 4 : tls_dh_paramfile = token + 9;
49 : }
50 4 : else if(!strcmp(token, "tlsonly")){
51 2 : tls_mode = TLS_ONLY;
52 : }
53 2 : else if(!strcmp(token, "tlsrequire")){
54 2 : settings.tls_require = true;
55 : }
56 : #endif
57 : else{
58 0 : logprintf(config->log, LOG_INFO, "Ignored additional bind parameter %s\n", token);
59 : }
60 : }
61 32 : }while(token);
62 :
63 : #ifndef CMAIL_NO_TLS
64 4 : if(tls_keyfile && tls_certfile){
65 4 : if(tls_mode == TLS_NONE){
66 2 : tls_mode = TLS_NEGOTIATE;
67 : }
68 :
69 8 : if(tls_init_listener(config->log, &settings, tls_certfile, tls_keyfile, tls_dh_paramfile, tls_priorities) < 0){
70 0 : return -1;
71 : }
72 : }
73 0 : else if(tls_keyfile || tls_certfile || tls_mode != TLS_NONE){
74 0 : logprintf(config->log, LOG_ERROR, "Need both certificate and key for TLS\n");
75 0 : return -1;
76 : }
77 : #endif
78 :
79 : //try to open a listening socket
80 4 : listen_fd = network_listener(config->log, bindhost, port);
81 :
82 4 : if(listen_fd < 0){
83 0 : return -1;
84 : }
85 :
86 : //add the new listener to the pool
87 4 : listener_slot = connpool_add(&(config->listeners), listen_fd);
88 4 : if(listener_slot >= 0){
89 4 : logprintf(config->log, LOG_INFO, "Bound to %s port %s (slot %d)\n", bindhost, port, listener_slot);
90 :
91 : //create listener auxdata
92 4 : config->listeners.conns[listener_slot].aux_data = calloc(1, sizeof(LISTENER));
93 4 : if(!config->listeners.conns[listener_slot].aux_data){
94 0 : logprintf(config->log, LOG_ERROR, "Failed to allocate auxiliary data for listener\n");
95 0 : return -1;
96 : }
97 :
98 4 : listener_data = (LISTENER*)config->listeners.conns[listener_slot].aux_data;
99 4 : *listener_data = settings;
100 :
101 : //copy data to heap
102 : #ifndef CMAIL_NO_TLS
103 4 : config->listeners.conns[listener_slot].tls_mode = tls_mode;
104 : #endif
105 :
106 4 : listener_data->announce_domain = common_strdup(settings.announce_domain);
107 4 : if(!listener_data->announce_domain){
108 0 : logprintf(config->log, LOG_ERROR, "Failed to allocate auxiliary data for listener announce\n");
109 0 : return -1;
110 : }
111 4 : return 0;
112 : }
113 :
114 0 : logprintf(config->log, LOG_ERROR, "Failed to store listen socket\n");
115 0 : return -1;
116 : }
117 :
118 2 : int config_privileges(CONFIGURATION* config, char* directive, char* params){
119 : struct passwd* user_info;
120 : struct group* group_info;
121 :
122 2 : errno=0;
123 2 : if(!strcmp(directive, "user")){
124 1 : user_info = getpwnam(params);
125 1 : if(!user_info){
126 0 : logprintf(config->log, LOG_ERROR, "Failed to get user info for %s\n", params);
127 0 : return -1;
128 : }
129 1 : config->privileges.uid = user_info->pw_uid;
130 1 : config->privileges.gid = user_info->pw_gid;
131 1 : logprintf(config->log, LOG_DEBUG, "Configured dropped privileges to uid %d gid %d\n", config->privileges.uid, config->privileges.gid);
132 1 : return 0;
133 : }
134 1 : else if(!strcmp(directive, "group")){
135 1 : group_info = getgrnam(params);
136 1 : if(!group_info){
137 0 : logprintf(config->log, LOG_ERROR, "Failed to get group info for %s\n", params);
138 0 : return -1;
139 : }
140 1 : config->privileges.gid = group_info->gr_gid;
141 1 : logprintf(config->log, LOG_DEBUG, "Configured dropped privileges to gid %d\n", config->privileges.gid);
142 1 : return 0;
143 : }
144 0 : return -1;
145 : }
146 :
147 1 : int config_database(CONFIGURATION* config, char* directive, char* params){
148 1 : if(config->database.conn){
149 0 : logprintf(config->log, LOG_ERROR, "Can not use %s as master database, another one is already attached\n", params);
150 0 : return -1;
151 : }
152 :
153 1 : config->database.conn = database_open(config->log, params, SQLITE_OPEN_READWRITE);
154 :
155 1 : return (config->database.conn) ? 0:-1;
156 : }
157 :
158 2 : int config_logger(CONFIGURATION* config, char* directive, char* params){
159 : FILE* log_file;
160 :
161 2 : if(!strcmp(directive, "verbosity")){
162 1 : config->log.verbosity = strtoul(params, NULL, 10);
163 1 : return 0;
164 : }
165 1 : else if(!strcmp(directive, "logfile")){
166 1 : log_file = fopen(params, "a");
167 1 : if(!log_file){
168 0 : logprintf(config->log, LOG_ERROR, "Failed to open logfile %s for appending\n", params);
169 0 : return -1;
170 : }
171 1 : config->log.stream = log_file;
172 1 : config->log.log_secondary = true;
173 1 : return 0;
174 : }
175 0 : return -1;
176 : }
177 :
178 1 : int config_pidfile(CONFIGURATION* config, char* directive, char* params){
179 1 : if(config->pid_file){
180 0 : logprintf(config->log, LOG_ERROR, "Multiple pidfile stanzas read, aborting\n");
181 0 : return -1;
182 : }
183 :
184 1 : config->pid_file = common_strdup(params);
185 :
186 1 : if(!config->pid_file){
187 0 : logprintf(config->log, LOG_ERROR, "Failed to allocate memory for pidfile path\n");
188 0 : return -1;
189 : }
190 1 : return 0;
191 : }
192 :
193 10 : int config_line(void* config_data, char* line){
194 : unsigned parameter;
195 10 : CONFIGURATION* config = (CONFIGURATION*)config_data;
196 :
197 : //scan over directive
198 10 : for(parameter = 0; (!isspace(line[parameter])) && line[parameter] != 0; parameter++){
199 : }
200 :
201 10 : if(line[parameter] != 0){
202 10 : line[parameter] = 0;
203 10 : parameter++;
204 : }
205 :
206 : //scan for parameter begin
207 10 : for(; isspace(line[parameter]); parameter++){
208 : }
209 :
210 : //route directives
211 10 : if(!strncmp(line, "bind", 4)){
212 4 : return config_bind(config, line, line + parameter);
213 : }
214 :
215 6 : else if(!strncmp(line, "user", 4) || !strncmp(line, "group", 5)){
216 2 : return config_privileges(config, line, line + parameter);
217 : }
218 :
219 4 : else if(!strncmp(line, "database", 8)){
220 1 : return config_database(config, line, line + parameter);
221 : }
222 :
223 3 : else if(!strncmp(line, "verbosity", 9) || !strncmp(line, "logfile", 7)){
224 2 : return config_logger(config, line, line + parameter);
225 : }
226 :
227 1 : else if(!strncmp(line, "pidfile", 7)){
228 1 : return config_pidfile(config, line, line + parameter);
229 : }
230 :
231 0 : logprintf(config->log, LOG_ERROR, "Unknown configuration directive %s\n", line);
232 0 : return -1;
233 : }
234 :
235 2 : void config_free(CONFIGURATION* config){
236 : unsigned i;
237 : LISTENER* listener_data;
238 :
239 10 : for(i = 0; i < config->listeners.count; i++){
240 8 : listener_data = (LISTENER*)config->listeners.conns[i].aux_data;
241 :
242 : #ifndef CMAIL_NO_TLS
243 8 : if(config->listeners.conns[i].tls_mode != TLS_NONE){
244 8 : gnutls_certificate_free_credentials(listener_data->tls_cert);
245 8 : gnutls_priority_deinit(listener_data->tls_priorities);
246 8 : gnutls_dh_params_deinit(listener_data->tls_dhparams);
247 : }
248 : #endif
249 8 : free(listener_data->announce_domain);
250 : }
251 :
252 2 : connpool_free(&(config->listeners));
253 2 : database_free(config->log, &(config->database));
254 :
255 2 : if(config->pid_file){
256 2 : free(config->pid_file);
257 : }
258 :
259 2 : if(config->log.stream != stderr){
260 2 : fclose(config->log.stream);
261 2 : config->log.stream = stderr;
262 : }
263 2 : }
|