]>
Commit | Line | Data |
---|---|---|
e8d25806 MW |
1 | /** |
2 | * @file stroke.c | |
3 | * | |
4 | * @brief Implementation of stroke_t. | |
5 | * | |
6 | */ | |
7 | ||
8 | /* | |
9 | * Copyright (C) 2006 Martin Willi | |
10 | * Hochschule fuer Technik Rapperswil | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or modify it | |
13 | * under the terms of the GNU General Public License as published by the | |
14 | * Free Software Foundation; either version 2 of the License, or (at your | |
15 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
16 | * | |
17 | * This program is distributed in the hope that it will be useful, but | |
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
19 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
20 | * for more details. | |
21 | */ | |
22 | ||
23 | #include <stdlib.h> | |
24 | #include <sys/types.h> | |
25 | #include <sys/stat.h> | |
26 | #include <sys/socket.h> | |
27 | #include <sys/un.h> | |
28 | #include <sys/fcntl.h> | |
29 | #include <unistd.h> | |
efadbf79 | 30 | #include <dirent.h> |
e8d25806 MW |
31 | #include <errno.h> |
32 | #include <pthread.h> | |
33 | ||
f2ee13a7 | 34 | #include "stroke_interface.h" |
e8d25806 | 35 | |
f2ee13a7 | 36 | #include <stroke.h> |
e8d25806 MW |
37 | #include <types.h> |
38 | #include <daemon.h> | |
ec6582cc | 39 | #include <crypto/x509.h> |
e8d25806 MW |
40 | #include <queues/jobs/initiate_ike_sa_job.h> |
41 | ||
42 | ||
43 | struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET}; | |
44 | ||
e8d25806 MW |
45 | |
46 | typedef struct private_stroke_t private_stroke_t; | |
47 | ||
48 | /** | |
49 | * Private data of an stroke_t object. | |
50 | */ | |
51 | struct private_stroke_t { | |
52 | ||
53 | /** | |
54 | * Public part of stroke_t object. | |
55 | */ | |
56 | stroke_t public; | |
57 | ||
e8d25806 | 58 | /** |
f2ee13a7 | 59 | * Assigned logger_t object in charon. |
e8d25806 MW |
60 | */ |
61 | logger_t *logger; | |
f2ee13a7 MW |
62 | |
63 | /** | |
64 | * Logger which logs to stroke | |
65 | */ | |
66 | logger_t *stroke_logger; | |
e8d25806 MW |
67 | |
68 | /** | |
f2ee13a7 | 69 | * Unix socket to listen for strokes |
e8d25806 MW |
70 | */ |
71 | int socket; | |
72 | ||
73 | /** | |
74 | * Thread which reads from the socket | |
75 | */ | |
76 | pthread_t assigned_thread; | |
77 | ||
78 | /** | |
79 | * Read from the socket and handle stroke messages | |
80 | */ | |
81 | void (*stroke_receive) (private_stroke_t *this); | |
e8d25806 MW |
82 | }; |
83 | ||
84 | /** | |
85 | * Helper function which corrects the string pointers | |
efadbf79 MW |
86 | * in a stroke_msg_t. Strings in a stroke_msg sent over "wire" |
87 | * contains RELATIVE addresses (relative to the beginning of the | |
e8d25806 MW |
88 | * stroke_msg). They must be corrected if they reach our address |
89 | * space... | |
90 | */ | |
87a217f9 | 91 | static void pop_string(stroke_msg_t *msg, char **string) |
e8d25806 MW |
92 | { |
93 | /* check for sanity of string pointer and string */ | |
87a217f9 MW |
94 | if (*string == NULL) |
95 | { | |
96 | *string = ""; | |
97 | } | |
98 | else if (string < (char**)msg || | |
e8d25806 MW |
99 | string > (char**)msg + sizeof(stroke_msg_t) || |
100 | *string < (char*)msg->buffer - (u_int)msg || | |
101 | *string > (char*)(u_int)msg->length) | |
102 | { | |
103 | *string = "(invalid char* in stroke msg)"; | |
104 | } | |
105 | else | |
106 | { | |
107 | *string = (char*)msg + (u_int)*string; | |
108 | } | |
109 | } | |
110 | ||
f2ee13a7 MW |
111 | /** |
112 | * Add a connection to the configuration list | |
113 | */ | |
114 | static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg) | |
115 | { | |
116 | connection_t *connection; | |
117 | policy_t *policy; | |
118 | identification_t *my_id, *other_id; | |
119 | host_t *my_host, *other_host, *my_subnet, *other_subnet; | |
120 | proposal_t *proposal; | |
121 | traffic_selector_t *my_ts, *other_ts; | |
13e4a62f | 122 | x509_t *cert; |
f2ee13a7 MW |
123 | |
124 | pop_string(msg, &msg->add_conn.name); | |
125 | pop_string(msg, &msg->add_conn.me.address); | |
126 | pop_string(msg, &msg->add_conn.other.address); | |
127 | pop_string(msg, &msg->add_conn.me.id); | |
128 | pop_string(msg, &msg->add_conn.other.id); | |
129 | pop_string(msg, &msg->add_conn.me.cert); | |
130 | pop_string(msg, &msg->add_conn.other.cert); | |
131 | pop_string(msg, &msg->add_conn.me.subnet); | |
132 | pop_string(msg, &msg->add_conn.other.subnet); | |
133 | ||
134 | this->logger->log(this->logger, CONTROL, "received stroke: add connection \"%s\"", msg->add_conn.name); | |
135 | ||
136 | my_host = host_create(AF_INET, msg->add_conn.me.address, 500); | |
137 | if (my_host == NULL) | |
138 | { | |
139 | this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.me.address); | |
140 | return; | |
141 | } | |
142 | other_host = host_create(AF_INET, msg->add_conn.other.address, 500); | |
143 | if (other_host == NULL) | |
144 | { | |
145 | this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.other.address); | |
146 | my_host->destroy(my_host); | |
147 | return; | |
148 | } | |
a8c09d8c MW |
149 | my_id = identification_create_from_string(*msg->add_conn.me.id ? |
150 | msg->add_conn.me.id : msg->add_conn.me.address); | |
f2ee13a7 MW |
151 | if (my_id == NULL) |
152 | { | |
153 | this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.me.id); | |
154 | my_host->destroy(my_host); | |
155 | other_host->destroy(other_host); | |
156 | return; | |
157 | } | |
a8c09d8c MW |
158 | other_id = identification_create_from_string(*msg->add_conn.other.id ? |
159 | msg->add_conn.other.id : msg->add_conn.other.address); | |
f2ee13a7 MW |
160 | if (other_id == NULL) |
161 | { | |
162 | my_host->destroy(my_host); | |
163 | other_host->destroy(other_host); | |
164 | my_id->destroy(my_id); | |
165 | this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.other.id); | |
166 | return; | |
167 | } | |
a8c09d8c | 168 | |
f2ee13a7 MW |
169 | my_subnet = host_create(AF_INET, *msg->add_conn.me.subnet ? msg->add_conn.me.subnet : msg->add_conn.me.address, 500); |
170 | if (my_subnet == NULL) | |
171 | { | |
172 | my_host->destroy(my_host); | |
173 | other_host->destroy(other_host); | |
174 | my_id->destroy(my_id); | |
175 | other_id->destroy(other_id); | |
176 | this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet); | |
177 | return; | |
178 | } | |
a8c09d8c | 179 | |
f2ee13a7 MW |
180 | other_subnet = host_create(AF_INET, *msg->add_conn.other.subnet ? msg->add_conn.other.subnet : msg->add_conn.other.address, 500); |
181 | if (other_subnet == NULL) | |
182 | { | |
183 | my_host->destroy(my_host); | |
184 | other_host->destroy(other_host); | |
185 | my_id->destroy(my_id); | |
186 | other_id->destroy(other_id); | |
187 | my_subnet->destroy(my_subnet); | |
188 | this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet); | |
189 | return; | |
190 | } | |
191 | ||
192 | my_ts = traffic_selector_create_from_subnet(my_subnet, *msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 32); | |
193 | my_subnet->destroy(my_subnet); | |
194 | other_ts = traffic_selector_create_from_subnet(other_subnet, *msg->add_conn.other.subnet ? msg->add_conn.other.subnet_mask : 32); | |
195 | other_subnet->destroy(other_subnet); | |
196 | ||
197 | if (charon->socket->is_listening_on(charon->socket, other_host)) | |
198 | { | |
199 | this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is other host, switching"); | |
13e4a62f | 200 | |
f2ee13a7 MW |
201 | host_t *tmp_host = my_host; |
202 | identification_t *tmp_id = my_id; | |
203 | traffic_selector_t *tmp_ts = my_ts; | |
204 | char *tmp_cert = msg->add_conn.me.cert; | |
13e4a62f | 205 | |
f2ee13a7 MW |
206 | my_host = other_host; |
207 | other_host = tmp_host; | |
208 | my_id = other_id; | |
209 | other_id = tmp_id; | |
210 | my_ts = other_ts; | |
211 | other_ts = tmp_ts; | |
212 | msg->add_conn.me.cert = msg->add_conn.other.cert; | |
213 | msg->add_conn.other.cert = tmp_cert; | |
214 | } | |
215 | else if (charon->socket->is_listening_on(charon->socket, my_host)) | |
216 | { | |
217 | this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is own host, not switching"); | |
218 | } | |
219 | else | |
220 | { | |
221 | this->stroke_logger->log(this->stroke_logger, ERROR, "left nor right host is our, aborting"); | |
13e4a62f | 222 | |
f2ee13a7 MW |
223 | my_host->destroy(my_host); |
224 | other_host->destroy(other_host); | |
225 | my_id->destroy(my_id); | |
226 | other_id->destroy(other_id); | |
227 | my_ts->destroy(my_ts); | |
228 | other_ts->destroy(other_ts); | |
229 | return; | |
230 | } | |
231 | ||
13e4a62f MW |
232 | if (msg->add_conn.me.cert) |
233 | { | |
234 | char file[128]; | |
235 | snprintf(file, sizeof(file), "%s%s", CERTIFICATE_DIR, msg->add_conn.me.cert); | |
236 | cert = x509_create_from_file(file); | |
237 | if (cert) | |
238 | { | |
239 | my_id->destroy(my_id); | |
240 | my_id = cert->get_subject(cert); | |
241 | my_id = my_id->clone(my_id); | |
242 | cert->destroy(cert); | |
243 | this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, | |
244 | "defined a valid certificate, using its ID \"%s\"", | |
245 | my_id->get_string(my_id)); | |
246 | } | |
247 | } | |
248 | if (msg->add_conn.other.cert) | |
249 | { | |
250 | char file[128]; | |
251 | snprintf(file, sizeof(file), "%s%s", CERTIFICATE_DIR, msg->add_conn.other.cert); | |
252 | cert = x509_create_from_file(file); | |
253 | if (cert) | |
254 | { | |
255 | other_id->destroy(other_id); | |
256 | other_id = cert->get_subject(cert); | |
257 | other_id = other_id->clone(other_id); | |
258 | cert->destroy(cert); | |
259 | this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, | |
260 | "defined a valid certificate, using its ID \"%s\"", | |
261 | other_id->get_string(other_id)); | |
262 | } | |
263 | } | |
264 | ||
e168ee17 MW |
265 | connection = connection_create(msg->add_conn.name, |
266 | my_host, other_host, | |
267 | my_id->clone(my_id), other_id->clone(other_id), | |
f2ee13a7 MW |
268 | RSA_DIGITAL_SIGNATURE); |
269 | proposal = proposal_create(1); | |
270 | proposal->add_algorithm(proposal, PROTO_IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16); | |
271 | proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); | |
272 | proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); | |
273 | proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1, 0); | |
274 | proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0); | |
275 | proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0); | |
276 | proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0); | |
277 | proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); | |
278 | proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0); | |
279 | proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0); | |
280 | connection->add_proposal(connection, proposal); | |
13e4a62f MW |
281 | /* add to global connection list */ |
282 | charon->connections->add_connection(charon->connections, connection); | |
283 | ||
f2ee13a7 MW |
284 | policy = policy_create(my_id, other_id); |
285 | proposal = proposal_create(1); | |
286 | proposal->add_algorithm(proposal, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16); | |
287 | proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); | |
288 | proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); | |
289 | policy->add_proposal(policy, proposal); | |
290 | policy->add_my_traffic_selector(policy, my_ts); | |
291 | policy->add_other_traffic_selector(policy, other_ts); | |
13e4a62f MW |
292 | /* add to global policy list */ |
293 | charon->policies->add_policy(charon->policies, policy); | |
294 | ||
295 | this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "connection \"%s\" added", msg->add_conn.name); | |
f2ee13a7 MW |
296 | } |
297 | ||
298 | /** | |
299 | * initiate a connection by name | |
300 | */ | |
301 | static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg) | |
302 | { | |
303 | initiate_ike_sa_job_t *job; | |
304 | connection_t *connection; | |
305 | ||
306 | pop_string(msg, &(msg->initiate.name)); | |
307 | this->logger->log(this->logger, CONTROL, "received stroke: initiate \"%s\"", msg->initiate.name); | |
e168ee17 | 308 | connection = charon->connections->get_connection_by_name(charon->connections, msg->initiate.name); |
f2ee13a7 MW |
309 | if (connection == NULL) |
310 | { | |
311 | this->stroke_logger->log(this->stroke_logger, ERROR, "could not find a connection named \"%s\"", msg->initiate.name); | |
312 | } | |
313 | else | |
314 | { | |
eea35346 | 315 | job = initiate_ike_sa_job_create(connection); |
f2ee13a7 MW |
316 | charon->job_queue->add(charon->job_queue, (job_t*)job); |
317 | } | |
318 | } | |
319 | ||
320 | /** | |
321 | * terminate a connection by name | |
322 | */ | |
323 | static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg) | |
324 | { | |
325 | connection_t *connection; | |
326 | ike_sa_t *ike_sa; | |
327 | host_t *my_host, *other_host; | |
328 | status_t status; | |
329 | ||
330 | pop_string(msg, &(msg->terminate.name)); | |
331 | this->logger->log(this->logger, CONTROL, "received stroke: terminate \"%s\"", msg->terminate.name); | |
e168ee17 | 332 | connection = charon->connections->get_connection_by_name(charon->connections, msg->terminate.name); |
f2ee13a7 MW |
333 | |
334 | if (connection) | |
335 | { | |
336 | my_host = connection->get_my_host(connection); | |
337 | other_host = connection->get_other_host(connection); | |
338 | ||
e168ee17 MW |
339 | /* TODO: Do this directly by name now */ |
340 | /* TODO: terminate any instance of the name */ | |
f2ee13a7 MW |
341 | status = charon->ike_sa_manager->checkout_by_hosts(charon->ike_sa_manager, |
342 | my_host, other_host, &ike_sa); | |
343 | ||
344 | if (status == SUCCESS) | |
345 | { | |
346 | this->stroke_logger->log(this->stroke_logger, CONTROL, "deleting IKE SA between %s - %s", | |
347 | my_host->get_address(my_host), other_host->get_address(other_host)); | |
348 | ||
349 | charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa); | |
350 | } | |
351 | else | |
352 | { | |
353 | this->stroke_logger->log(this->stroke_logger, ERROR, "no active connection found between %s - %s", | |
354 | my_host->get_address(my_host), other_host->get_address(other_host)); | |
355 | } | |
356 | } | |
357 | else | |
358 | { | |
359 | this->stroke_logger->log(this->stroke_logger, ERROR, "could not find a connection named \"%s\"", msg->terminate.name); | |
360 | } | |
361 | ||
362 | } | |
363 | ||
364 | /** | |
365 | * show status of (established) connections | |
366 | */ | |
367 | static void stroke_status(private_stroke_t *this, stroke_msg_t *msg) | |
368 | { | |
e168ee17 MW |
369 | if (msg->status.name) |
370 | { | |
371 | pop_string(msg, &(msg->status.name)); | |
f2ee13a7 | 372 | } |
e168ee17 | 373 | charon->ike_sa_manager->log_status(charon->ike_sa_manager, this->stroke_logger, msg->status.name); |
f2ee13a7 MW |
374 | } |
375 | ||
376 | logger_context_t get_context(char *context) | |
377 | { | |
378 | if (strcasecmp(context, "ALL") == 0) return ALL_LOGGERS; | |
379 | else if (strcasecmp(context, "PARSR") == 0) return PARSER; | |
380 | else if (strcasecmp(context, "GNRAT") == 0) return GENERATOR; | |
381 | else if (strcasecmp(context, "IKESA") == 0) return IKE_SA; | |
382 | else if (strcasecmp(context, "SAMGR") == 0) return IKE_SA_MANAGER; | |
383 | else if (strcasecmp(context, "CHDSA") == 0) return CHILD_SA; | |
384 | else if (strcasecmp(context, "MESSG") == 0) return MESSAGE; | |
385 | else if (strcasecmp(context, "TPOOL") == 0) return THREAD_POOL; | |
386 | else if (strcasecmp(context, "WORKR") == 0) return WORKER; | |
387 | else if (strcasecmp(context, "SCHED") == 0) return SCHEDULER; | |
388 | else if (strcasecmp(context, "SENDR") == 0) return SENDER; | |
389 | else if (strcasecmp(context, "RECVR") == 0) return RECEIVER; | |
390 | else if (strcasecmp(context, "SOCKT") == 0) return SOCKET; | |
391 | else if (strcasecmp(context, "TESTR") == 0) return TESTER; | |
392 | else if (strcasecmp(context, "DAEMN") == 0) return DAEMON; | |
393 | else if (strcasecmp(context, "CONFG") == 0) return CONFIG; | |
394 | else if (strcasecmp(context, "ENCPL") == 0) return ENCRYPTION_PAYLOAD; | |
395 | else if (strcasecmp(context, "PAYLD") == 0) return PAYLOAD; | |
396 | else return -2; | |
397 | } | |
398 | ||
399 | /** | |
400 | * set the type of logged messages in a context | |
401 | */ | |
402 | static void stroke_logtype(private_stroke_t *this, stroke_msg_t *msg) | |
403 | { | |
404 | pop_string(msg, &(msg->logtype.context)); | |
405 | pop_string(msg, &(msg->logtype.type)); | |
406 | ||
407 | this->logger->log(this->logger, CONTROL, "received stroke: logtype for %s", msg->logtype.context); | |
408 | ||
409 | log_level_t level; | |
410 | logger_context_t context = get_context(msg->logtype.context); | |
411 | if (context == -2) | |
412 | { | |
413 | this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->logtype.context); | |
414 | return; | |
415 | } | |
416 | ||
417 | if (strcasecmp(msg->logtype.type, "CONTROL") == 0) level = CONTROL; | |
418 | else if (strcasecmp(msg->logtype.type, "ERROR") == 0) level = ERROR; | |
419 | else if (strcasecmp(msg->logtype.type, "AUDIT") == 0) level = AUDIT; | |
420 | else if (strcasecmp(msg->logtype.type, "RAW") == 0) level = RAW; | |
421 | else if (strcasecmp(msg->logtype.type, "PRIVATE") == 0) level = PRIVATE; | |
422 | else | |
423 | { | |
424 | this->stroke_logger->log(this->stroke_logger, ERROR, "invalid type (%s)!", msg->logtype.type); | |
425 | return; | |
426 | } | |
427 | ||
428 | if (msg->logtype.enable) | |
429 | { | |
5113680f | 430 | logger_manager->enable_log_level(logger_manager, context, level); |
f2ee13a7 MW |
431 | } |
432 | else | |
433 | { | |
5113680f | 434 | logger_manager->disable_log_level(logger_manager, context, level); |
f2ee13a7 MW |
435 | } |
436 | } | |
437 | ||
438 | /** | |
439 | * set the verbosity of a logger | |
440 | */ | |
441 | static void stroke_loglevel(private_stroke_t *this, stroke_msg_t *msg) | |
442 | { | |
443 | pop_string(msg, &(msg->loglevel.context)); | |
444 | ||
8f1c27ba | 445 | this->logger->log(this->logger, CONTROL, "received stroke: loglevel for %s", msg->loglevel.context); |
f2ee13a7 MW |
446 | |
447 | log_level_t level; | |
448 | logger_context_t context = get_context(msg->loglevel.context); | |
449 | ||
450 | if (context == -2) | |
451 | { | |
452 | this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->loglevel.context); | |
453 | return; | |
454 | } | |
455 | ||
456 | if (msg->loglevel.level == 0) | |
457 | { | |
458 | level = LEVEL0; | |
459 | } | |
460 | else if (msg->loglevel.level == 1) | |
461 | { | |
462 | level = LEVEL1; | |
463 | } | |
464 | else if (msg->loglevel.level == 2) | |
465 | { | |
466 | level = LEVEL2; | |
467 | } | |
468 | else if (msg->loglevel.level == 3) | |
469 | { | |
470 | level = LEVEL3; | |
471 | } | |
472 | else | |
473 | { | |
474 | this->stroke_logger->log(this->stroke_logger, ERROR, "invalid level (%d)!", msg->loglevel.level); | |
475 | return; | |
476 | } | |
477 | ||
5113680f | 478 | logger_manager->enable_log_level(logger_manager, context, level); |
f2ee13a7 MW |
479 | } |
480 | ||
e8d25806 MW |
481 | /** |
482 | * Implementation of private_stroke_t.stroke_receive. | |
483 | */ | |
484 | static void stroke_receive(private_stroke_t *this) | |
485 | { | |
486 | stroke_msg_t *msg; | |
487 | u_int16_t msg_length; | |
488 | struct sockaddr_un strokeaddr; | |
489 | int strokeaddrlen = sizeof(strokeaddr); | |
490 | ssize_t bytes_read; | |
491 | int strokefd; | |
f2ee13a7 | 492 | FILE *strokefile; |
5113680f MW |
493 | int oldstate; |
494 | ||
495 | /* disable cancellation by default */ | |
496 | pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); | |
e8d25806 MW |
497 | |
498 | while (1) | |
499 | { | |
5113680f MW |
500 | /* wait for connections, but allow thread to terminate */ |
501 | pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); | |
e8d25806 | 502 | strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen); |
5113680f MW |
503 | pthread_setcancelstate(oldstate, NULL); |
504 | ||
e8d25806 MW |
505 | if (strokefd < 0) |
506 | { | |
f2ee13a7 | 507 | this->logger->log(this->logger, ERROR, "accepting stroke connection failed: %s", strerror(errno)); |
e8d25806 MW |
508 | continue; |
509 | } | |
510 | ||
511 | /* peek the length */ | |
512 | bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK); | |
513 | if (bytes_read != sizeof(msg_length)) | |
514 | { | |
515 | this->logger->log(this->logger, ERROR, "reading lenght of stroke message failed"); | |
516 | close(strokefd); | |
517 | continue; | |
518 | } | |
519 | ||
520 | /* read message */ | |
5113680f | 521 | msg = malloc(msg_length); |
e8d25806 MW |
522 | bytes_read = recv(strokefd, msg, msg_length, 0); |
523 | if (bytes_read != msg_length) | |
524 | { | |
f2ee13a7 | 525 | this->logger->log(this->logger, ERROR, "reading stroke message failed: %s"); |
e8d25806 MW |
526 | close(strokefd); |
527 | continue; | |
528 | } | |
529 | ||
f2ee13a7 MW |
530 | strokefile = fdopen(dup(strokefd), "w"); |
531 | if (strokefile == NULL) | |
532 | { | |
533 | this->logger->log(this->logger, ERROR, "opening stroke output channel failed:", strerror(errno)); | |
534 | close(strokefd); | |
5113680f | 535 | free(msg); |
f2ee13a7 MW |
536 | continue; |
537 | } | |
538 | ||
539 | this->stroke_logger = logger_create("-", CONTROL|ERROR, FALSE, strokefile); | |
540 | ||
dec59822 | 541 | this->logger->log_bytes(this->logger, RAW, "stroke message", (void*)msg, msg_length); |
e8d25806 MW |
542 | |
543 | switch (msg->type) | |
544 | { | |
545 | case STR_INITIATE: | |
546 | { | |
f2ee13a7 MW |
547 | stroke_initiate(this, msg); |
548 | break; | |
549 | } | |
550 | case STR_TERMINATE: | |
551 | { | |
552 | stroke_terminate(this, msg); | |
e8d25806 MW |
553 | break; |
554 | } | |
f2ee13a7 | 555 | case STR_STATUS: |
e8d25806 | 556 | { |
f2ee13a7 | 557 | stroke_status(this, msg); |
e8d25806 MW |
558 | break; |
559 | } | |
e168ee17 MW |
560 | case STR_STATUS_ALL: |
561 | { | |
562 | this->stroke_logger->enable_level(this->stroke_logger, LEVEL1); | |
563 | stroke_status(this, msg); | |
564 | break; | |
565 | } | |
e8d25806 MW |
566 | case STR_ADD_CONN: |
567 | { | |
f2ee13a7 MW |
568 | stroke_add_conn(this, msg); |
569 | break; | |
570 | } | |
571 | case STR_LOGTYPE: | |
572 | { | |
573 | stroke_logtype(this, msg); | |
574 | break; | |
575 | } | |
576 | case STR_LOGLEVEL: | |
577 | { | |
578 | stroke_loglevel(this, msg); | |
e8d25806 MW |
579 | break; |
580 | } | |
e8d25806 MW |
581 | default: |
582 | this->logger->log(this->logger, ERROR, "received invalid stroke"); | |
583 | } | |
f2ee13a7 MW |
584 | this->stroke_logger->destroy(this->stroke_logger); |
585 | fclose(strokefile); | |
87a217f9 | 586 | close(strokefd); |
5113680f | 587 | free(msg); |
e8d25806 MW |
588 | } |
589 | } | |
590 | ||
e8d25806 MW |
591 | /** |
592 | * Implementation of stroke_t.destroy. | |
593 | */ | |
594 | static void destroy(private_stroke_t *this) | |
595 | { | |
87a217f9 | 596 | |
5113680f MW |
597 | pthread_cancel(this->assigned_thread); |
598 | pthread_join(this->assigned_thread, NULL); | |
e8d25806 | 599 | |
e8d25806 MW |
600 | close(this->socket); |
601 | unlink(socket_addr.sun_path); | |
5113680f | 602 | free(this); |
e8d25806 MW |
603 | } |
604 | ||
e8d25806 MW |
605 | |
606 | /* | |
607 | * Described in header-file | |
608 | */ | |
609 | stroke_t *stroke_create() | |
610 | { | |
5113680f | 611 | private_stroke_t *this = malloc_thing(private_stroke_t); |
e8d25806 MW |
612 | mode_t old; |
613 | ||
614 | /* public functions */ | |
e8d25806 MW |
615 | this->public.destroy = (void (*)(stroke_t*))destroy; |
616 | ||
617 | /* private functions */ | |
618 | this->stroke_receive = stroke_receive; | |
e8d25806 | 619 | |
5113680f | 620 | this->logger = logger_manager->get_logger(logger_manager, CONFIG); |
e8d25806 MW |
621 | |
622 | /* set up unix socket */ | |
623 | this->socket = socket(AF_UNIX, SOCK_STREAM, 0); | |
624 | if (this->socket == -1) | |
625 | { | |
626 | this->logger->log(this->logger, ERROR, "could not create whack socket"); | |
5113680f | 627 | free(this); |
e8d25806 MW |
628 | return NULL; |
629 | } | |
630 | ||
631 | old = umask(~S_IRWXU); | |
632 | if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0) | |
633 | { | |
634 | this->logger->log(this->logger, ERROR, "could not bind stroke socket: %s", strerror(errno)); | |
e8d25806 | 635 | close(this->socket); |
5113680f | 636 | free(this); |
e8d25806 MW |
637 | return NULL; |
638 | } | |
639 | umask(old); | |
640 | ||
641 | if (listen(this->socket, 0) < 0) | |
642 | { | |
643 | this->logger->log(this->logger, ERROR, "could not listen on stroke socket: %s", strerror(errno)); | |
e8d25806 MW |
644 | close(this->socket); |
645 | unlink(socket_addr.sun_path); | |
5113680f | 646 | free(this); |
e8d25806 MW |
647 | return NULL; |
648 | } | |
649 | ||
650 | /* start a thread reading from the socket */ | |
651 | if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->stroke_receive, this) != 0) | |
652 | { | |
653 | this->logger->log(this->logger, ERROR, "Could not spawn stroke thread"); | |
e8d25806 MW |
654 | close(this->socket); |
655 | unlink(socket_addr.sun_path); | |
5113680f | 656 | free(this); |
87a217f9 | 657 | return NULL; |
e8d25806 MW |
658 | } |
659 | ||
e8d25806 MW |
660 | return (&this->public); |
661 | } |