diff options
Diffstat (limited to 'src')
23 files changed, 1241 insertions, 985 deletions
diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index fa8b322e5..3db6ae48a 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -11,6 +11,7 @@ sa/states/state.c sa/states/state.h sa/states/ike_sa_init_requested.c sa/states/ sa/states/ike_sa_init_responded.c sa/states/ike_sa_established.c sa/states/ike_sa_established.h \ sa/states/responder_init.c sa/states/responder_init.h sa/states/initiator_init.c sa/states/initiator_init.h \ sa/states/ike_sa_init_responded.h sa/states/ike_auth_requested.c sa/states/ike_auth_requested.h \ +sa/states/delete_requested.h sa/states/delete_requested.c \ sa/child_sa.c sa/child_sa.h sa/ike_sa.c sa/ike_sa.h sa/ike_sa_manager.c sa/ike_sa_manager.h \ sa/ike_sa_id.c sa/ike_sa_id.h sa/authenticator.c sa/authenticator.h encoding/payloads/encryption_payload.c \ encoding/payloads/cert_payload.c encoding/payloads/payload.h encoding/payloads/traffic_selector_substructure.c \ diff --git a/src/charon/encoding/message.c b/src/charon/encoding/message.c index a57315272..9875a3df9 100644 --- a/src/charon/encoding/message.c +++ b/src/charon/encoding/message.c @@ -941,7 +941,7 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig iterator->destroy(iterator); return FAILED; } - /* decrypt */ + /* decrypt */ encryption_payload->set_transforms(encryption_payload, crypter, signer); this->logger->log(this->logger, CONTROL | LEVEL1, "Verify signature of encryption payload"); status = encryption_payload->verify_signature(encryption_payload, this->packet->get_data(this->packet)); @@ -955,8 +955,9 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig status = encryption_payload->decrypt(encryption_payload); if (status != SUCCESS) { - this->logger->log(this->logger, ERROR | LEVEL1, "Encrypted payload could not be decrypted and parsed: %s", - mapping_find(status_m, status)); + this->logger->log(this->logger, ERROR | LEVEL1, + "Encrypted payload could not be decrypted and parsed: %s", + mapping_find(status_m, status)); iterator->destroy(iterator); return status; } @@ -997,8 +998,9 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig while (encryption_payload->get_payload_count(encryption_payload) > 0) { encryption_payload->remove_first_payload(encryption_payload, ¤t_encrypted_payload); - this->logger->log(this->logger, CONTROL | LEVEL1, "Insert unencrypted payload of type %s at end of list.", - mapping_find(payload_type_m,current_encrypted_payload->get_type(current_encrypted_payload))); + this->logger->log(this->logger, CONTROL | LEVEL1, + "Insert unencrypted payload of type %s at end of list.", + mapping_find(payload_type_m, current_encrypted_payload->get_type(current_encrypted_payload))); this->payloads->insert_last(this->payloads,current_encrypted_payload); } @@ -1007,14 +1009,15 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig } /* we allow unknown payloads of any type and don't bother if it was encrypted. Not our problem. */ - if (current_payload_type != UNKNOWN_PAYLOAD) + if (current_payload_type != UNKNOWN_PAYLOAD && current_payload_type != NO_PAYLOAD) { /* get the ruleset for found payload */ status = this->get_payload_rule(this, current_payload_type, &payload_rule); if (status != SUCCESS) { /* payload is not allowed */ - this->logger->log(this->logger, ERROR | LEVEL1, "Payload type %s not allowed",mapping_find(payload_type_m,current_payload_type)); + this->logger->log(this->logger, ERROR | LEVEL1, "Payload type %s not allowed", + mapping_find(payload_type_m,current_payload_type)); iterator->destroy(iterator); return status; } diff --git a/src/charon/encoding/payloads/encryption_payload.c b/src/charon/encoding/payloads/encryption_payload.c index e0ca74ff4..358f371e9 100644 --- a/src/charon/encoding/payloads/encryption_payload.c +++ b/src/charon/encoding/payloads/encryption_payload.c @@ -556,13 +556,6 @@ static status_t parse(private_encryption_payload_t *this) status_t status; payload_type_t current_payload_type; - /* check if there is decrypted data */ - if (this->decrypted.ptr == NULL) - { - this->logger->log(this->logger, ERROR, "unable to parse, no input!"); - return INVALID_STATE; - } - /* build a parser on the decrypted data */ parser = parser_create(this->decrypted); diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 5290bde64..c012ce82b 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -42,6 +42,7 @@ #include <sa/states/responder_init.h> #include <queues/jobs/retransmit_request_job.h> #include <queues/jobs/delete_established_ike_sa_job.h> +#include <queues/jobs/delete_half_open_ike_sa_job.h> @@ -186,43 +187,45 @@ struct private_ike_sa_t { * A logger for this IKE_SA. */ logger_t *logger; - - /** - * Resends the last sent reply. - * - * @param this calling object - */ - status_t (*resend_last_reply) (private_ike_sa_t *this); }; /** * Implementation of ike_sa_t.process_message. */ -static status_t process_message (private_ike_sa_t *this, message_t *message) +static status_t process_message(private_ike_sa_t *this, message_t *message) { u_int32_t message_id; exchange_type_t exchange_type; bool is_request; - /* We must process each request or response from remote host */ - + /* Find out type of message (request or response) */ is_request = message->get_request(message); exchange_type = message->get_exchange_type(message); - + this->logger->log(this->logger, CONTROL|LEVEL1, "Process %s of exchange type %s", (is_request) ? "request" : "response",mapping_find(exchange_type_m,exchange_type)); - + message_id = message->get_message_id(message); - + /* * It has to be checked, if the message has to be resent cause of lost packets! */ if (is_request && (message_id == (this->message_id_in - 1))) { - /* Message can be resent ! */ - this->logger->log(this->logger, CONTROL|LEVEL1, "Resent request detected. Send stored reply."); - return (this->resend_last_reply(this)); + /* resend last message, if any */ + if (this->last_responded_message) + { + packet_t *packet = this->last_responded_message->get_packet(this->last_responded_message); + this->logger->log(this->logger, CONTROL|LEVEL1, "Resent request detected. Send stored reply."); + charon->send_queue->add(charon->send_queue, packet); + return SUCCESS; + } + else + { + /* somebody does something nasty here... */ + return FAILED; + } } /* Now, the message id is checked for request AND reply */ @@ -253,7 +256,7 @@ static status_t process_message (private_ike_sa_t *this, message_t *message) * The specific state object is responsible to check if a message can be received in * the state it represents. * The current state is also responsible to change the state object to the next state - * by calling protected_ike_sa_t.set_new_state*/ + * by calling protected_ike_sa_t.set_new_state*/ return this->current_state->process_message(this->current_state,message); } @@ -269,7 +272,7 @@ static void build_message(private_ike_sa_t *this, exchange_type_t type, bool req other = this->connection->get_other_host(this->connection); this->logger->log(this->logger, CONTROL|LEVEL2, "Build empty message"); - new_message = message_create(); + new_message = message_create(); new_message->set_source(new_message, me->clone(me)); new_message->set_destination(new_message, other->clone(other)); new_message->set_exchange_type(new_message, type); @@ -301,55 +304,6 @@ static status_t initiate_connection(private_ike_sa_t *this, connection_t *connec } /** - * Implementation of ike_sa_t.send_delete_ike_sa_request. - */ -static void send_delete_ike_sa_request (private_ike_sa_t *this) -{ - message_t *informational_request; - delete_payload_t *delete_payload; - crypter_t *crypter; - signer_t *signer; - packet_t *packet; - status_t status; - - if (this->current_state->get_state(this->current_state) != IKE_SA_ESTABLISHED) - { - return; - } - - /* build empty INFORMATIONAL message */ - this->protected.build_message(&(this->protected), INFORMATIONAL, TRUE, &informational_request); - - delete_payload = delete_payload_create(); - delete_payload->set_protocol_id(delete_payload, PROTO_IKE); - - informational_request->add_payload(informational_request,(payload_t *)delete_payload); - - if (this->ike_sa_id->is_initiator(this->ike_sa_id)) - { - crypter = this->crypter_initiator; - signer = this->signer_initiator; - } - else - { - crypter = this->crypter_responder; - signer = this->signer_responder; - } - - status = informational_request->generate(informational_request, - crypter, - signer, &packet); - informational_request->destroy(informational_request); - if (status != SUCCESS) - { - this->logger->log(this->logger, ERROR, "Could not generate packet from message"); - return ; - } - - charon->send_queue->add(charon->send_queue,packet); -} - -/** * Implementation of ike_sa_t.get_id. */ static ike_sa_id_t* get_id(private_ike_sa_t *this) @@ -390,20 +344,6 @@ static identification_t* get_other_id(private_ike_sa_t *this) } /** - * Implementation of private_ike_sa_t.resend_last_reply. - */ -static status_t resend_last_reply(private_ike_sa_t *this) -{ - packet_t *packet; - - this->logger->log(this->logger, CONTROL | LEVEL1, "Going to retransmit last reply"); - packet = this->last_responded_message->get_packet(this->last_responded_message); - charon->send_queue->add(charon->send_queue, packet); - - return SUCCESS; -} - -/** * Implementation of ike_sa_t.retransmit_request. */ status_t retransmit_request (private_ike_sa_t *this, u_int32_t message_id) @@ -431,22 +371,30 @@ status_t retransmit_request (private_ike_sa_t *this, u_int32_t message_id) return SUCCESS; } + +/** + * Implementation of ike_sa_t.get_state. + */ +static ike_sa_state_t get_state(private_ike_sa_t *this) +{ + return this->current_state->get_state(this->current_state); +} /** * Implementation of protected_ike_sa_t.set_new_state. */ -static void set_new_state (private_ike_sa_t *this, state_t *state) +static void set_new_state(private_ike_sa_t *this, state_t *state) { this->logger->log(this->logger, CONTROL, "statechange: %s => %s", - mapping_find(ike_sa_state_m,this->current_state->get_state(this->current_state)), - mapping_find(ike_sa_state_m,state->get_state(state))); + mapping_find(ike_sa_state_m, get_state(this)), + mapping_find(ike_sa_state_m, state->get_state(state))); this->current_state = state; } /** * Implementation of protected_ike_sa_t.get_connection. */ -static connection_t *get_connection (private_ike_sa_t *this) +static connection_t *get_connection(private_ike_sa_t *this) { return this->connection; } @@ -454,7 +402,7 @@ static connection_t *get_connection (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.set_connection. */ -static void set_connection (private_ike_sa_t *this,connection_t * connection) +static void set_connection(private_ike_sa_t *this,connection_t * connection) { this->connection = connection; } @@ -462,7 +410,7 @@ static void set_connection (private_ike_sa_t *this,connection_t * connection) /** * Implementation of protected_ike_sa_t.get_policy. */ -static policy_t *get_policy (private_ike_sa_t *this) +static policy_t *get_policy(private_ike_sa_t *this) { return this->policy; } @@ -470,7 +418,7 @@ static policy_t *get_policy (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.set_policy. */ -static void set_policy (private_ike_sa_t *this,policy_t * policy) +static void set_policy(private_ike_sa_t *this,policy_t * policy) { this->policy = policy; } @@ -478,7 +426,7 @@ static void set_policy (private_ike_sa_t *this,policy_t * policy) /** * Implementation of protected_ike_sa_t.get_prf. */ -static prf_t *get_prf (private_ike_sa_t *this) +static prf_t *get_prf(private_ike_sa_t *this) { return this->prf; } @@ -486,7 +434,7 @@ static prf_t *get_prf (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.get_prf. */ -static prf_t *get_child_prf (private_ike_sa_t *this) +static prf_t *get_child_prf(private_ike_sa_t *this) { return this->child_prf; } @@ -494,7 +442,7 @@ static prf_t *get_child_prf (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.get_prf_auth_i. */ -static prf_t *get_prf_auth_i (private_ike_sa_t *this) +static prf_t *get_prf_auth_i(private_ike_sa_t *this) { return this->prf_auth_i; } @@ -502,7 +450,7 @@ static prf_t *get_prf_auth_i (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.get_prf_auth_r. */ -static prf_t *get_prf_auth_r (private_ike_sa_t *this) +static prf_t *get_prf_auth_r(private_ike_sa_t *this) { return this->prf_auth_r; } @@ -701,7 +649,7 @@ static status_t build_transforms(private_ike_sa_t *this, proposal_t *proposal, d /** * Implementation of protected_ike_sa_t.get_randomizer. */ -static randomizer_t *get_randomizer (private_ike_sa_t *this) +static randomizer_t *get_randomizer(private_ike_sa_t *this) { return this->randomizer; } @@ -709,7 +657,7 @@ static randomizer_t *get_randomizer (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.get_crypter_initiator. */ -static crypter_t *get_crypter_initiator (private_ike_sa_t *this) +static crypter_t *get_crypter_initiator(private_ike_sa_t *this) { return this->crypter_initiator; } @@ -717,7 +665,7 @@ static crypter_t *get_crypter_initiator (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.get_signer_initiator. */ -static signer_t *get_signer_initiator (private_ike_sa_t *this) +static signer_t *get_signer_initiator(private_ike_sa_t *this) { return this->signer_initiator; } @@ -733,7 +681,7 @@ static crypter_t *get_crypter_responder(private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.get_signer_responder. */ -static signer_t *get_signer_responder (private_ike_sa_t *this) +static signer_t *get_signer_responder(private_ike_sa_t *this) { return this->signer_responder; } @@ -741,7 +689,7 @@ static signer_t *get_signer_responder (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.send_request. */ -static status_t send_request (private_ike_sa_t *this,message_t * message) +static status_t send_request(private_ike_sa_t *this, message_t *message) { retransmit_request_job_t *retransmit_job; u_int32_t timeout; @@ -783,29 +731,25 @@ static status_t send_request (private_ike_sa_t *this,message_t * message) this->message_id_out); charon->send_queue->add(charon->send_queue, packet); + /* replace last message for retransmit with current */ if (this->last_requested_message != NULL) { - /* destroy message */ this->last_requested_message->destroy(this->last_requested_message); - } - + } this->logger->log(this->logger, CONTROL|LEVEL3, "Replace last requested message with new one"); this->last_requested_message = message; - retransmit_job = retransmit_request_job_create(this->message_id_out,this->ike_sa_id); - - status = charon->configuration->get_retransmit_timeout (charon->configuration, - retransmit_job->get_retransmit_count(retransmit_job),&timeout); - + /* schedule a job for retransmission */ + status = charon->configuration->get_retransmit_timeout(charon->configuration, 0, &timeout); if (status != SUCCESS) { this->logger->log(this->logger, CONTROL|LEVEL2, "No retransmit job for message created!"); - retransmit_job->destroy(retransmit_job); } else { - this->logger->log(this->logger, CONTROL|LEVEL2, "Request will be retransmitted in %d ms.",timeout); - charon->event_queue->add_relative(charon->event_queue,(job_t *) retransmit_job,timeout); + this->logger->log(this->logger, CONTROL|LEVEL2, "Request will be retransmitted in %d ms.", timeout); + retransmit_job = retransmit_request_job_create(this->message_id_out, this->ike_sa_id); + charon->event_queue->add_relative(charon->event_queue, (job_t *)retransmit_job, timeout); } /* message counter can now be increased */ @@ -819,7 +763,7 @@ static status_t send_request (private_ike_sa_t *this,message_t * message) /** * Implementation of protected_ike_sa_t.send_response. */ -static status_t send_response (private_ike_sa_t *this,message_t * message) +static status_t send_response(private_ike_sa_t *this, message_t *message) { crypter_t *crypter; signer_t *signer; @@ -832,7 +776,6 @@ static status_t send_response (private_ike_sa_t *this,message_t * message) return FAILED; } - if (this->ike_sa_id->is_initiator(this->ike_sa_id)) { crypter = this->crypter_initiator; @@ -922,7 +865,7 @@ static void set_last_replied_message_id (private_ike_sa_t *this,u_int32_t messag /** * Implementation of protected_ike_sa_t.get_last_responded_message. */ -static message_t * get_last_responded_message (private_ike_sa_t *this) +static message_t *get_last_responded_message (private_ike_sa_t *this) { return this->last_responded_message; } @@ -930,23 +873,15 @@ static message_t * get_last_responded_message (private_ike_sa_t *this) /** * Implementation of protected_ike_sa_t.get_last_requested_message. */ -static message_t * get_last_requested_message (private_ike_sa_t *this) +static message_t *get_last_requested_message(private_ike_sa_t *this) { return this->last_requested_message; } /** - * Implementation of ike_sa_t.get_state. - */ -static ike_sa_state_t get_state (private_ike_sa_t *this) -{ - return this->current_state->get_state(this->current_state); -} - -/** * Implementation of protected_ike_sa_t.add_child_sa. */ -static void add_child_sa (private_ike_sa_t *this, child_sa_t *child_sa) +static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa) { this->child_sas->insert_last(this->child_sas, child_sa); } @@ -954,7 +889,7 @@ static void add_child_sa (private_ike_sa_t *this, child_sa_t *child_sa) /** * Implementation of protected_ike_sa_t.reset_message_buffers. */ -static void reset_message_buffers (private_ike_sa_t *this) +static void reset_message_buffers(private_ike_sa_t *this) { this->logger->log(this->logger, CONTROL|LEVEL2, "Reset message counters and destroy stored messages"); /* destroy stored requested message */ @@ -983,6 +918,8 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name) { iterator_t *iterator; child_sa_t *child_sa; + host_t *my_host, *other_host; + identification_t *my_id, *other_id; /* only log if name == NULL or name == connection_name */ if (name) @@ -997,11 +934,11 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name) name = this->connection->get_name(this->connection); } - host_t *my_host = this->connection->get_my_host(this->connection); - host_t *other_host = this->connection->get_other_host(this->connection); + my_host = this->connection->get_my_host(this->connection); + other_host = this->connection->get_other_host(this->connection); - identification_t *my_id = this->connection->get_my_id(this->connection); - identification_t *other_id = this->connection->get_other_id(this->connection); + my_id = this->connection->get_my_id(this->connection); + other_id = this->connection->get_other_id(this->connection); if (logger == NULL) { @@ -1029,9 +966,52 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name) } /** + * Implementation of public_ike_sa_t.delete. + */ +static status_t delete_(private_ike_sa_t *this) +{ + message_t *informational_request; + delete_payload_t *delete_payload; + u_int32_t timeout; + delete_half_open_ike_sa_job_t *job; + + if (get_state(this) != IKE_SA_ESTABLISHED) + { + this->logger->log(this->logger, ERROR, "Closing a not established IKE SA not allowed, aborting!"); + return INVALID_STATE; + } + + build_message(this, INFORMATIONAL, TRUE, &informational_request); + /* delete for the full IKE_SA, this deletes all child_sa's implicit */ + delete_payload = delete_payload_create(); + delete_payload->set_protocol_id(delete_payload, PROTO_IKE); + + informational_request->add_payload(informational_request, (payload_t*)delete_payload); + + if (send_request(this, informational_request) != SUCCESS) + { + /* send failed, but we ignore this, SA will get deleted anyway later */ + informational_request->destroy(informational_request); + } + + /* transit to state delete_requested */ + this->current_state->destroy(this->current_state); + set_new_state(this, (state_t*)delete_requested_create(this)); + + /* there is no guarantee that the other peer will acknowledge the delete, + * so we have to set a timeout where we destroy the SA... This is done with + * the delete_half_open_ike_sa_job as used in IKE SA setup. + */ + timeout = charon->configuration->get_half_open_ike_sa_timeout(charon->configuration); + job = delete_half_open_ike_sa_job_create(this->ike_sa_id); + charon->event_queue->add_relative(charon->event_queue, (job_t*)job, timeout); + return SUCCESS; +} + +/** * Implementation of protected_ike_sa_t.destroy. */ -static void destroy (private_ike_sa_t *this) +static void destroy(private_ike_sa_t *this) { child_sa_t *child_sa; @@ -1039,9 +1019,12 @@ static void destroy (private_ike_sa_t *this) this->ike_sa_id->get_initiator_spi(this->ike_sa_id), this->ike_sa_id->get_responder_spi(this->ike_sa_id), this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder"); + + if (get_state(this) == IKE_SA_ESTABLISHED) + { + this->logger->log(this->logger, ERROR, "Destroying an established IKE SA without knowledge from remote peer!"); + } - /* inform other peer of delete */ - send_delete_ike_sa_request(this); while (this->child_sas->remove_last(this->child_sas, (void**)&child_sa) == SUCCESS) { child_sa->destroy(child_sa); @@ -1127,8 +1110,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->protected.public.get_connection = (connection_t*(*)(ike_sa_t*)) get_connection; this->protected.public.retransmit_request = (status_t (*) (ike_sa_t *, u_int32_t)) retransmit_request; this->protected.public.get_state = (ike_sa_state_t (*) (ike_sa_t *this)) get_state; - this->protected.public.send_delete_ike_sa_request = (void (*)(ike_sa_t*)) send_delete_ike_sa_request; this->protected.public.log_status = (void (*) (ike_sa_t*,logger_t*,char*))log_status; + this->protected.public.delete = (status_t(*)(ike_sa_t*))delete_; this->protected.public.destroy = (void(*)(ike_sa_t*))destroy; /* protected functions */ @@ -1158,9 +1141,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->protected.set_last_replied_message_id = (void (*) (protected_ike_sa_t *,u_int32_t)) set_last_replied_message_id; - /* private functions */ - this->resend_last_reply = resend_last_reply; - /* initialize private fields */ this->logger = logger_manager->get_logger(logger_manager, IKE_SA); diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index a4ab82cef..31a5ba8a1 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -73,7 +73,7 @@ struct ike_sa_t { * @return * - SUCCESS * - FAILED - * - DELETE_ME if this IKE_SA MUST be deleted + * - DESTROY_ME if this IKE_SA MUST be deleted */ status_t (*process_message) (ike_sa_t *this,message_t *message); @@ -88,7 +88,7 @@ struct ike_sa_t { * @return * - SUCCESS if initialization started * - FAILED if in wrong state - * - DELETE_ME if initialization failed and IKE_SA MUST be deleted + * - DESTROY_ME if initialization failed and IKE_SA MUST be deleted */ status_t (*initiate_connection) (ike_sa_t *this, connection_t *connection); @@ -102,15 +102,6 @@ struct ike_sa_t { * - NOT_FOUND if request doesn't have to be retransmited */ status_t (*retransmit_request) (ike_sa_t *this, u_int32_t message_id); - - /** - * @brief Sends a request to delete IKE_SA. - * - * Only supported in state IKE_SA_ESTABLISHED - * - * @param this calling object - */ - void (*send_delete_ike_sa_request) (ike_sa_t *this); /** * @brief Get the id of the SA. @@ -188,6 +179,22 @@ struct ike_sa_t { * @param name name of the connection */ void (*log_status) (ike_sa_t *this, logger_t *logger, char *name); + + /** + * @brief Initiates the deletion of an IKE_SA. + * + * Sends a delete message to the remote peer and waits for + * its response. If the response comes in, or a timeout occur, + * the IKE SA gets deleted. + * + * @param this calling object + * @return + * - SUCCESS if deletion is initialized + * - INVALID_STATE, if the IKE_SA is not in + * an established state and can not be + * delete (but destroyed). + */ + status_t (*delete) (ike_sa_t *this); /** * @brief Destroys a ike_sa_t object. diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index e6c8e4982..475898e26 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -137,7 +137,7 @@ struct private_ike_sa_manager_t { /** * @brief Get next spi. * - * We give out SPIs incremental starting at 1. + * We give out SPIs from a pseudo random source * * @param this the ike_sa_manager * @return the next spi @@ -232,7 +232,8 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) == ike_sa_id->get_initiator_spi(ike_sa_id)) && (ike_sa_id->is_initiator(ike_sa_id) == current->ike_sa_id->is_initiator(current->ike_sa_id))) { - this->logger->log(this->logger,CONTROL | LEVEL2,"Found entry by initiator spi %d",ike_sa_id->get_initiator_spi(ike_sa_id)); + this->logger->log(this->logger, CONTROL|LEVEL2, "Found entry by initiator spi %d", + ike_sa_id->get_initiator_spi(ike_sa_id)); *entry = current; status = SUCCESS; break; @@ -243,7 +244,8 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) == ike_sa_id->get_initiator_spi(ike_sa_id)) && (ike_sa_id->is_initiator(ike_sa_id) == current->ike_sa_id->is_initiator(current->ike_sa_id))) { - this->logger->log(this->logger,CONTROL | LEVEL2,"Found entry by initiator spi %d",ike_sa_id->get_initiator_spi(ike_sa_id)); + this->logger->log(this->logger, CONTROL|LEVEL2, "Found entry by initiator spi %d", + ike_sa_id->get_initiator_spi(ike_sa_id)); *entry = current; status = SUCCESS; break; @@ -251,7 +253,7 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike } if (current->ike_sa_id->equals(current->ike_sa_id, ike_sa_id)) { - this->logger->log(this->logger,CONTROL | LEVEL2,"Found entry by full ID"); + this->logger->log(this->logger, CONTROL|LEVEL2, "Found entry by full ID"); *entry = current; status = SUCCESS; break; @@ -283,7 +285,7 @@ static status_t get_entry_by_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa /* only pointers are compared */ if (current->ike_sa == ike_sa) { - this->logger->log(this->logger,CONTROL | LEVEL2,"Found entry by pointer"); + this->logger->log(this->logger, CONTROL|LEVEL2, "Found entry by pointer"); *entry = current; status = SUCCESS; break; @@ -305,7 +307,7 @@ static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *ent iterator = list->create_iterator(list, TRUE); - status = NOT_FOUND; + status = NOT_FOUND; while (iterator->has_next(iterator)) { @@ -313,7 +315,7 @@ static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *ent iterator->current(iterator, (void**)¤t); if (current == entry) { - this->logger->log(this->logger,CONTROL | LEVEL2,"Found entry by pointer. Going to delete it."); + this->logger->log(this->logger, CONTROL|LEVEL2, "Found entry by pointer. Going to delete it."); iterator->remove(iterator); entry->destroy(entry); status = SUCCESS; @@ -360,7 +362,7 @@ static void create_and_checkout(private_ike_sa_manager_t *this,ike_sa_t **ike_sa this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry); /* check ike_sa out */ - this->logger->log(this->logger,CONTROL | LEVEL1 ,"New IKE_SA created and added to list of known IKE_SA's"); + this->logger->log(this->logger, CONTROL|LEVEL1, "New IKE_SA created and added to list of known IKE_SA's"); new_ike_sa_entry->checked_out = TRUE; *ike_sa = new_ike_sa_entry->ike_sa; @@ -397,7 +399,7 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, /* can we give this ike_sa out to new requesters?*/ if (entry->driveout_new_threads) { - this->logger->log(this->logger,CONTROL|LEVEL1,"Drive out new thread for existing IKE_SA"); + this->logger->log(this->logger, CONTROL|LEVEL1, "Drive out new thread for existing IKE_SA"); /* no we can't */ retval = NOT_FOUND; } @@ -420,12 +422,12 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, { /* we must signal here, others are interested that we leave */ pthread_cond_signal(&(entry->condvar)); - this->logger->log(this->logger,CONTROL|LEVEL1,"Drive out waiting thread for existing IKE_SA"); + this->logger->log(this->logger, CONTROL|LEVEL1, "Drive out waiting thread for existing IKE_SA"); retval = NOT_FOUND; } else { - this->logger->log(this->logger,CONTROL|LEVEL2,"IKE SA successfully checked out"); + this->logger->log(this->logger, CONTROL|LEVEL2, "IKE SA successfully checked out"); /* ok, this IKE_SA is finally ours */ entry->checked_out = TRUE; *ike_sa = entry->ike_sa; @@ -436,7 +438,7 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, } else { - this->logger->log(this->logger,ERROR | LEVEL1,"IKE SA not stored in known IKE_SA list"); + this->logger->log(this->logger, ERROR|LEVEL1, "IKE SA not stored in known IKE_SA list"); /* looks like there is no such IKE_SA, better luck next time... */ /* DON'T use return, we must unlock the mutex! */ retval = NOT_FOUND; @@ -467,7 +469,7 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry); /* check ike_sa out */ - this->logger->log(this->logger,CONTROL | LEVEL1 ,"IKE_SA added to list of known IKE_SA's"); + this->logger->log(this->logger, CONTROL|LEVEL1 ,"IKE_SA added to list of known IKE_SA's"); new_ike_sa_entry->checked_out = TRUE; *ike_sa = new_ike_sa_entry->ike_sa; @@ -476,7 +478,7 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, else { /* responder set, initiator not: here is something seriously wrong! */ - this->logger->log(this->logger,ERROR | LEVEL1, "Invalid IKE_SA SPI's"); + this->logger->log(this->logger, ERROR|LEVEL1, "Invalid IKE_SA SPI's"); /* DON'T use return, we must unlock the mutex! */ retval = INVALID_ARG; } @@ -644,13 +646,13 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa)); /* signal waiting threads */ entry->checked_out = FALSE; - this->logger->log(this->logger,CONTROL | LEVEL1,"Checkin of IKE_SA successful."); + this->logger->log(this->logger, CONTROL|LEVEL1, "Checkin of IKE_SA successful."); pthread_cond_signal(&(entry->condvar)); retval = SUCCESS; } else { - this->logger->log(this->logger,ERROR,"Fatal Error: Tried to checkin nonexisting IKE_SA"); + this->logger->log(this->logger, ERROR, "Tried to checkin nonexisting IKE_SA"); /* this SA is no more, this REALLY should not happen */ retval = NOT_FOUND; } @@ -660,9 +662,9 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) /** - * Implementation of ike_sa_manager_t.checkin_and_delete. + * Implementation of ike_sa_manager_t.checkin_and_destroy. */ -static status_t checkin_and_delete(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) +static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) { /* deletion is a bit complex, we must garant that no thread is waiting for * this SA. @@ -682,21 +684,21 @@ static status_t checkin_and_delete(private_ike_sa_manager_t *this, ike_sa_t *ike entry->driveout_waiting_threads = TRUE; /* wait until all workers have done their work */ - while (entry->waiting_threads > 0) + while (entry->waiting_threads) { - /* let the other threads do some work*/ - pthread_cond_signal(&(entry->condvar)); + /* let the other threads leave the manager */ + pthread_cond_broadcast(&(entry->condvar)); /* and the nice thing, they will wake us again when their work is done */ pthread_cond_wait(&(entry->condvar), &(this->mutex)); } /* ok, we are alone now, no threads waiting in the entry's condvar */ this->delete_entry(this, entry); - this->logger->log(this->logger,CONTROL | LEVEL1,"Checkin and delete of IKE_SA successful"); + this->logger->log(this->logger, CONTROL|LEVEL1, "Checkin and destroy of IKE_SA successful"); retval = SUCCESS; } else { - this->logger->log(this->logger,ERROR,"Fatal Error: Tried to checkin and delete nonexisting IKE_SA"); + this->logger->log(this->logger,ERROR, "Tried to checkin and delete nonexisting IKE_SA"); retval = NOT_FOUND; } @@ -707,7 +709,7 @@ static status_t checkin_and_delete(private_ike_sa_manager_t *this, ike_sa_t *ike /** * Implementation of ike_sa_manager_t.delete. */ -static status_t delete(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id) +static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id) { /* deletion is a bit complex, we must garant that no thread is waiting for * this SA. @@ -721,25 +723,38 @@ static status_t delete(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id) if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS) { - /* mark it, so now new threads can acquire this SA */ - entry->driveout_new_threads = TRUE; - - /* wait until all workers have done their work */ - while (entry->waiting_threads) + /* we try a delete. If it succeeds, our job is done here. The + * other peer will reply, and the IKE SA gets the finally deleted... + */ + if (entry->ike_sa->delete(entry->ike_sa) == SUCCESS) { - /* wake up all */ - pthread_cond_signal(&(entry->condvar)); - /* and the nice thing, they will wake us again when their work is done */ - pthread_cond_wait(&(entry->condvar), &(this->mutex)); + this->logger->log(this->logger, CONTROL|LEVEL1, "Initiated delete for IKE_SA"); + } + /* but if the IKE SA is not in a state where the deletion is negotiated with + * the other peer, we can destroy the IKE SA on our own. For this, we must + * be sure that really NO other threads are waiting for this SA... + */ + else + { + /* mark it, so now new threads can acquire this SA */ + entry->driveout_new_threads = TRUE; + /* wait until all workers have done their work */ + while (entry->waiting_threads) + { + /* wake up all */ + pthread_cond_broadcast(&(entry->condvar)); + /* and the nice thing, they will wake us again when their work is done */ + pthread_cond_wait(&(entry->condvar), &(this->mutex)); + } + /* ok, we are alone now, no threads waiting in the entry's condvar */ + this->delete_entry(this, entry); + this->logger->log(this->logger, CONTROL|LEVEL1, "Destroyed IKE_SA"); } - /* ok, we are alone now, no threads waiting in the entry's condvar */ - this->delete_entry(this, entry); - this->logger->log(this->logger,CONTROL | LEVEL1,"Delete of IKE_SA successful"); retval = SUCCESS; } else { - this->logger->log(this->logger,ERROR,"Fatal Error: Tried to delete nonexisting IKE_SA"); + this->logger->log(this->logger,ERROR, "Tried to delete nonexisting IKE_SA"); retval = NOT_FOUND; } @@ -782,9 +797,9 @@ static void destroy(private_ike_sa_manager_t *this) while (entry->waiting_threads) { /* wake up all */ - pthread_cond_signal(&(entry->condvar)); + pthread_cond_broadcast(&(entry->condvar)); /* go sleeping until they are gone */ - pthread_cond_wait(&(entry->condvar), &(this->mutex)); + pthread_cond_wait(&(entry->condvar), &(this->mutex)); } } this->logger->log(this->logger,CONTROL | LEVEL2,"Delete all IKE_SA's"); @@ -821,8 +836,8 @@ ike_sa_manager_t *ike_sa_manager_create() this->public.get_ike_sa_list_by_name = (linked_list_t*(*)(ike_sa_manager_t*,const char*))get_ike_sa_list_by_name; this->public.log_status = (void(*)(ike_sa_manager_t*,logger_t*,char*))log_status; this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin; - this->public.delete = (status_t(*)(ike_sa_manager_t*,ike_sa_id_t*))delete; - this->public.checkin_and_delete = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_delete; + this->public.delete = (status_t(*)(ike_sa_manager_t*,ike_sa_id_t*))delete_; + this->public.checkin_and_destroy = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy; /* initialize private functions */ this->get_next_spi = get_next_spi; diff --git a/src/charon/sa/ike_sa_manager.h b/src/charon/sa/ike_sa_manager.h index d4cd749dc..a608052bd 100644 --- a/src/charon/sa/ike_sa_manager.h +++ b/src/charon/sa/ike_sa_manager.h @@ -149,10 +149,14 @@ struct ike_sa_manager_t { /** * @brief Delete a SA, which was not checked out. - * + * + * If the state allows it, the IKE SA is destroyed immediately. If it is + * in the state ike_sa_established or further, a delete message + * is sent to the remote peer, which has to be acknowledged. + * * @warning do not use this when the SA is already checked out, this will * deadlock! - * + * * @param this the manager object * @param ike_sa_id[in/out] the SA identifier * @returns @@ -162,7 +166,14 @@ struct ike_sa_manager_t { status_t (*delete) (ike_sa_manager_t* this, ike_sa_id_t *ike_sa_id); /** - * @brief Delete a checked out SA. + * @brief Destroy a checked out SA. + * + * The IKE SA is destroyed without notification of the remote peer. + * Use this only if the other peer doesn't respond or behaves not + * as predicted. + * Checking in and destruction is an atomic operation (for the IKE_SA), + * so this can be called if the SA is in a "unclean" state, without the + * risk that another thread can get the SA. * * @param this the manager object * @param ike_sa SA to delete @@ -170,7 +181,7 @@ struct ike_sa_manager_t { * - SUCCESS if found * - NOT_FOUND when no such SA is available */ - status_t (*checkin_and_delete) (ike_sa_manager_t* this, ike_sa_t *ike_sa); + status_t (*checkin_and_destroy) (ike_sa_manager_t* this, ike_sa_t *ike_sa); /** * @brief Destroys the manager with all associated SAs. diff --git a/src/charon/sa/states/delete_requested.c b/src/charon/sa/states/delete_requested.c new file mode 100644 index 000000000..ff6ec1d48 --- /dev/null +++ b/src/charon/sa/states/delete_requested.c @@ -0,0 +1,163 @@ +/** + * @file delete_requested.c + * + * @brief Implementation of delete_requested_t. + * + */ + +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "delete_requested.h" + +#include <daemon.h> + + +typedef struct private_delete_requested_t private_delete_requested_t; + +/** + * Private data of a delete_requested_t object. + */ +struct private_delete_requested_t { + + /** + * methods of the state_t interface + */ + delete_requested_t public; + + /** + * Assigned IKE_SA. + */ + protected_ike_sa_t *ike_sa; + + /** + * Assigned logger. Use logger of IKE_SA. + */ + logger_t *logger; +}; + +/** + * Implements state_t.get_state + */ +static status_t process_message(private_delete_requested_t *this, message_t *message) +{ + ike_sa_id_t *ike_sa_id; + crypter_t *crypter; + signer_t *signer; + status_t status; + + /* Notation as follows: + * Mx{D} means: Message, with message ID "x", containing a Delete payload + * + * The clarifcation Document says in 5.8, that a IKE_SA delete should not + * be acknowledged with the same delete. This only makes sense for CHILD_SAs, + * as they are paired. IKE_SAs are not, there is only one for both ends. + * + * Normal case: + * ---------------- + * Mx{D} --> + * <-- Mx{} + * Delete request is sent, and we wait for the acknowledge. + * + * Special case 1: + * --------------- + * Mx{D} --> + * <-- My{D} + * My{} --> + * <-- Mx{} + * Both initate a delete at the same time. We ack the delete, but wait for + * our delete to be acknowledged. + */ + + if (message->get_exchange_type(message) != INFORMATIONAL) + { + /* anything other than information is ignored. We can an will not handle + * messages such as CREATE_CHILD_SA */ + this->logger->log(this->logger, ERROR | LEVEL1, + "%s messages not supported in state delete_requested. Ignored", + mapping_find(exchange_type_m, message->get_exchange_type(message))); + return FAILED; + } + + if (message->get_request(message)) + { + /* if it is a request, not a reply to our delete request, we + * just acknowledge this. We stay in our state, as the other peer + * has to ACK our request. + */ + message_t *acknowledge; + this->ike_sa->build_message(this->ike_sa, INFORMATIONAL, FALSE, &acknowledge); + return this->ike_sa->send_response(this->ike_sa, acknowledge); + } + + /* get signer for verification and crypter for decryption */ + ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public)); + if (!ike_sa_id->is_initiator(ike_sa_id)) + { + crypter = this->ike_sa->get_crypter_initiator(this->ike_sa); + signer = this->ike_sa->get_signer_initiator(this->ike_sa); + } + else + { + crypter = this->ike_sa->get_crypter_responder(this->ike_sa); + signer = this->ike_sa->get_signer_responder(this->ike_sa); + } + + /* parse incoming message, check if it's proper signed */ + status = message->parse_body(message, crypter, signer); + if (status != SUCCESS) + { + this->logger->log(this->logger, AUDIT, "INFORMATIONAL message decryption failed. Ignoring message"); + return status; + } + + /* ok, he knows about the deletion, destroy this IKE SA */ + return DESTROY_ME; +} + +/** + * Implementation of state_t.get_state. + */ +static ike_sa_state_t get_state(private_delete_requested_t *this) +{ + return DELETE_REQUESTED; +} + +/** + * Implementation of state_t.get_state + */ +static void destroy(private_delete_requested_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +delete_requested_t *delete_requested_create(protected_ike_sa_t *ike_sa) +{ + private_delete_requested_t *this = malloc_thing(private_delete_requested_t); + + /* interface functions */ + this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message; + this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state; + this->public.state_interface.destroy = (void (*) (state_t *)) destroy; + + /* private data */ + this->ike_sa = ike_sa; + this->logger = logger_manager->get_logger(logger_manager, IKE_SA); + + return &(this->public); +} diff --git a/src/charon/sa/states/delete_requested.h b/src/charon/sa/states/delete_requested.h new file mode 100644 index 000000000..a4c6daba0 --- /dev/null +++ b/src/charon/sa/states/delete_requested.h @@ -0,0 +1,57 @@ +/** + * @file delete_requested.h + * + * @brief Interface of delete_requested_t. + * + */ + +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef DELETE_REQUESTED_H_ +#define DELETE_REQUESTED_H_ + +#include <sa/states/state.h> +#include <sa/ike_sa.h> + +typedef struct delete_requested_t delete_requested_t; + +/** + * @brief This class represents an the state of a half closed IKE_SA. + * + * @b Constructors: + * - delete_requested_create() + * + * @ingroup states + */ +struct delete_requested_t { + /** + * methods of the state_t interface + */ + state_t state_interface; + +}; + +/** + * @brief Constructor of class delete_requested_t + * + * @param ike_sa assigned ike_sa + * @return created delete_requested_t object + * + * @ingroup states + */ +delete_requested_t *delete_requested_create(protected_ike_sa_t *ike_sa); + +#endif /*DELETE_REQUESTED_H_*/ diff --git a/src/charon/sa/states/ike_auth_requested.c b/src/charon/sa/states/ike_auth_requested.c index 3d49f440f..069f16506 100644 --- a/src/charon/sa/states/ike_auth_requested.c +++ b/src/charon/sa/states/ike_auth_requested.c @@ -107,7 +107,7 @@ struct private_ike_auth_requested_t { * @param idr_payload ID payload of responder * @return * - SUCCESS - * - DELETE_ME + * - DESTROY_ME */ status_t (*process_idr_payload) (private_ike_auth_requested_t *this, id_payload_t *idr_payload); @@ -118,7 +118,7 @@ struct private_ike_auth_requested_t { * @param sa_payload SA payload of responder * * - SUCCESS - * - DELETE_ME + * - DESTROY_ME */ status_t (*process_sa_payload) (private_ike_auth_requested_t *this, sa_payload_t *sa_payload); @@ -130,7 +130,7 @@ struct private_ike_auth_requested_t { * @param other_id_payload ID payload of responder * * - SUCCESS - * - DELETE_ME + * - DESTROY_ME */ status_t (*process_auth_payload) (private_ike_auth_requested_t *this, auth_payload_t *auth_payload, id_payload_t *other_id_payload); @@ -142,7 +142,7 @@ struct private_ike_auth_requested_t { * @param ts_payload TS payload of responder * * - SUCCESS - * - DELETE_ME + * - DESTROY_ME */ status_t (*process_ts_payload) (private_ike_auth_requested_t *this, bool ts_initiator, ts_payload_t *ts_payload); @@ -154,7 +154,7 @@ struct private_ike_auth_requested_t { * * - SUCCESS * - FAILED - * - DELETE_ME + * - DESTROY_ME */ status_t (*process_notify_payload) (private_ike_auth_requested_t *this, notify_payload_t *notify_payload); @@ -281,7 +281,7 @@ static status_t process_message(private_ike_auth_requested_t *this, message_t *i if (!(idr_payload && sa_payload && auth_payload && tsi_payload && tsr_payload)) { this->logger->log(this->logger, AUDIT, "IKE_AUTH reply did not contain all required payloads. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } /* process all payloads */ @@ -341,13 +341,13 @@ static status_t process_message(private_ike_auth_requested_t *this, message_t *i if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } status = this->child_sa->add_policies(this->child_sa, this->my_ts, this->other_ts); if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA policy! Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } this->ike_sa->add_child_sa(this->ike_sa, this->child_sa); } @@ -386,7 +386,7 @@ static status_t process_idr_payload(private_ike_auth_requested_t *this, id_paylo { other_id->destroy(other_id); this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a not acceptable ID. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } connection = this->ike_sa->get_connection(this->ike_sa); @@ -424,7 +424,7 @@ static status_t process_sa_payload(private_ike_auth_requested_t *this, sa_payloa proposal->destroy(proposal); } proposal_list->destroy(proposal_list); - return DELETE_ME; + return DESTROY_ME; } /* we have to re-check here if other's selection is valid */ @@ -439,7 +439,7 @@ static status_t process_sa_payload(private_ike_auth_requested_t *this, sa_payloa if (proposal == NULL) { this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a not offered proposal. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } /* apply proposal */ @@ -462,7 +462,7 @@ static status_t process_auth_payload(private_ike_auth_requested_t *this, auth_pa if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Verification of IKE_AUTH reply failed. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } this->logger->log(this->logger, CONTROL|LEVEL1, "AUTH data verified successfully"); @@ -521,19 +521,19 @@ static status_t process_notify_payload(private_ike_auth_requested_t *this, notif case INVALID_SYNTAX: { this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained an INVALID_SYNTAX notify. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } case AUTHENTICATION_FAILED: { this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained an AUTHENTICATION_FAILED notify. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } case SINGLE_PAIR_REQUIRED: { this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a SINGLE_PAIR_REQUIRED notify. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } default: { @@ -546,7 +546,7 @@ static status_t process_notify_payload(private_ike_auth_requested_t *this, notif { this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained an unknown notify error (%d). Deleting IKE_SA", notify_message_type); - return DELETE_ME; + return DESTROY_ME; } else diff --git a/src/charon/sa/states/ike_sa_established.c b/src/charon/sa/states/ike_sa_established.c index e91409f6a..782b608dc 100644 --- a/src/charon/sa/states/ike_sa_established.c +++ b/src/charon/sa/states/ike_sa_established.c @@ -46,22 +46,59 @@ struct private_ike_sa_established_t { * Assigned logger. Use logger of IKE_SA. */ logger_t *logger; - - /** - * Process a notify payload - * - * @param this calling object - * @param notify_payload notify payload - * @param response response message of type INFORMATIONAL - * - * - SUCCESS - * - FAILED - * - DELETE_ME - */ - status_t (*process_notify_payload) (private_ike_sa_established_t *this, notify_payload_t *notify_payload,message_t *response); }; /** + * Process an informational request + */ +static status_t process_informational(private_ike_sa_established_t *this, message_t *request, message_t *response) +{ + delete_payload_t *delete_request = NULL; + iterator_t *payloads = request->get_payload_iterator(request); + + while (payloads->has_next(payloads)) + { + payload_t *payload; + payloads->current(payloads, (void**)&payload); + + switch (payload->get_type(payload)) + { + case DELETE: + { + delete_request = (delete_payload_t *) payload; + break; + } + default: + { + this->logger->log(this->logger, ERROR|LEVEL1, "Ignoring Payload %s (%d)", + mapping_find(payload_type_m, payload->get_type(payload)), + payload->get_type(payload)); + break; + } + } + } + /* iterator can be destroyed */ + payloads->destroy(payloads); + + if (delete_request) + { + if (delete_request->get_protocol_id(delete_request) == PROTO_IKE) + { + this->logger->log(this->logger, CONTROL, "DELETE request for IKE_SA received"); + /* we reply with an empty informational message */ + return DESTROY_ME; + } + else + { + this->logger->log(this->logger, CONTROL, "DELETE request for CHILD_SA received. Ignored"); + response->destroy(response); + return SUCCESS; + } + } + return SUCCESS; +} + +/** * Implements state_t.get_state */ static status_t process_message(private_ike_sa_established_t *this, message_t *message) @@ -74,22 +111,16 @@ static status_t process_message(private_ike_sa_established_t *this, message_t *m signer_t *signer; status_t status; - if (message->get_exchange_type(message) != INFORMATIONAL) - { - this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state ike_sa_established", - mapping_find(exchange_type_m,message->get_exchange_type(message))); - return FAILED; - } - + /* only requests are allowed, responses are handled in sub-states */ if (!message->get_request(message)) { - this->logger->log(this->logger, ERROR | LEVEL1, "INFORMATIONAL responses not handled in state ike_sa_established"); + this->logger->log(this->logger, ERROR | LEVEL1, + "INFORMATIONAL responses not handled in state ike_sa_established"); return FAILED; } - ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public)); - /* get signer for verification and crypter for decryption */ + ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public)); if (!ike_sa_id->is_initiator(ike_sa_id)) { crypter = this->ike_sa->get_crypter_initiator(this->ike_sa); @@ -105,99 +136,50 @@ static status_t process_message(private_ike_sa_established_t *this, message_t *m status = message->parse_body(message, crypter, signer); if (status != SUCCESS) { - this->logger->log(this->logger, AUDIT, "INFORMATIONAL request decryption failed. Ignoring message"); + this->logger->log(this->logger, AUDIT, "%s request decryption failed. Ignoring message", + mapping_find(exchange_type_m, message->get_exchange_type(message))); return status; } - /* build empty INFORMATIONAL message */ - this->ike_sa->build_message(this->ike_sa, INFORMATIONAL, FALSE, &response); - - payloads = message->get_payload_iterator(message); + /* prepare a reply of the same type */ + this->ike_sa->build_message(this->ike_sa, message->get_exchange_type(message), FALSE, &response); - while (payloads->has_next(payloads)) + /* handle the different message types in their functions */ + switch (message->get_exchange_type(message)) { - payload_t *payload; - payloads->current(payloads, (void**)&payload); - - switch (payload->get_type(payload)) - { - case NOTIFY: - { - notify_payload_t *notify_payload = (notify_payload_t *) payload; - /* handle the notify directly, abort if no further processing required */ - status = this->process_notify_payload(this, notify_payload,response); - if (status != SUCCESS) - { - payloads->destroy(payloads); - response->destroy(response); - return status; - } - } - case DELETE: - { - delete_request = (delete_payload_t *) payload; - break; - } - default: - { - this->logger->log(this->logger, ERROR|LEVEL1, "Ignoring Payload %s (%d)", - mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload)); - break; - } - } + case INFORMATIONAL: + status = process_informational(this, message, response); + break; + default: + this->logger->log(this->logger, ERROR | LEVEL1, + "Message of type %s currently not supported in state ike_sa_established", + mapping_find(exchange_type_m, message->get_exchange_type(message))); + status = NOT_SUPPORTED; } - /* iterator can be destroyed */ - payloads->destroy(payloads); - if (delete_request) - { - if (delete_request->get_protocol_id(delete_request) == PROTO_IKE) + /* if we get a DESTROY_ME, we respond to follow strict request/reply scheme */ + if (status == SUCCESS || status == DESTROY_ME) + { + if (this->ike_sa->send_response(this->ike_sa, response) != SUCCESS) { - this->logger->log(this->logger, AUDIT, "DELETE request for IKE_SA received"); + /* something is seriously wrong, kill connection */ + this->logger->log(this->logger, AUDIT, "Unable to send reply. Deleting IKE_SA"); response->destroy(response); - return DELETE_ME; + status = DESTROY_ME; } - else + else if (status == DESTROY_ME) { - this->logger->log(this->logger, AUDIT, "DELETE request for CHILD_SA received. Ignored"); - response->destroy(response); - return SUCCESS; + /* switch to delete_requested. This is not absolutly correct, but we + * allow the clean destruction of an SA only in this state. */ + this->ike_sa->set_new_state(this->ike_sa, (state_t*)delete_requested_create(this)); + this->public.state_interface.destroy(&(this->public.state_interface)); } } - - status = this->ike_sa->send_response(this->ike_sa, response); - /* message can now be sent (must not be destroyed) */ - if (status != SUCCESS) + else { - this->logger->log(this->logger, AUDIT, "Unable to send INFORMATIONAL reply"); response->destroy(response); - return FAILED; } - - return SUCCESS; -} - -/** - * Implementation of private_ike_sa_established_t.process_notify_payload; - */ -static status_t process_notify_payload (private_ike_sa_established_t *this, notify_payload_t *notify_payload, message_t *response) -{ - notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload); - - this->logger->log(this->logger, CONTROL|LEVEL1, "Process notify type %s for protocol %s", - mapping_find(notify_message_type_m, notify_message_type), - mapping_find(protocol_id_m, notify_payload->get_protocol_id(notify_payload))); - - switch (notify_message_type) - { - default: - { - this->logger->log(this->logger, AUDIT, "INFORMATIONAL request contained an unknown notify (%d), ignored.", notify_message_type); - } - } - - - return SUCCESS; + return status; } /** @@ -228,9 +210,6 @@ ike_sa_established_t *ike_sa_established_create(protected_ike_sa_t *ike_sa) this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state; this->public.state_interface.destroy = (void (*) (state_t *)) destroy; - /* private functions */ - this->process_notify_payload = process_notify_payload; - /* private data */ this->ike_sa = ike_sa; this->logger = logger_manager->get_logger(logger_manager, IKE_SA); diff --git a/src/charon/sa/states/ike_sa_init_requested.c b/src/charon/sa/states/ike_sa_init_requested.c index 04fef3d94..6befa96e6 100644 --- a/src/charon/sa/states/ike_sa_init_requested.c +++ b/src/charon/sa/states/ike_sa_init_requested.c @@ -325,7 +325,7 @@ static status_t process_message(private_ike_sa_init_requested_t *this, message_t if (!(nonce_payload && sa_payload && ke_payload)) { this->logger->log(this->logger, AUDIT, "IKE_SA_INIT reply did not contain all required payloads. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } status = this->process_nonce_payload (this,nonce_payload); @@ -351,7 +351,7 @@ static status_t process_message(private_ike_sa_init_requested_t *this, message_t if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Transform objects could not be created from selected proposal. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } /* apply the address on wich we really received the packet */ @@ -407,7 +407,7 @@ static status_t process_message(private_ike_sa_init_requested_t *this, message_t { this->logger->log(this->logger, AUDIT, "Unable to send IKE_AUTH request. Deleting IKE_SA"); request->destroy(request); - return DELETE_ME; + return DESTROY_ME; } this->ike_sa->set_last_replied_message_id(this->ike_sa,ike_sa_init_reply->get_message_id(ike_sa_init_reply)); @@ -456,7 +456,7 @@ status_t process_sa_payload (private_ike_sa_init_requested_t *this, sa_payload_t proposal->destroy(proposal); } proposal_list->destroy(proposal_list); - return DELETE_ME; + return DESTROY_ME; } /* we have to re-check if the others selection is valid */ @@ -470,7 +470,7 @@ status_t process_sa_payload (private_ike_sa_init_requested_t *this, sa_payload_t if (this->proposal == NULL) { this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response contained selected proposal we did not offer. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } return SUCCESS; @@ -544,7 +544,7 @@ static status_t build_auth_payload (private_ike_sa_init_requested_t *this, id_pa if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Could not generate AUTH data for IKE_AUTH request. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } this->logger->log(this->logger, CONTROL|LEVEL2, "Add AUTH payload to message"); @@ -573,7 +573,7 @@ static status_t build_sa_payload (private_ike_sa_init_requested_t *this, message if (this->child_sa->alloc(this->child_sa, proposal_list) != SUCCESS) { this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } sa_payload = sa_payload_create_from_proposal_list(proposal_list); @@ -637,12 +637,12 @@ static status_t process_notify_payload(private_ike_sa_init_requested_t *this, no case NO_PROPOSAL_CHOSEN: { this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response contained a NO_PROPOSAL_CHOSEN notify. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } case INVALID_MAJOR_VERSION: { this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response contained a INVALID_MAJOR_VERSION notify. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } case INVALID_KE_PAYLOAD: { @@ -671,7 +671,7 @@ static status_t process_notify_payload(private_ike_sa_init_requested_t *this, no this->logger->log(this->logger, AUDIT, "Peer does only accept DH group %s, which we do not accept! Aborting", mapping_find(diffie_hellman_group_m, dh_group)); - return DELETE_ME; + return DESTROY_ME; } /* Going to change state back to initiator_init_t */ @@ -691,7 +691,7 @@ static status_t process_notify_payload(private_ike_sa_init_requested_t *this, no this->public.state_interface.destroy(&(this->public.state_interface)); if (initiator_init_state->retry_initiate_connection (initiator_init_state, dh_group) != SUCCESS) { - return DELETE_ME; + return DESTROY_ME; } return FAILED; } @@ -705,7 +705,7 @@ static status_t process_notify_payload(private_ike_sa_init_requested_t *this, no { this->logger->log(this->logger, AUDIT, "IKE_SA_INIT reply contained an unknown notify error (%d). Deleting IKE_SA", notify_message_type); - return DELETE_ME; + return DESTROY_ME; } else { diff --git a/src/charon/sa/states/ike_sa_init_responded.c b/src/charon/sa/states/ike_sa_init_responded.c index 84187f027..3a379247c 100644 --- a/src/charon/sa/states/ike_sa_init_responded.c +++ b/src/charon/sa/states/ike_sa_init_responded.c @@ -152,7 +152,7 @@ struct private_ike_sa_init_responded_t { * @param this calling object * @param notify_payload payload to process * @return - * - DELETE_ME if IKE_SA should be deleted + * - DESTROY_ME if IKE_SA should be deleted * - SUCCSS if processed successfull */ status_t (*process_notify_payload) (private_ike_sa_init_responded_t *this, notify_payload_t* notify_payload); @@ -210,7 +210,7 @@ static status_t process_message(private_ike_sa_init_responded_t *this, message_t this->logger->log(this->logger, ERROR | LEVEL1, "IKE_AUTH request contains unsupported payload with critical flag set. " "Deleting IKE_SA"); this->ike_sa->send_notify(this->ike_sa, IKE_AUTH, UNSUPPORTED_CRITICAL_PAYLOAD, CHUNK_INITIALIZER); - return DELETE_ME; + return DESTROY_ME; } else { @@ -291,7 +291,7 @@ static status_t process_message(private_ike_sa_init_responded_t *this, message_t if (!(idi_request && sa_request && auth_request && tsi_request && tsr_request)) { this->logger->log(this->logger, AUDIT, "IKE_AUTH reply did not contain all required payloads. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } /* build response */ @@ -335,7 +335,7 @@ static status_t process_message(private_ike_sa_init_responded_t *this, message_t { this->logger->log(this->logger, AUDIT, "Unable to send IKE_AUTH reply. Deleting IKE_SA"); response->destroy(response); - return DELETE_ME; + return DESTROY_ME; } /* install child SA policies */ @@ -355,12 +355,12 @@ static status_t process_message(private_ike_sa_init_responded_t *this, message_t if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA policy! Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } this->ike_sa->add_child_sa(this->ike_sa, this->child_sa); } - /* create new state */ + /* create new state */ this->ike_sa->set_new_state(this->ike_sa, (state_t*)ike_sa_established_create(this->ike_sa)); this->destroy_after_state_change(this); @@ -403,7 +403,7 @@ static status_t build_idr_payload(private_ike_sa_init_responded_t *this, id_payl { this->logger->log(this->logger, AUDIT, "We don't have a policy for IDs %s - %s. Deleting IKE_SA", my_id->get_string(my_id), other_id->get_string(other_id)); - return DELETE_ME; + return DESTROY_ME; } /* get my id from policy, which must contain a fully qualified valid id */ @@ -462,7 +462,7 @@ static status_t build_sa_payload(private_ike_sa_init_responded_t *this, sa_paylo { this->logger->log(this->logger, AUDIT, "IKE_AUTH request did not contain any proposals we accept. Deleting IKE_SA"); this->ike_sa->send_notify(this->ike_sa, IKE_AUTH, NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER); - return DELETE_ME; + return DESTROY_ME; } /* set up child sa */ @@ -481,7 +481,7 @@ static status_t build_sa_payload(private_ike_sa_init_responded_t *this, sa_paylo if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } /* create payload with selected propsal */ @@ -508,7 +508,7 @@ static status_t build_auth_payload(private_ike_sa_init_responded_t *this, auth_p this->logger->log(this->logger, AUDIT, "IKE_AUTH request verification failed. Deleting IKE_SA"); this->ike_sa->send_notify(this->ike_sa, IKE_AUTH, AUTHENTICATION_FAILED, CHUNK_INITIALIZER); authenticator->destroy(authenticator); - return DELETE_ME; + return DESTROY_ME; } status = authenticator->compute_auth_data(authenticator,&auth_reply, this->ike_sa_init_response_data,this->received_nonce,my_id_payload,FALSE); @@ -516,8 +516,7 @@ static status_t build_auth_payload(private_ike_sa_init_responded_t *this, auth_p if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Unable to build authentication data for IKE_AUTH reply. Deleting IKE_SA"); - return DELETE_ME; - + return DESTROY_ME; } response->add_payload(response, (payload_t *)auth_reply); diff --git a/src/charon/sa/states/initiator_init.c b/src/charon/sa/states/initiator_init.c index 35d15235d..9636d8f66 100644 --- a/src/charon/sa/states/initiator_init.c +++ b/src/charon/sa/states/initiator_init.c @@ -131,7 +131,7 @@ static status_t initiate_connection (private_initiator_init_t *this, connection_ { this->logger->log(this->logger, ERROR | LEVEL1, "Could not get a policy for '%s - %s', aborting", my_id->get_string(my_id), other_id->get_string(other_id)); - return DELETE_ME; + return DESTROY_ME; } this->ike_sa->set_policy(this->ike_sa,policy); @@ -157,7 +157,7 @@ status_t retry_initiate_connection (private_initiator_init_t *this, diffie_hellm if (dh_group == MODP_UNDEFINED) { this->logger->log(this->logger, AUDIT, "No DH group acceptable for initialization, Aborting"); - return DELETE_ME; + return DESTROY_ME; } connection = this->ike_sa->get_connection(this->ike_sa); @@ -181,7 +181,7 @@ status_t retry_initiate_connection (private_initiator_init_t *this, diffie_hellm { this->logger->log(this->logger, ERROR, "Building nonce payload failed. Aborting"); message->destroy(message); - return DELETE_ME; + return DESTROY_ME; } /* message can now be sent (must not be destroyed) */ @@ -190,7 +190,7 @@ status_t retry_initiate_connection (private_initiator_init_t *this, diffie_hellm { this->logger->log(this->logger, AUDIT, "Unable to initiate connection, could not send message. Aborting"); message->destroy(message); - return DELETE_ME; + return DESTROY_ME; } message = this->ike_sa->get_last_requested_message(this->ike_sa); diff --git a/src/charon/sa/states/initiator_init.h b/src/charon/sa/states/initiator_init.h index 6b4940a73..903c58038 100644 --- a/src/charon/sa/states/initiator_init.h +++ b/src/charon/sa/states/initiator_init.h @@ -52,7 +52,7 @@ struct initiator_init_t { * @param connection connection to initiate * @return * - SUCCESS - * - DELETE_ME if something failed + * - DESTROY_ME if something failed */ status_t (*initiate_connection) (initiator_init_t *this, connection_t *connection); @@ -65,7 +65,7 @@ struct initiator_init_t { * @param dh_group_priority dh group priority to try with * @return * - SUCCESS - * - DELETE_ME if something failed (see log for error) + * - DESTROY_ME if something failed (see log for error) */ status_t (*retry_initiate_connection) (initiator_init_t *this, int dh_group_priority); }; diff --git a/src/charon/sa/states/responder_init.c b/src/charon/sa/states/responder_init.c index 10acf645c..8ee77269d 100644 --- a/src/charon/sa/states/responder_init.c +++ b/src/charon/sa/states/responder_init.c @@ -97,7 +97,7 @@ struct private_responder_init_t { * @param sa_request The received SA payload * @param response the SA payload is added to this response message_t object. * @return - * - DELETE_ME + * - DESTROY_ME * - SUCCESS */ status_t (*build_sa_payload) (private_responder_init_t *this,sa_payload_t *sa_request, message_t *response); @@ -108,7 +108,7 @@ struct private_responder_init_t { * @param this calling object * @param ke_request The received KE payload * @param response the KE payload is added to this response message_t object. - * - DELETE_ME + * - DESTROY_ME * - SUCCESS */ status_t (*build_ke_payload) (private_responder_init_t *this,ke_payload_t *ke_request, message_t *response); @@ -119,7 +119,7 @@ struct private_responder_init_t { * @param this calling object * @param nonce_request The received NONCE payload * @param response the NONCE payload is added to this response message_t object. - * - DELETE_ME + * - DESTROY_ME * - SUCCESS */ status_t (*build_nonce_payload) (private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *response); @@ -164,12 +164,12 @@ static status_t process_message(private_responder_init_t *this, message_t *messa if (message->get_exchange_type(message) != IKE_SA_INIT) { this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state responder_init",mapping_find(exchange_type_m,message->get_exchange_type(message))); - return DELETE_ME; + return DESTROY_ME; } if (!message->get_request(message)) { this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT responses not allowed state ike_sa_init_responded"); - return DELETE_ME; + return DESTROY_ME; } /* this is the first message to process, so get host infos */ @@ -182,7 +182,7 @@ static status_t process_message(private_responder_init_t *this, message_t *messa /* no configuration matches given hosts */ this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request does not match any available connection. Deleting IKE_SA"); /* TODO: inform requestor */ - return DELETE_ME; + return DESTROY_ME; } this->ike_sa->set_connection(this->ike_sa,connection); @@ -200,7 +200,7 @@ static status_t process_message(private_responder_init_t *this, message_t *messa { this->logger->log(this->logger, AUDIT, "Unable to parse IKE_SA_INIT request. Deleting IKE_SA"); } - return DELETE_ME; + return DESTROY_ME; } payloads = message->get_payload_iterator(message); @@ -251,7 +251,7 @@ static status_t process_message(private_responder_init_t *this, message_t *messa if (!(sa_request && ke_request && nonce_request)) { this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain all required payloads. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, FALSE, &response); @@ -282,7 +282,7 @@ static status_t process_message(private_responder_init_t *this, message_t *messa if (status != SUCCESS) { this->logger->log(this->logger, AUDIT, "Transform objects could not be created from selected proposal. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } /* message can now be sent (must not be destroyed) */ @@ -291,7 +291,7 @@ static status_t process_message(private_responder_init_t *this, message_t *messa { this->logger->log(this->logger, AUDIT, "Unable to send IKE_SA_INIT response. Deleting IKE_SA"); response->destroy(response); - return DELETE_ME; + return DESTROY_ME; } /* state can now be changed */ @@ -340,7 +340,7 @@ static status_t build_sa_payload(private_responder_init_t *this,sa_payload_t *sa { this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain any acceptable proposals. Deleting IKE_SA"); this->ike_sa->send_notify(this->ike_sa, IKE_SA_INIT, NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER); - return DELETE_ME; + return DESTROY_ME; } /* get selected DH group to force policy, this is very restrictive!? */ this->proposal->get_algorithm(this->proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, &algo); @@ -372,7 +372,7 @@ static status_t build_ke_payload(private_responder_init_t *this,ke_payload_t *ke if (group == MODP_UNDEFINED) { this->logger->log(this->logger, AUDIT, "No diffie hellman group to select. Deleting IKE_SA"); - return DELETE_ME; + return DESTROY_ME; } if (this->dh_group_number != group) @@ -387,7 +387,7 @@ static status_t build_ke_payload(private_responder_init_t *this,ke_payload_t *ke accepted_group_chunk.ptr = (u_int8_t*) &(accepted_group); accepted_group_chunk.len = 2; this->ike_sa->send_notify(this->ike_sa,IKE_SA_INIT,INVALID_KE_PAYLOAD,accepted_group_chunk); - return DELETE_ME; + return DESTROY_ME; } /* create diffie hellman object to handle DH exchange */ @@ -396,7 +396,7 @@ static status_t build_ke_payload(private_responder_init_t *this,ke_payload_t *ke { this->logger->log(this->logger, AUDIT, "Could not generate DH object with group %d. Deleting IKE_SA", mapping_find(diffie_hellman_group_m,group) ); - return DELETE_ME; + return DESTROY_ME; } this->logger->log(this->logger, CONTROL | LEVEL2, "Set other DH public value"); diff --git a/src/charon/sa/states/state.c b/src/charon/sa/states/state.c index 595f5abbb..eda29870b 100644 --- a/src/charon/sa/states/state.c +++ b/src/charon/sa/states/state.c @@ -33,5 +33,6 @@ mapping_t ike_sa_state_m[] = { {IKE_SA_INIT_RESPONDED, "IKE_SA_INIT_RESPONDED"}, {IKE_AUTH_REQUESTED, "IKE_AUTH_REQUESTED"}, {IKE_SA_ESTABLISHED, "IKE_SA_ESTABLISHED"}, + {DELETE_REQUESTED, "DELETE_REQUESTED"}, {MAPPING_END, NULL} }; diff --git a/src/charon/sa/states/state.h b/src/charon/sa/states/state.h index c93068d35..0f39aec01 100644 --- a/src/charon/sa/states/state.h +++ b/src/charon/sa/states/state.h @@ -90,9 +90,20 @@ enum ike_sa_state_t { * * In this state, all the informations for an IKE_SA and one CHILD_SA are known. * - * Implemented in class ike_sa_established_t. + * Implemented in class ike_sa_established_t. */ - IKE_SA_ESTABLISHED = 6 + IKE_SA_ESTABLISHED = 6, + + /** + * @brief An IKE SA has sent a DELETE IKE_SA to the other peer. + * + * After a call to ike_sa.close(), the IKE_SA sends a delete message + * to the remote peer and switches to this state. It waits until the + * message is aknowledged, or a certain timout occurs. + * + * Implemented in class delete_requested. + */ + DELETE_REQUESTED = 7 }; @@ -122,6 +133,7 @@ typedef struct state_t state_t; * - IKE_SA_INIT_RESPONDED: implemented in ike_sa_init_responded_t * - IKE_AUTH_REQUESTED: implemented in ike_auth_requested_t * - IKE_SA_ESTABLISHED: implemented in ike_sa_established_t + * - DELETE_REQUESTED: implemented in delete_requested_t * * @b Constructors: * - initiator_init_create() @@ -130,6 +142,7 @@ typedef struct state_t state_t; * - ike_sa_init_responded_create() * - ike_auth_requested_create() * - ike_sa_established_create() + * - delete_requested_create() * * @ingroup states */ @@ -143,7 +156,7 @@ struct state_t { * @return * - SUCCESSFUL * - FAILED - * - DELETE_ME if belonging IKE_SA should be deleted + * - DESTROY_ME if belonging IKE_SA should be deleted */ status_t (*process_message) (state_t *this,message_t *message); diff --git a/src/charon/threads/thread_pool.c b/src/charon/threads/thread_pool.c index 57b2539cb..51d29c222 100644 --- a/src/charon/threads/thread_pool.c +++ b/src/charon/threads/thread_pool.c @@ -146,8 +146,8 @@ static void process_jobs(private_thread_pool_t *this) this->worker_logger->log(this->worker_logger, CONTROL, "worker thread running, thread_ID: %06d", (int)pthread_self()); - for (;;) { - + for (;;) + { job = charon->job_queue->get(charon->job_queue); job_type = job->get_type(job); this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Process job of type %s", @@ -207,47 +207,43 @@ static void process_jobs(private_thread_pool_t *this) */ static void process_incoming_packet_job(private_thread_pool_t *this, incoming_packet_job_t *job) { - packet_t *packet; - message_t *message; - ike_sa_t *ike_sa; + packet_t *packet; + message_t *message; + ike_sa_t *ike_sa; ike_sa_id_t *ike_sa_id; - status_t status; - + status_t status; packet = job->get_packet(job); - + message = message_create_from_packet(packet); - status = message->parse_header(message); if (status != SUCCESS) { this->worker_logger->log(this->worker_logger, ERROR, "Message header could not be verified!"); message->destroy(message); - return; + return; } - + this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Message is a %s %s", mapping_find(exchange_type_m, message->get_exchange_type(message)), message->get_request(message) ? "request" : "reply"); - - if ((message->get_major_version(message) != IKE_MAJOR_VERSION) || - (message->get_minor_version(message) != IKE_MINOR_VERSION)) + + if ((message->get_major_version(message) != IKE_MAJOR_VERSION) || + (message->get_minor_version(message) != IKE_MINOR_VERSION)) { - this->worker_logger->log(this->worker_logger, ERROR | LEVEL2, "IKE version %d.%d not supported", - message->get_major_version(message), - message->get_minor_version(message)); - /* - * This check is not handled in state_t object of IKE_SA to increase speed. - */ + this->worker_logger->log(this->worker_logger, ERROR | LEVEL2, + "IKE version %d.%d not supported", + message->get_major_version(message), + message->get_minor_version(message)); if ((message->get_exchange_type(message) == IKE_SA_INIT) && (message->get_request(message))) - { + { message_t *response; message->get_ike_sa_id(message, &ike_sa_id); ike_sa_id->switch_initiator(ike_sa_id); response = message_create_notify_reply(message->get_destination(message), - message->get_source(message), - IKE_SA_INIT, - FALSE,ike_sa_id,INVALID_MAJOR_VERSION); + message->get_source(message), + IKE_SA_INIT, FALSE, ike_sa_id, + INVALID_MAJOR_VERSION); message->destroy(message); ike_sa_id->destroy(ike_sa_id); status = response->generate(response, NULL, NULL, &packet); @@ -265,27 +261,24 @@ static void process_incoming_packet_job(private_thread_pool_t *this, incoming_pa message->destroy(message); return; } - + message->get_ike_sa_id(message, &ike_sa_id); - + ike_sa_id->switch_initiator(ike_sa_id); - + this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "Checking out IKE SA %lld:%lld, role %s", ike_sa_id->get_initiator_spi(ike_sa_id), ike_sa_id->get_responder_spi(ike_sa_id), ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder"); - + status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa); if ((status != SUCCESS) && (status != CREATED)) { this->worker_logger->log(this->worker_logger, ERROR, "IKE SA could not be checked out"); ike_sa_id->destroy(ike_sa_id); message->destroy(message); - - /* - * TODO send notify reply of type INVALID_IKE_SPI if SPI could not be found ? - */ - + + /* TODO: send notify reply of type INVALID_IKE_SPI if SPI could not be found ? */ return; } @@ -296,25 +289,25 @@ static void process_incoming_packet_job(private_thread_pool_t *this, incoming_pa this->create_delete_half_open_ike_sa_job(this,ike_sa_id, charon->configuration->get_half_open_ike_sa_timeout(charon->configuration)); } - + status = ike_sa->process_message(ike_sa, message); - + this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "%s IKE SA %lld:%lld, role %s", - (status == DELETE_ME) ? "Checkin and delete" : "Checkin", + (status == DESTROY_ME) ? "Checkin and delete" : "Checkin", ike_sa_id->get_initiator_spi(ike_sa_id), ike_sa_id->get_responder_spi(ike_sa_id), ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder"); ike_sa_id->destroy(ike_sa_id); - - if (status == DELETE_ME) + + if (status == DESTROY_ME) { - status = charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa); + status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); } else { status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } - + if (status != SUCCESS) { this->worker_logger->log(this->worker_logger, ERROR, "Checkin of IKE SA failed!"); @@ -345,7 +338,7 @@ static void process_initiate_ike_sa_job(private_thread_pool_t *this, initiate_ik { this->worker_logger->log(this->worker_logger, ERROR, "Initiation returned %s, going to delete IKE_SA.", mapping_find(status_m, status)); - charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa); + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); return; } @@ -373,11 +366,10 @@ static void process_delete_half_open_ike_sa_job(private_thread_pool_t *this, del status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa); if ((status != SUCCESS) && (status != CREATED)) { - this->worker_logger->log(this->worker_logger, CONTROL | LEVEL3, "IKE SA seems to be already deleted and so doesn't have to be deleted"); + this->worker_logger->log(this->worker_logger, CONTROL | LEVEL3, "IKE SA seems to be already deleted"); return; } - switch (ike_sa->get_state(ike_sa)) { case INITIATOR_INIT: @@ -385,9 +377,10 @@ static void process_delete_half_open_ike_sa_job(private_thread_pool_t *this, del case IKE_SA_INIT_REQUESTED: case IKE_SA_INIT_RESPONDED: case IKE_AUTH_REQUESTED: + case DELETE_REQUESTED: { /* IKE_SA is half open and gets deleted! */ - status = charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa); + status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); if (status != SUCCESS) { this->worker_logger->log(this->worker_logger, ERROR, "Could not checkin and delete checked out IKE_SA!"); @@ -415,39 +408,14 @@ static void process_delete_established_ike_sa_job(private_thread_pool_t *this, d ike_sa_id_t *ike_sa_id = job->get_ike_sa_id(job); ike_sa_t *ike_sa; status_t status; - status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa); - if ((status != SUCCESS) && (status != CREATED)) - { - this->worker_logger->log(this->worker_logger, CONTROL | LEVEL3, "IKE SA seems to be already deleted and so doesn't have to be deleted"); - return; - } - - switch (ike_sa->get_state(ike_sa)) - { - case INITIATOR_INIT: - case RESPONDER_INIT: - case IKE_SA_INIT_REQUESTED: - case IKE_SA_INIT_RESPONDED: - case IKE_AUTH_REQUESTED: - { - break; - } - default: - { - this->worker_logger->log(this->worker_logger, CONTROL, "Send delete request for IKE_SA."); - ike_sa->send_delete_ike_sa_request(ike_sa); - break; - } - } - this->worker_logger->log(this->worker_logger, CONTROL, "Delete established IKE_SA."); - status = charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa); + status = charon->ike_sa_manager->delete(charon->ike_sa_manager, ike_sa_id); if (status != SUCCESS) { - this->worker_logger->log(this->worker_logger, ERROR, "Could not checkin and delete checked out IKE_SA!"); + this->worker_logger->log(this->worker_logger, CONTROL, "IKE SA didn't exist anymore"); + return; } } - /** * Implementation of private_thread_pool_t.process_retransmit_request_job. */ @@ -470,7 +438,7 @@ static void process_retransmit_request_job(private_thread_pool_t *this, retransm if ((status != SUCCESS) && (status != CREATED)) { job->destroy(job); - this->worker_logger->log(this->worker_logger, ERROR, "IKE SA could not be checked out. Already deleted?"); + this->worker_logger->log(this->worker_logger, ERROR|LEVEL1, "IKE SA could not be checked out. Already deleted?"); return; } @@ -478,7 +446,7 @@ static void process_retransmit_request_job(private_thread_pool_t *this, retransm if (status != SUCCESS) { - this->worker_logger->log(this->worker_logger, CONTROL | LEVEL3, "Message doesn't have to be retransmitted"); + this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "Message doesn't have to be retransmitted"); stop_retransmitting = TRUE; } diff --git a/src/libstrongswan/types.c b/src/libstrongswan/types.c index 3427b9433..6ba2a008b 100644 --- a/src/libstrongswan/types.c +++ b/src/libstrongswan/types.c @@ -39,7 +39,7 @@ mapping_t status_m[] = { {PARSE_ERROR, "PARSE_ERROR"}, {VERIFY_ERROR, "VERIFY_ERROR"}, {INVALID_STATE, "INVALID_STATE"}, - {DELETE_ME, "DELETE_ME"}, + {DESTROY_ME, "DESTROY_ME"}, {CREATED, "CREATED"}, {MAPPING_END, NULL} }; diff --git a/src/libstrongswan/types.h b/src/libstrongswan/types.h index 0498bdae5..14aee2c02 100644 --- a/src/libstrongswan/types.h +++ b/src/libstrongswan/types.h @@ -61,10 +61,10 @@ enum status_t { /** * Out of ressources. */ - OUT_OF_RES, + /** - * Already done. + * The suggested operation is already done */ ALREADY_DONE, @@ -99,9 +99,9 @@ enum status_t { INVALID_STATE, /** - * Delete object which function belongs to. + * Destroy object which called method belongs to. */ - DELETE_ME, + DESTROY_ME, /** * An object got created. diff --git a/src/starter/starter.c b/src/starter/starter.c index ee7eae3bd..88e190e1d 100644 --- a/src/starter/starter.c +++ b/src/starter/starter.c @@ -55,534 +55,595 @@ static unsigned int _action_ = 0; static void fsig(int signal) { - switch (signal) - { + switch (signal) + { case SIGCHLD: - { - int status; - pid_t pid; - char *name = NULL; - - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) - { - if (pid == starter_pluto_pid()) - name = " (Pluto)"; - if (pid == starter_charon_pid()) - name = " (Charon)"; - if (WIFSIGNALED(status)) - DBG(DBG_CONTROL, - DBG_log("child %d%s has been killed by sig %d\n", - pid, name?name:"", WTERMSIG(status)) - ) - else if (WIFSTOPPED(status)) - DBG(DBG_CONTROL, - DBG_log("child %d%s has been stopped by sig %d\n", - pid, name?name:"", WSTOPSIG(status)) - ) - else if (WIFEXITED(status)) - DBG(DBG_CONTROL, - DBG_log("child %d%s has quit (exit code %d)\n", - pid, name?name:"", WEXITSTATUS(status)) - ) - else - DBG(DBG_CONTROL, - DBG_log("child %d%s has quit", pid, name?name:"") - ) - - if (pid == starter_pluto_pid()) - starter_pluto_sigchild(pid); - if (pid == starter_charon_pid()) - starter_charon_sigchild(pid); - } - } - break; - - case SIGPIPE: - /** ignore **/ - break; - - case SIGALRM: - _action_ |= FLAG_ACTION_START_PLUTO; - _action_ |= FLAG_ACTION_START_CHARON; - break; - - case SIGHUP: - _action_ |= FLAG_ACTION_UPDATE; - break; - - case SIGTERM: - case SIGQUIT: - case SIGINT: - _action_ |= FLAG_ACTION_QUIT; - break; - - case SIGUSR1: - _action_ |= FLAG_ACTION_RELOAD; - _action_ |= FLAG_ACTION_UPDATE; - break; - - default: - plog("fsig(): unknown signal %d -- investigate", signal); - break; + { + int status; + pid_t pid; + char *name = NULL; + + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) + { + if (pid == starter_pluto_pid()) + name = " (Pluto)"; + if (pid == starter_charon_pid()) + name = " (Charon)"; + if (WIFSIGNALED(status)) + DBG(DBG_CONTROL, + DBG_log("child %d%s has been killed by sig %d\n", + pid, name?name:"", WTERMSIG(status)) + ) + else if (WIFSTOPPED(status)) + DBG(DBG_CONTROL, + DBG_log("child %d%s has been stopped by sig %d\n", + pid, name?name:"", WSTOPSIG(status)) + ) + else if (WIFEXITED(status)) + DBG(DBG_CONTROL, + DBG_log("child %d%s has quit (exit code %d)\n", + pid, name?name:"", WEXITSTATUS(status)) + ) + else + DBG(DBG_CONTROL, + DBG_log("child %d%s has quit", pid, name?name:"") + ) + if (pid == starter_pluto_pid()) + starter_pluto_sigchild(pid); + if (pid == starter_charon_pid()) + starter_charon_sigchild(pid); + } + } + break; + + case SIGPIPE: + /** ignore **/ + break; + + case SIGALRM: + _action_ |= FLAG_ACTION_START_PLUTO; + _action_ |= FLAG_ACTION_START_CHARON; + break; + + case SIGHUP: + _action_ |= FLAG_ACTION_UPDATE; + break; + + case SIGTERM: + case SIGQUIT: + case SIGINT: + _action_ |= FLAG_ACTION_QUIT; + break; + + case SIGUSR1: + _action_ |= FLAG_ACTION_RELOAD; + _action_ |= FLAG_ACTION_UPDATE; + break; + + default: + plog("fsig(): unknown signal %d -- investigate", signal); + break; } } static void usage(char *name) { - fprintf(stderr, "Usage: starter [--nofork] [--auto-update <sec>] " - "[--debug|--debug-more|--debug-all]\n"); - exit(1); + fprintf(stderr, "Usage: starter [--nofork] [--auto-update <sec>] " + "[--debug|--debug-more|--debug-all]\n"); + exit(1); } int main (int argc, char **argv) { - starter_config_t *cfg = NULL; - starter_config_t *new_cfg; - starter_conn_t *conn, *conn2; - starter_ca_t *ca, *ca2; + starter_config_t *cfg = NULL; + starter_config_t *new_cfg; + starter_conn_t *conn, *conn2; + starter_ca_t *ca, *ca2; - struct stat stb; + struct stat stb; - char *err = NULL; - int i; - int id = 1; - struct timeval tv; - unsigned long auto_update = 0; - time_t last_reload; - bool no_fork = FALSE; + char *err = NULL; + int i; + int id = 1; + struct timeval tv; + unsigned long auto_update = 0; + time_t last_reload; + bool no_fork = FALSE; - /* global variables defined in log.h */ - log_to_stderr = TRUE; - base_debugging = DBG_NONE; + /* global variables defined in log.h */ + log_to_stderr = TRUE; + base_debugging = DBG_NONE; /* parse command line */ - for (i = 1; i < argc; i++) + for (i = 1; i < argc; i++) + { + if (streq(argv[i], "--debug")) { - if (streq(argv[i], "--debug")) - { - base_debugging |= DBG_CONTROL; - } - else if (streq(argv[i], "--debug-more")) - { - base_debugging |= DBG_CONTROLMORE; - } - else if (streq(argv[i], "--debug-all")) - { - base_debugging |= DBG_ALL; - } - else if (streq(argv[i], "--nofork")) - { - no_fork = TRUE; - } - else if (streq(argv[i], "--auto-update") && i+1 < argc) - { - auto_update = atoi(argv[++i]); - if (!auto_update) - usage(argv[0]); - } - else - { - usage(argv[0]); - } + base_debugging |= DBG_CONTROL; } - - /* Init */ - init_log("ipsec_starter"); - cur_debugging = base_debugging; - - signal(SIGHUP, fsig); - signal(SIGCHLD, fsig); - signal(SIGPIPE, fsig); - signal(SIGINT, fsig); - signal(SIGTERM, fsig); - signal(SIGQUIT, fsig); - signal(SIGALRM, fsig); - signal(SIGUSR1, fsig); - - plog("Starting strongSwan %s IPsec [starter]...", ipsec_version_code()); - - /* verify that we can start */ - if (getuid() != 0) + else if (streq(argv[i], "--debug-more")) { - plog("permission denied (must be superuser)"); - exit(1); + base_debugging |= DBG_CONTROLMORE; } - - if (stat(PLUTO_PID_FILE, &stb) == 0) + else if (streq(argv[i], "--debug-all")) { - plog("pluto is already running (%s exists) -- skipping pluto start", PLUTO_PID_FILE); + base_debugging |= DBG_ALL; } - else + else if (streq(argv[i], "--nofork")) { - _action_ |= FLAG_ACTION_START_PLUTO; + no_fork = TRUE; } - if (stat(CHARON_PID_FILE, &stb) == 0) + else if (streq(argv[i], "--auto-update") && i+1 < argc) { - plog("charon is already running (%s exists) -- skipping charon start", CHARON_PID_FILE); + auto_update = atoi(argv[++i]); + if (!auto_update) + usage(argv[0]); } else { - _action_ |= FLAG_ACTION_START_CHARON; - } - if (stat(DEV_RANDOM, &stb) != 0) - { - plog("unable to start strongSwan IPsec -- no %s!", DEV_RANDOM); - exit(1); + usage(argv[0]); } + } - if (stat(DEV_URANDOM, &stb)!= 0) - { - plog("unable to start strongSwan IPsec -- no %s!", DEV_URANDOM); - exit(1); - } + /* Init */ + init_log("ipsec_starter"); + cur_debugging = base_debugging; - cfg = confread_load(CONFIG_FILE); - if (!cfg) - { - plog("unable to start strongSwan -- errors in config"); - exit(1); - } + signal(SIGHUP, fsig); + signal(SIGCHLD, fsig); + signal(SIGPIPE, fsig); + signal(SIGINT, fsig); + signal(SIGTERM, fsig); + signal(SIGQUIT, fsig); + signal(SIGALRM, fsig); + signal(SIGUSR1, fsig); - /* determine if we have a native netkey IPsec stack */ - if (!starter_netkey_init()) - { - plog("nor netkey IPSec stack detected"); - exit(1); - } + plog("Starting strongSwan %s IPsec [starter]...", ipsec_version_code()); - last_reload = time(NULL); + /* verify that we can start */ + if (getuid() != 0) + { + plog("permission denied (must be superuser)"); + exit(1); + } - if (stat(STARTER_PID_FILE, &stb) == 0) - { - plog("starter is already running (%s exists) -- no fork done", STARTER_PID_FILE); - exit(0); - } + if (stat(PLUTO_PID_FILE, &stb) == 0) + { + plog("pluto is already running (%s exists) -- skipping pluto start", PLUTO_PID_FILE); + } + else + { + _action_ |= FLAG_ACTION_START_PLUTO; + } + if (stat(CHARON_PID_FILE, &stb) == 0) + { + plog("charon is already running (%s exists) -- skipping charon start", CHARON_PID_FILE); + } + else + { + _action_ |= FLAG_ACTION_START_CHARON; + } + if (stat(DEV_RANDOM, &stb) != 0) + { + plog("unable to start strongSwan IPsec -- no %s!", DEV_RANDOM); + exit(1); + } - /* fork if we're not debugging stuff */ - if (!no_fork) + if (stat(DEV_URANDOM, &stb)!= 0) + { + plog("unable to start strongSwan IPsec -- no %s!", DEV_URANDOM); + exit(1); + } + + cfg = confread_load(CONFIG_FILE); + if (!cfg) + { + plog("unable to start strongSwan -- errors in config"); + exit(1); + } + + /* determine if we have a native netkey IPsec stack */ + if (!starter_netkey_init()) + { + plog("nor netkey IPSec stack detected"); + exit(1); + } + + last_reload = time(NULL); + + if (stat(STARTER_PID_FILE, &stb) == 0) + { + plog("starter is already running (%s exists) -- no fork done", STARTER_PID_FILE); + exit(0); + } + + /* fork if we're not debugging stuff */ + if (!no_fork) + { + log_to_stderr = FALSE; + + switch (fork()) { - log_to_stderr = FALSE; + case 0: + { + int fnull = open("/dev/null", O_RDWR); - switch (fork()) + if (fnull >= 0) { - case 0: - { - int fnull = open("/dev/null", O_RDWR); - - if (fnull >= 0) - { - dup2(fnull, STDIN_FILENO); - dup2(fnull, STDOUT_FILENO); - dup2(fnull, STDERR_FILENO); - close(fnull); - } - } - break; - case -1: - plog("can't fork: %s", strerror(errno)); - break; - default: - exit(0); + dup2(fnull, STDIN_FILENO); + dup2(fnull, STDOUT_FILENO); + dup2(fnull, STDERR_FILENO); + close(fnull); } + } + break; + case -1: + plog("can't fork: %s", strerror(errno)); + break; + default: + exit(0); + } } /* save pid file in /var/run/starter.pid */ { - FILE *fd = fopen(STARTER_PID_FILE, "w"); + FILE *fd = fopen(STARTER_PID_FILE, "w"); - if (fd) - { - fprintf(fd, "%u\n", getpid()); - fclose(fd); - } + if (fd) + { + fprintf(fd, "%u\n", getpid()); + fclose(fd); + } } for (;;) { - /* - * Stop pluto/charon (if started) and exit - */ - if (_action_ & FLAG_ACTION_QUIT) - { - if (starter_pluto_pid()) - starter_stop_pluto(); - if (starter_charon_pid()) - starter_stop_charon(); - starter_netkey_cleanup(); - confread_free(cfg); - unlink(STARTER_PID_FILE); - unlink(INFO_FILE); + /* + * Stop pluto/charon (if started) and exit + */ + if (_action_ & FLAG_ACTION_QUIT) + { + if (starter_pluto_pid()) + starter_stop_pluto(); + if (starter_charon_pid()) + starter_stop_charon(); + starter_netkey_cleanup(); + confread_free(cfg); + unlink(STARTER_PID_FILE); + unlink(INFO_FILE); #ifdef LEAK_DETECTIVE - report_leaks(); + report_leaks(); #endif /* LEAK_DETECTIVE */ - close_log(); - plog("ipsec starter stopped"); - exit(0); - } + close_log(); + plog("ipsec starter stopped"); + exit(0); + } - /* - * Delete all connections. Will be added below - */ - if (_action_ & FLAG_ACTION_RELOAD) + /* + * Delete all connections. Will be added below + */ + if (_action_ & FLAG_ACTION_RELOAD) + { + if (starter_pluto_pid() || starter_charon_pid()) + { + for (conn = cfg->conn_first; conn; conn = conn->next) { - if (starter_pluto_pid() || starter_charon_pid()) + if (conn->state == STATE_ADDED) + { + if (conn->keyexchange == KEY_EXCHANGE_IKEV2) { - for (conn = cfg->conn_first; conn; conn = conn->next) - { - if (conn->state == STATE_ADDED) - { - if (conn->keyexchange == KEY_EXCHANGE_IKEV2) - starter_stroke_del_conn(conn); - else - starter_whack_del_conn(conn); - conn->state = STATE_TO_ADD; - } - } - for (ca = cfg->ca_first; ca; ca = ca->next) - { - if (ca->state == STATE_ADDED) - { - starter_whack_del_ca(ca); - ca->state = STATE_TO_ADD; - } - } + if (starter_charon_pid()) + { + starter_stroke_del_conn(conn); + } } - _action_ &= ~FLAG_ACTION_RELOAD; + else + { + if (starter_pluto_pid()) + { + starter_whack_del_conn(conn); + conn->state = STATE_TO_ADD; + } + } + } } + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_ADDED) + { + if (starter_pluto_pid()) + { + starter_whack_del_ca(ca); + ca->state = STATE_TO_ADD; + } + } + } + } + _action_ &= ~FLAG_ACTION_RELOAD; + } - /* - * Update configuration - */ - if (_action_ & FLAG_ACTION_UPDATE) + /* + * Update configuration + */ + if (_action_ & FLAG_ACTION_UPDATE) + { + err = NULL; + DBG(DBG_CONTROL, + DBG_log("Reloading config...") + ); + new_cfg = confread_load(CONFIG_FILE); + + if (new_cfg) + { + /* Switch to new config. New conn will be loaded below */ + if (!starter_cmp_defaultroute(&new_cfg->defaultroute + , &cfg->defaultroute)) + { + _action_ |= FLAG_ACTION_LISTEN; + } + + if (!starter_cmp_pluto(cfg, new_cfg)) + { + plog("Pluto has changed"); + if (starter_pluto_pid()) + starter_stop_pluto(); + _action_ &= ~FLAG_ACTION_LISTEN; + _action_ |= FLAG_ACTION_START_PLUTO; + } + else { - err = NULL; - DBG(DBG_CONTROL, - DBG_log("Reloading config...") - ) - new_cfg = confread_load(CONFIG_FILE); + /* Only reload conn and ca sections if pluto is not killed */ - if (new_cfg) + /* Look for new connections that are already loaded */ + for (conn = cfg->conn_first; conn; conn = conn->next) + { + if (conn->state == STATE_ADDED) { - /* Switch to new config. New conn will be loaded below */ - if (!starter_cmp_defaultroute(&new_cfg->defaultroute - , &cfg->defaultroute)) + for (conn2 = new_cfg->conn_first; conn2; conn2 = conn2->next) + { + if (conn2->state == STATE_TO_ADD && starter_cmp_conn(conn, conn2)) { - _action_ |= FLAG_ACTION_LISTEN; + conn->state = STATE_REPLACED; + conn2->state = STATE_ADDED; + conn2->id = conn->id; + break; } + } + } + } - if (!starter_cmp_pluto(cfg, new_cfg)) + /* Remove conn sections that have become unused */ + for (conn = cfg->conn_first; conn; conn = conn->next) + { + if (conn->state == STATE_ADDED) + { + if (conn->keyexchange == KEY_EXCHANGE_IKEV2) + { + if (starter_charon_pid()) { - plog("Pluto has changed"); - if (starter_pluto_pid()) - starter_stop_pluto(); - _action_ &= ~FLAG_ACTION_LISTEN; - _action_ |= FLAG_ACTION_START_PLUTO; + starter_stroke_del_conn(conn); } - else + } + else + { + if (starter_pluto_pid()) { - /* Only reload conn and ca sections if pluto is not killed */ - - /* Look for new connections that are already loaded */ - for (conn = cfg->conn_first; conn; conn = conn->next) - { - if (conn->state == STATE_ADDED) - { - for (conn2 = new_cfg->conn_first; conn2; conn2 = conn2->next) - { - if (conn2->state == STATE_TO_ADD - && starter_cmp_conn(conn, conn2)) - { - conn->state = STATE_REPLACED; - conn2->state = STATE_ADDED; - conn2->id = conn->id; - break; - } - } - } - } - - /* Remove conn sections that have become unused */ - for (conn = cfg->conn_first; conn; conn = conn->next) - { - if (conn->state == STATE_ADDED) - { - if (conn->keyexchange == KEY_EXCHANGE_IKEV2) - starter_stroke_del_conn(conn); - else - starter_whack_del_conn(conn); - } - } - - /* Look for new ca sections that are already loaded */ - for (ca = cfg->ca_first; ca; ca = ca->next) - { - if (ca->state == STATE_ADDED) - { - for (ca2 = new_cfg->ca_first; ca2; ca2 = ca2->next) - { - if (ca2->state == STATE_TO_ADD - && starter_cmp_ca(ca, ca2)) - { - ca->state = STATE_REPLACED; - ca2->state = STATE_ADDED; - break; - } - } - } - } - - /* Remove ca sections that have become unused */ - for (ca = cfg->ca_first; ca; ca = ca->next) - { - if (ca->state == STATE_ADDED) - starter_whack_del_ca(ca); - } + starter_whack_del_conn(conn); } - confread_free(cfg); - cfg = new_cfg; - } - else - { - plog("can't reload config file: %s -- keeping old one"); + } } - _action_ &= ~FLAG_ACTION_UPDATE; - last_reload = time(NULL); - } + } - /* - * Start pluto - */ - if (_action_ & FLAG_ACTION_START_PLUTO) - { - if (cfg->setup.plutostart && !starter_pluto_pid()) + /* Look for new ca sections that are already loaded */ + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_ADDED) { - DBG(DBG_CONTROL, - DBG_log("Attempting to start pluto...") - ) - - if (starter_start_pluto(cfg, no_fork) == 0) + for (ca2 = new_cfg->ca_first; ca2; ca2 = ca2->next) + { + if (ca2->state == STATE_TO_ADD && starter_cmp_ca(ca, ca2)) { - starter_whack_listen(); - } - else - { - /* schedule next try */ - alarm(PLUTO_RESTART_DELAY); + ca->state = STATE_REPLACED; + ca2->state = STATE_ADDED; + break; } + } } - _action_ &= ~FLAG_ACTION_START_PLUTO; + } - for (ca = cfg->ca_first; ca; ca = ca->next) + /* Remove ca sections that have become unused */ + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_ADDED) { - if (ca->state == STATE_ADDED) - ca->state = STATE_TO_ADD; + if (starter_pluto_pid()) + { + starter_whack_del_ca(ca); + } } + } + } + confread_free(cfg); + cfg = new_cfg; + } + else + { + plog("can't reload config file: %s -- keeping old one"); + } + _action_ &= ~FLAG_ACTION_UPDATE; + last_reload = time(NULL); + } - for (conn = cfg->conn_first; conn; conn = conn->next) - { - if (conn->state == STATE_ADDED) - conn->state = STATE_TO_ADD; - } + /* + * Start pluto + */ + if (_action_ & FLAG_ACTION_START_PLUTO) + { + if (cfg->setup.plutostart && !starter_pluto_pid()) + { + DBG(DBG_CONTROL, + DBG_log("Attempting to start pluto...") + ); + + if (starter_start_pluto(cfg, no_fork) == 0) + { + starter_whack_listen(); } + else + { + /* schedule next try */ + alarm(PLUTO_RESTART_DELAY); + } + } + _action_ &= ~FLAG_ACTION_START_PLUTO; + + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_ADDED) + ca->state = STATE_TO_ADD; + } + + for (conn = cfg->conn_first; conn; conn = conn->next) + { + if (conn->state == STATE_ADDED) + conn->state = STATE_TO_ADD; + } + } - /* - * Start charon - */ - if (_action_ & FLAG_ACTION_START_CHARON) + /* + * Start charon + */ + if (_action_ & FLAG_ACTION_START_CHARON) + { + if (cfg->setup.charonstart && !starter_charon_pid()) + { + DBG(DBG_CONTROL, + DBG_log("Attempting to start charon...") + ); + if (starter_start_charon(cfg, no_fork)) { - if (cfg->setup.charonstart && !starter_charon_pid()) - { - DBG(DBG_CONTROL, - DBG_log("Attempting to start charon...") - ) - if (starter_start_charon(cfg, no_fork)) - { - /* schedule next try */ - alarm(PLUTO_RESTART_DELAY); - } - } - _action_ &= ~FLAG_ACTION_START_CHARON; + /* schedule next try */ + alarm(PLUTO_RESTART_DELAY); } + } + _action_ &= ~FLAG_ACTION_START_CHARON; + } - /* - * Tell pluto to reread its interfaces - */ - if (_action_ & FLAG_ACTION_LISTEN) + /* + * Tell pluto to reread its interfaces + */ + if (_action_ & FLAG_ACTION_LISTEN) + { + if (starter_pluto_pid()) + { + starter_whack_listen(); + _action_ &= ~FLAG_ACTION_LISTEN; + } + } + + /* + * Add stale conn and ca sections + */ + if (starter_pluto_pid() || starter_charon_pid()) + { + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_TO_ADD) { - starter_whack_listen(); - _action_ &= ~FLAG_ACTION_LISTEN; + if (starter_pluto_pid()) + { + starter_whack_add_ca(ca); + ca->state = STATE_ADDED; + } } + } - /* - * Add stale conn and ca sections - */ - if (starter_pluto_pid() || starter_charon_pid()) + for (conn = cfg->conn_first; conn; conn = conn->next) + { + if (conn->state == STATE_TO_ADD) { - for (ca = cfg->ca_first; ca; ca = ca->next) + if (conn->id == 0) + { + /* affect new unique id */ + conn->id = id++; + } + if (conn->keyexchange == KEY_EXCHANGE_IKEV2) + { + if (starter_charon_pid()) { - if (ca->state == STATE_TO_ADD) - { - starter_whack_add_ca(ca); - ca->state = STATE_ADDED; - } + starter_stroke_add_conn(conn); } + } + else + { + if (starter_pluto_pid()) + { + starter_whack_add_conn(conn); + } + } + conn->state = STATE_ADDED; - for (conn = cfg->conn_first; conn; conn = conn->next) + if (conn->startup == STARTUP_START) + { + if (conn->keyexchange == KEY_EXCHANGE_IKEV2) { - if (conn->state == STATE_TO_ADD) - { - if (conn->id == 0) - { - /* affect new unique id */ - conn->id = id++; - } - if (conn->keyexchange == KEY_EXCHANGE_IKEV2) - starter_stroke_add_conn(conn); - else - starter_whack_add_conn(conn); - conn->state = STATE_ADDED; - - if (conn->startup == STARTUP_START) - { - if (conn->keyexchange == KEY_EXCHANGE_IKEV2) - starter_stroke_initiate_conn(conn); - else - starter_whack_initiate_conn(conn); - } - else if (conn->startup == STARTUP_ROUTE) - { - if (conn->keyexchange == KEY_EXCHANGE_IKEV2) - starter_stroke_route_conn(conn); - else - starter_whack_route_conn(conn); - } - } + if (starter_charon_pid()) + { + starter_stroke_initiate_conn(conn); + } + } + else + { + if (starter_pluto_pid()) + { + starter_whack_initiate_conn(conn); + } + } + } + else if (conn->startup == STARTUP_ROUTE) + { + if (conn->keyexchange == KEY_EXCHANGE_IKEV2) + { + if (starter_charon_pid()) + { + starter_stroke_route_conn(conn); + } + } + else + { + if (starter_pluto_pid()) + { + starter_whack_route_conn(conn); + } } + } } + } + } - /* - * If auto_update activated, when to stop select - */ - if (auto_update) - { - time_t now = time(NULL); + /* + * If auto_update activated, when to stop select + */ + if (auto_update) + { + time_t now = time(NULL); - tv.tv_sec = (now < last_reload + auto_update) - ? (last_reload + auto_update-now) : 0; - tv.tv_usec = 0; - } + tv.tv_sec = (now < last_reload + auto_update) + ? (last_reload + auto_update-now) : 0; + tv.tv_usec = 0; + } - /* - * Wait for something to happen - */ - if (select(0, NULL, NULL, NULL, auto_update ? &tv : NULL) == 0) - { - /* timeout -> auto_update */ - _action_ |= FLAG_ACTION_UPDATE; - } + /* + * Wait for something to happen + */ + if (select(0, NULL, NULL, NULL, auto_update ? &tv : NULL) == 0) + { + /* timeout -> auto_update */ + _action_ |= FLAG_ACTION_UPDATE; } + } - return 0; + return 0; } diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index 67a0995a3..6fd83840a 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -36,138 +36,143 @@ #include "confread.h" #include "files.h" -static char* push_string(stroke_msg_t **strm, char *string) +static char* +push_string(stroke_msg_t **strm, char *string) { - stroke_msg_t *stroke_msg; - size_t string_length; - - if (string == NULL) - { - return NULL; - } - stroke_msg = *strm; - string_length = strlen(string) + 1; - stroke_msg->length += string_length; - - stroke_msg = realloc(stroke_msg, stroke_msg->length); - strcpy((char*)stroke_msg + stroke_msg->length - string_length, string); - - *strm = stroke_msg; - return (char*)(u_int)stroke_msg->length - string_length; + stroke_msg_t *stroke_msg; + size_t string_length; + + if (string == NULL) + { + return NULL; + } + stroke_msg = *strm; + string_length = strlen(string) + 1; + stroke_msg->length += string_length; + + stroke_msg = realloc(stroke_msg, stroke_msg->length); + strcpy((char*)stroke_msg + stroke_msg->length - string_length, string); + + *strm = stroke_msg; + return (char*)(u_int)stroke_msg->length - string_length; } static int send_stroke_msg (stroke_msg_t *msg) { - struct sockaddr_un ctl_addr = { AF_UNIX, CHARON_CTL_FILE }; - int sock; - int byte_count; - char buffer[64]; - - sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) - { - plog("socket() failed: %s", strerror(errno)); - return -1; - } - if (connect(sock, (struct sockaddr *)&ctl_addr, - offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0) - { - plog("connect(charon_ctl) failed: %s", strerror(errno)); - close(sock); - return -1; - } - - /* send message */ - if (write(sock, msg, msg->length) != msg->length) - { - plog("write(charon_ctl) failed: %s", strerror(errno)); - close(sock); - return -1; - } - while ((byte_count = read(sock, buffer, sizeof(buffer)-1)) > 0) - { - buffer[byte_count] = '\0'; - plog("%s", buffer); - } - if (byte_count < 0) - { - plog("read() failed: %s", strerror(errno)); - } + struct sockaddr_un ctl_addr = { AF_UNIX, CHARON_CTL_FILE }; + int sock; + int byte_count; + char buffer[64]; + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + { + plog("socket() failed: %s", strerror(errno)); + return -1; + } + if (connect(sock, (struct sockaddr *)&ctl_addr, + offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0) + { + plog("connect(charon_ctl) failed: %s", strerror(errno)); + close(sock); + return -1; + } + /* send message */ + if (write(sock, msg, msg->length) != msg->length) + { + plog("write(charon_ctl) failed: %s", strerror(errno)); close(sock); - return 0; + return -1; + } + while ((byte_count = read(sock, buffer, sizeof(buffer)-1)) > 0) + { + buffer[byte_count] = '\0'; + plog("%s", buffer); + } + if (byte_count < 0) + { + plog("read() failed: %s", strerror(errno)); + } + + close(sock); + return 0; } -static char * +static char* connection_name(starter_conn_t *conn) { - /* if connection name is '%auto', create a new name like conn_xxxxx */ - static char buf[32]; - - if (streq(conn->name, "%auto")) - { - sprintf(buf, "conn_%ld", conn->id); - return buf; - } - return conn->name; + /* if connection name is '%auto', create a new name like conn_xxxxx */ + static char buf[32]; + + if (streq(conn->name, "%auto")) + { + sprintf(buf, "conn_%ld", conn->id); + return buf; + } + return conn->name; } -int starter_stroke_add_conn(starter_conn_t *conn) +int +starter_stroke_add_conn(starter_conn_t *conn) { - stroke_msg_t *msg = malloc(sizeof(stroke_msg_t)); - int res; + stroke_msg_t *msg = malloc(sizeof(stroke_msg_t)); + int res; - msg->length = sizeof(stroke_msg_t); - msg->type = STR_ADD_CONN; + msg->length = sizeof(stroke_msg_t); + msg->type = STR_ADD_CONN; - msg->add_conn.name = push_string(&msg, connection_name(conn)); + msg->add_conn.name = push_string(&msg, connection_name(conn)); - msg->add_conn.me.id = push_string(&msg, conn->left.id); - msg->add_conn.me.cert = push_string(&msg, conn->left.cert); - msg->add_conn.me.address = push_string(&msg, inet_ntoa(conn->left.addr.u.v4.sin_addr)); - msg->add_conn.me.subnet = push_string(&msg, inet_ntoa(conn->left.subnet.addr.u.v4.sin_addr)); - msg->add_conn.me.subnet_mask = conn->left.subnet.maskbits; + msg->add_conn.me.id = push_string(&msg, conn->left.id); + msg->add_conn.me.cert = push_string(&msg, conn->left.cert); + msg->add_conn.me.address = push_string(&msg, inet_ntoa(conn->left.addr.u.v4.sin_addr)); + msg->add_conn.me.subnet = push_string(&msg, inet_ntoa(conn->left.subnet.addr.u.v4.sin_addr)); + msg->add_conn.me.subnet_mask = conn->left.subnet.maskbits; - msg->add_conn.other.id = push_string(&msg, conn->right.id); - msg->add_conn.other.cert = push_string(&msg, conn->right.cert); - msg->add_conn.other.address = push_string(&msg, inet_ntoa(conn->right.addr.u.v4.sin_addr)); - msg->add_conn.other.subnet = push_string(&msg, inet_ntoa(conn->right.subnet.addr.u.v4.sin_addr)); - msg->add_conn.other.subnet_mask = conn->right.subnet.maskbits; + msg->add_conn.other.id = push_string(&msg, conn->right.id); + msg->add_conn.other.cert = push_string(&msg, conn->right.cert); + msg->add_conn.other.address = push_string(&msg, inet_ntoa(conn->right.addr.u.v4.sin_addr)); + msg->add_conn.other.subnet = push_string(&msg, inet_ntoa(conn->right.subnet.addr.u.v4.sin_addr)); + msg->add_conn.other.subnet_mask = conn->right.subnet.maskbits; - res = send_stroke_msg(msg); - free(msg); - return res; + res = send_stroke_msg(msg); + free(msg); + return res; } -int starter_stroke_del_conn(starter_conn_t *conn) +int +starter_stroke_del_conn(starter_conn_t *conn) { - return 0; + return 0; } -int starter_stroke_route_conn(starter_conn_t *conn) +int +starter_stroke_route_conn(starter_conn_t *conn) { - stroke_msg_t *msg = malloc(sizeof(stroke_msg_t)); - int res; - - msg->length = sizeof(stroke_msg_t); - msg->type = STR_INSTALL; - msg->install.name = push_string(&msg, connection_name(conn)); - res = send_stroke_msg(msg); - free(msg); - return res; + stroke_msg_t *msg = malloc(sizeof(stroke_msg_t)); + int res; + + msg->length = sizeof(stroke_msg_t); + msg->type = STR_INSTALL; + msg->install.name = push_string(&msg, connection_name(conn)); + res = send_stroke_msg(msg); + free(msg); + return res; } -int starter_stroke_initiate_conn(starter_conn_t *conn) +int +starter_stroke_initiate_conn(starter_conn_t *conn) { - stroke_msg_t *msg = malloc(sizeof(stroke_msg_t)); - int res; - - msg->length = sizeof(stroke_msg_t); - msg->type = STR_INITIATE; - msg->initiate.name = push_string(&msg, connection_name(conn)); - res = send_stroke_msg(msg); - free(msg); - return res; + stroke_msg_t *msg = malloc(sizeof(stroke_msg_t)); + int res; + + msg->length = sizeof(stroke_msg_t); + msg->type = STR_INITIATE; + msg->initiate.name = push_string(&msg, connection_name(conn)); + res = send_stroke_msg(msg); + free(msg); + return res; } |