| /* |
| * Copyright (C) 2011-2013 Tobias Brunner |
| * Copyright (C) 2008 Martin Willi |
| * HSR 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 "stroke_socket.h" |
| |
| #include <stdlib.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/socket.h> |
| #include <sys/un.h> |
| #include <unistd.h> |
| #include <errno.h> |
| |
| #include <daemon.h> |
| |
| #include "stroke_config.h" |
| #include "stroke_control.h" |
| #include "stroke_cred.h" |
| #include "stroke_ca.h" |
| #include "stroke_attribute.h" |
| #include "stroke_handler.h" |
| #include "stroke_list.h" |
| #include "stroke_counter.h" |
| |
| /** |
| * To avoid clogging the thread pool with (blocking) jobs, we limit the number |
| * of concurrently handled stroke commands. |
| */ |
| #define MAX_CONCURRENT_DEFAULT 4 |
| |
| typedef struct stroke_job_context_t stroke_job_context_t; |
| typedef struct private_stroke_socket_t private_stroke_socket_t; |
| |
| /** |
| * private data of stroke_socket |
| */ |
| struct private_stroke_socket_t { |
| |
| /** |
| * public functions |
| */ |
| stroke_socket_t public; |
| |
| /** |
| * Service accepting stroke connections |
| */ |
| stream_service_t *service; |
| |
| /** |
| * configuration backend |
| */ |
| stroke_config_t *config; |
| |
| /** |
| * attribute provider |
| */ |
| stroke_attribute_t *attribute; |
| |
| /** |
| * attribute handler (requests only) |
| */ |
| stroke_handler_t *handler; |
| |
| /** |
| * controller to control daemon |
| */ |
| stroke_control_t *control; |
| |
| /** |
| * credential set |
| */ |
| stroke_cred_t *cred; |
| |
| /** |
| * CA sections |
| */ |
| stroke_ca_t *ca; |
| |
| /** |
| * status information logging |
| */ |
| stroke_list_t *list; |
| |
| /** |
| * Counter values for IKE events |
| */ |
| stroke_counter_t *counter; |
| |
| /** |
| * TRUE if log level changes are not allowed |
| */ |
| bool prevent_loglevel_changes; |
| }; |
| |
| /** |
| * Helper macro to log configuration options, but only if they are defined. |
| */ |
| #define DBG_OPT(...) VA_ARGS_DISPATCH(DBG_OPT, __VA_ARGS__)(__VA_ARGS__) |
| #define DBG_OPT2(fmt, val) ({ \ |
| typeof(val) _val = val; \ |
| if (_val) { DBG2(DBG_CFG, fmt, _val); } \ |
| }) |
| #define DBG_OPT3(fmt, label, val) ({ \ |
| typeof(val) _val = val; \ |
| if (_val) { DBG2(DBG_CFG, fmt, label, _val); } \ |
| }) |
| |
| /** |
| * Helper function which corrects the string pointers |
| * in a stroke_msg_t. Strings in a stroke_msg sent over "wire" |
| * contains RELATIVE addresses (relative to the beginning of the |
| * stroke_msg). They must be corrected if they reach our address |
| * space... |
| */ |
| static void pop_string(stroke_msg_t *msg, char **string) |
| { |
| if (*string == NULL) |
| { |
| return; |
| } |
| |
| /* check for sanity of string pointer and string */ |
| if (string < (char**)msg || |
| string > (char**)((char*)msg + sizeof(stroke_msg_t)) || |
| (unsigned long)*string < (unsigned long)((char*)msg->buffer - (char*)msg) || |
| (unsigned long)*string > msg->length) |
| { |
| *string = "(invalid pointer in stroke msg)"; |
| } |
| else |
| { |
| *string = (char*)msg + (unsigned long)*string; |
| } |
| } |
| |
| /** |
| * Pop the strings of a stroke_end_t struct and log them for debugging purposes |
| */ |
| static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end) |
| { |
| pop_string(msg, &end->address); |
| pop_string(msg, &end->subnets); |
| pop_string(msg, &end->sourceip); |
| pop_string(msg, &end->dns); |
| pop_string(msg, &end->auth); |
| pop_string(msg, &end->auth2); |
| pop_string(msg, &end->id); |
| pop_string(msg, &end->id2); |
| pop_string(msg, &end->rsakey); |
| pop_string(msg, &end->cert); |
| pop_string(msg, &end->cert2); |
| pop_string(msg, &end->ca); |
| pop_string(msg, &end->ca2); |
| pop_string(msg, &end->groups); |
| pop_string(msg, &end->groups2); |
| pop_string(msg, &end->cert_policy); |
| pop_string(msg, &end->updown); |
| |
| DBG_OPT(" %s=%s", label, end->address); |
| DBG_OPT(" %ssubnet=%s", label, end->subnets); |
| DBG_OPT(" %ssourceip=%s", label, end->sourceip); |
| DBG_OPT(" %sdns=%s", label, end->dns); |
| DBG_OPT(" %sauth=%s", label, end->auth); |
| DBG_OPT(" %sauth2=%s", label, end->auth2); |
| DBG_OPT(" %sid=%s", label, end->id); |
| DBG_OPT(" %sid2=%s", label, end->id2); |
| DBG_OPT(" %srsakey=%s", label, end->rsakey); |
| DBG_OPT(" %scert=%s", label, end->cert); |
| DBG_OPT(" %scert2=%s", label, end->cert2); |
| DBG_OPT(" %sca=%s", label, end->ca); |
| DBG_OPT(" %sca2=%s", label, end->ca2); |
| DBG_OPT(" %sgroups=%s", label, end->groups); |
| DBG_OPT(" %sgroups2=%s", label, end->groups2); |
| DBG_OPT(" %supdown=%s", label, end->updown); |
| } |
| |
| /** |
| * Add a connection to the configuration list |
| */ |
| static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg) |
| { |
| pop_string(msg, &msg->add_conn.name); |
| DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name); |
| |
| DBG2(DBG_CFG, "conn %s", msg->add_conn.name); |
| pop_end(msg, "left", &msg->add_conn.me); |
| pop_end(msg, "right", &msg->add_conn.other); |
| pop_string(msg, &msg->add_conn.eap_identity); |
| pop_string(msg, &msg->add_conn.aaa_identity); |
| pop_string(msg, &msg->add_conn.xauth_identity); |
| pop_string(msg, &msg->add_conn.algorithms.ike); |
| pop_string(msg, &msg->add_conn.algorithms.esp); |
| pop_string(msg, &msg->add_conn.algorithms.ah); |
| pop_string(msg, &msg->add_conn.ikeme.mediated_by); |
| pop_string(msg, &msg->add_conn.ikeme.peerid); |
| DBG_OPT(" eap_identity=%s", msg->add_conn.eap_identity); |
| DBG_OPT(" aaa_identity=%s", msg->add_conn.aaa_identity); |
| DBG_OPT(" xauth_identity=%s", msg->add_conn.xauth_identity); |
| DBG_OPT(" ike=%s", msg->add_conn.algorithms.ike); |
| DBG_OPT(" esp=%s", msg->add_conn.algorithms.esp); |
| DBG_OPT(" ah=%s", msg->add_conn.algorithms.ah); |
| DBG_OPT(" dpddelay=%d", msg->add_conn.dpd.delay); |
| DBG_OPT(" dpdtimeout=%d", msg->add_conn.dpd.timeout); |
| DBG_OPT(" dpdaction=%d", msg->add_conn.dpd.action); |
| DBG_OPT(" closeaction=%d", msg->add_conn.close_action); |
| DBG_OPT(" sha256_96=%s", msg->add_conn.sha256_96 ? "yes" : "no"); |
| DBG_OPT(" mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no"); |
| DBG_OPT(" mediated_by=%s", msg->add_conn.ikeme.mediated_by); |
| DBG_OPT(" me_peerid=%s", msg->add_conn.ikeme.peerid); |
| DBG_OPT(" keyexchange=ikev%u", msg->add_conn.version); |
| |
| this->config->add(this->config, msg); |
| this->attribute->add_dns(this->attribute, msg); |
| this->handler->add_attributes(this->handler, msg); |
| } |
| |
| /** |
| * Delete a connection from the list |
| */ |
| static void stroke_del_conn(private_stroke_socket_t *this, stroke_msg_t *msg) |
| { |
| pop_string(msg, &msg->del_conn.name); |
| DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name); |
| |
| this->config->del(this->config, msg); |
| this->attribute->del_dns(this->attribute, msg); |
| this->handler->del_attributes(this->handler, msg); |
| } |
| |
| /** |
| * initiate a connection by name |
| */ |
| static void stroke_initiate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) |
| { |
| pop_string(msg, &msg->initiate.name); |
| DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name); |
| |
| this->control->initiate(this->control, msg, out); |
| } |
| |
| /** |
| * terminate a connection by name |
| */ |
| static void stroke_terminate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) |
| { |
| pop_string(msg, &msg->terminate.name); |
| DBG1(DBG_CFG, "received stroke: terminate '%s'", msg->terminate.name); |
| |
| this->control->terminate(this->control, msg, out); |
| } |
| |
| /** |
| * terminate a connection by peers virtual IP |
| */ |
| static void stroke_terminate_srcip(private_stroke_socket_t *this, |
| stroke_msg_t *msg, FILE *out) |
| { |
| pop_string(msg, &msg->terminate_srcip.start); |
| pop_string(msg, &msg->terminate_srcip.end); |
| DBG1(DBG_CFG, "received stroke: terminate-srcip %s-%s", |
| msg->terminate_srcip.start, msg->terminate_srcip.end); |
| |
| this->control->terminate_srcip(this->control, msg, out); |
| } |
| |
| /** |
| * rekey a connection by name/id |
| */ |
| static void stroke_rekey(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) |
| { |
| pop_string(msg, &msg->terminate.name); |
| DBG1(DBG_CFG, "received stroke: rekey '%s'", msg->rekey.name); |
| |
| this->control->rekey(this->control, msg, out); |
| } |
| |
| /** |
| * route a policy (install SPD entries) |
| */ |
| static void stroke_route(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) |
| { |
| pop_string(msg, &msg->route.name); |
| DBG1(DBG_CFG, "received stroke: route '%s'", msg->route.name); |
| |
| this->control->route(this->control, msg, out); |
| } |
| |
| /** |
| * unroute a policy |
| */ |
| static void stroke_unroute(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) |
| { |
| pop_string(msg, &msg->terminate.name); |
| DBG1(DBG_CFG, "received stroke: unroute '%s'", msg->route.name); |
| |
| this->control->unroute(this->control, msg, out); |
| } |
| |
| /** |
| * Add a ca information record to the cainfo list |
| */ |
| static void stroke_add_ca(private_stroke_socket_t *this, |
| stroke_msg_t *msg, FILE *out) |
| { |
| pop_string(msg, &msg->add_ca.name); |
| DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name); |
| |
| pop_string(msg, &msg->add_ca.cacert); |
| pop_string(msg, &msg->add_ca.crluri); |
| pop_string(msg, &msg->add_ca.crluri2); |
| pop_string(msg, &msg->add_ca.ocspuri); |
| pop_string(msg, &msg->add_ca.ocspuri2); |
| pop_string(msg, &msg->add_ca.certuribase); |
| DBG2(DBG_CFG, "ca %s", msg->add_ca.name); |
| DBG_OPT(" cacert=%s", msg->add_ca.cacert); |
| DBG_OPT(" crluri=%s", msg->add_ca.crluri); |
| DBG_OPT(" crluri2=%s", msg->add_ca.crluri2); |
| DBG_OPT(" ocspuri=%s", msg->add_ca.ocspuri); |
| DBG_OPT(" ocspuri2=%s", msg->add_ca.ocspuri2); |
| DBG_OPT(" certuribase=%s", msg->add_ca.certuribase); |
| |
| this->ca->add(this->ca, msg); |
| } |
| |
| /** |
| * Delete a ca information record from the cainfo list |
| */ |
| static void stroke_del_ca(private_stroke_socket_t *this, |
| stroke_msg_t *msg, FILE *out) |
| { |
| pop_string(msg, &msg->del_ca.name); |
| DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name); |
| |
| this->ca->del(this->ca, msg); |
| } |
| |
| |
| /** |
| * show status of daemon |
| */ |
| static void stroke_status(private_stroke_socket_t *this, |
| stroke_msg_t *msg, FILE *out, bool all, bool wait) |
| { |
| pop_string(msg, &(msg->status.name)); |
| |
| this->list->status(this->list, msg, out, all, wait); |
| } |
| |
| /** |
| * list various information |
| */ |
| static void stroke_list(private_stroke_socket_t *this, stroke_msg_t *msg, |
| FILE *out) |
| { |
| if (msg->list.flags & LIST_CAINFOS) |
| { |
| this->ca->list(this->ca, msg, out); |
| } |
| this->list->list(this->list, msg, out); |
| } |
| |
| /** |
| * reread various information |
| */ |
| static void stroke_reread(private_stroke_socket_t *this, |
| stroke_msg_t *msg, FILE *out) |
| { |
| this->cred->reread(this->cred, msg, out); |
| } |
| |
| /** |
| * purge various information |
| */ |
| static void stroke_purge(private_stroke_socket_t *this, |
| stroke_msg_t *msg, FILE *out) |
| { |
| if (msg->purge.flags & PURGE_OCSP) |
| { |
| lib->credmgr->flush_cache(lib->credmgr, CERT_X509_OCSP_RESPONSE); |
| } |
| if (msg->purge.flags & PURGE_CRLS) |
| { |
| lib->credmgr->flush_cache(lib->credmgr, CERT_X509_CRL); |
| } |
| if (msg->purge.flags & PURGE_CERTS) |
| { |
| lib->credmgr->flush_cache(lib->credmgr, CERT_X509); |
| } |
| if (msg->purge.flags & PURGE_IKE) |
| { |
| this->control->purge_ike(this->control, msg, out); |
| } |
| } |
| |
| /** |
| * Print a certificate in PEM to out |
| */ |
| static void print_pem_cert(FILE *out, certificate_t *cert) |
| { |
| chunk_t encoded; |
| |
| if (cert->get_encoding(cert, CERT_PEM, &encoded)) |
| { |
| fprintf(out, "%.*s", (int)encoded.len, encoded.ptr); |
| free(encoded.ptr); |
| } |
| } |
| |
| /** |
| * Export in-memory credentials |
| */ |
| static void stroke_export(private_stroke_socket_t *this, |
| stroke_msg_t *msg, FILE *out) |
| { |
| pop_string(msg, &msg->export.selector); |
| |
| if (msg->export.flags & EXPORT_X509) |
| { |
| enumerator_t *enumerator; |
| identification_t *id; |
| certificate_t *cert; |
| |
| id = identification_create_from_string(msg->export.selector); |
| enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, |
| CERT_X509, KEY_ANY, id, FALSE); |
| while (enumerator->enumerate(enumerator, &cert)) |
| { |
| print_pem_cert(out, cert); |
| } |
| enumerator->destroy(enumerator); |
| id->destroy(id); |
| } |
| |
| if (msg->export.flags & (EXPORT_CONN_CERT | EXPORT_CONN_CHAIN)) |
| { |
| enumerator_t *sas, *auths, *certs; |
| ike_sa_t *ike_sa; |
| auth_cfg_t *auth; |
| certificate_t *cert; |
| auth_rule_t rule; |
| |
| sas = charon->ike_sa_manager->create_enumerator( |
| charon->ike_sa_manager, TRUE); |
| while (sas->enumerate(sas, &ike_sa)) |
| { |
| if (streq(msg->export.selector, ike_sa->get_name(ike_sa))) |
| { |
| auths = ike_sa->create_auth_cfg_enumerator(ike_sa, FALSE); |
| while (auths->enumerate(auths, &auth)) |
| { |
| bool got_subject = FALSE; |
| |
| certs = auth->create_enumerator(auth); |
| while (certs->enumerate(certs, &rule, &cert)) |
| { |
| switch (rule) |
| { |
| case AUTH_RULE_CA_CERT: |
| case AUTH_RULE_IM_CERT: |
| if (msg->export.flags & EXPORT_CONN_CHAIN) |
| { |
| print_pem_cert(out, cert); |
| } |
| break; |
| case AUTH_RULE_SUBJECT_CERT: |
| if (!got_subject) |
| { |
| print_pem_cert(out, cert); |
| got_subject = TRUE; |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| certs->destroy(certs); |
| } |
| auths->destroy(auths); |
| } |
| } |
| sas->destroy(sas); |
| } |
| } |
| |
| /** |
| * list pool leases |
| */ |
| static void stroke_leases(private_stroke_socket_t *this, |
| stroke_msg_t *msg, FILE *out) |
| { |
| pop_string(msg, &msg->leases.pool); |
| pop_string(msg, &msg->leases.address); |
| |
| this->list->leases(this->list, msg, out); |
| } |
| |
| /** |
| * Callback function for usage report |
| */ |
| static void report_usage(FILE *out, int count, size_t bytes, |
| backtrace_t *bt, bool detailed) |
| { |
| fprintf(out, "%zu bytes total, %d allocations, %zu bytes average:\n", |
| bytes, count, bytes / count); |
| bt->log(bt, out, detailed); |
| } |
| |
| /** |
| * Callback function for memusage summary |
| */ |
| static void sum_usage(FILE *out, int count, size_t bytes, int whitelisted) |
| { |
| fprintf(out, "Total memory usage: %zu\n", bytes); |
| } |
| |
| /** |
| * Show memory usage |
| */ |
| static void stroke_memusage(private_stroke_socket_t *this, |
| stroke_msg_t *msg, FILE *out) |
| { |
| if (lib->leak_detective) |
| { |
| lib->leak_detective->usage(lib->leak_detective, |
| (leak_detective_report_cb_t)report_usage, |
| (leak_detective_summary_cb_t)sum_usage, out); |
| } |
| } |
| |
| /** |
| * Set username and password for a connection |
| */ |
| static void stroke_user_creds(private_stroke_socket_t *this, |
| stroke_msg_t *msg, FILE *out) |
| { |
| pop_string(msg, &msg->user_creds.name); |
| pop_string(msg, &msg->user_creds.username); |
| pop_string(msg, &msg->user_creds.password); |
| |
| DBG1(DBG_CFG, "received stroke: user-creds '%s'", msg->user_creds.name); |
| |
| this->config->set_user_credentials(this->config, msg, out); |
| } |
| |
| /** |
| * Print stroke counter values |
| */ |
| static void stroke_counters(private_stroke_socket_t *this, |
| stroke_msg_t *msg, FILE *out) |
| { |
| pop_string(msg, &msg->counters.name); |
| |
| if (msg->counters.reset) |
| { |
| this->counter->reset(this->counter, msg->counters.name); |
| } |
| else |
| { |
| this->counter->print(this->counter, out, msg->counters.name); |
| } |
| } |
| |
| /** |
| * set the verbosity debug output |
| */ |
| static void stroke_loglevel(private_stroke_socket_t *this, |
| stroke_msg_t *msg, FILE *out) |
| { |
| debug_t group; |
| |
| pop_string(msg, &(msg->loglevel.type)); |
| DBG1(DBG_CFG, "received stroke: loglevel %d for %s", |
| msg->loglevel.level, msg->loglevel.type); |
| |
| if (this->prevent_loglevel_changes) |
| { |
| DBG1(DBG_CFG, "prevented log level change"); |
| fprintf(out, "command not allowed!\n"); |
| return; |
| } |
| if (!enum_from_name(debug_names, msg->loglevel.type, &group)) |
| { |
| fprintf(out, "unknown type '%s'!\n", msg->loglevel.type); |
| return; |
| } |
| charon->set_level(charon, group, msg->loglevel.level); |
| } |
| |
| /** |
| * set various config options |
| */ |
| static void stroke_config(private_stroke_socket_t *this, |
| stroke_msg_t *msg, FILE *out) |
| { |
| this->cred->cachecrl(this->cred, msg->config.cachecrl); |
| } |
| |
| /** |
| * process a stroke request |
| */ |
| static bool on_accept(private_stroke_socket_t *this, stream_t *stream) |
| { |
| stroke_msg_t *msg; |
| uint16_t len; |
| FILE *out; |
| |
| /* read length */ |
| if (!stream->read_all(stream, &len, sizeof(len))) |
| { |
| if (errno != EWOULDBLOCK) |
| { |
| DBG1(DBG_CFG, "reading length of stroke message failed: %s", |
| strerror(errno)); |
| } |
| return FALSE; |
| } |
| if (len < offsetof(stroke_msg_t, buffer)) |
| { |
| DBG1(DBG_CFG, "invalid stroke message length %d", len); |
| return FALSE; |
| } |
| |
| /* read message (we need an additional byte to terminate the buffer) */ |
| msg = malloc(len + 1); |
| msg->length = len; |
| if (!stream->read_all(stream, (char*)msg + sizeof(len), len - sizeof(len))) |
| { |
| if (errno != EWOULDBLOCK) |
| { |
| DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno)); |
| } |
| free(msg); |
| return FALSE; |
| } |
| /* make sure even incorrectly unterminated strings don't extend over the |
| * message boundaries */ |
| ((char*)msg)[len] = '\0'; |
| |
| DBG3(DBG_CFG, "stroke message %b", (void*)msg, len); |
| |
| out = stream->get_file(stream); |
| if (!out) |
| { |
| DBG1(DBG_CFG, "creating stroke output stream failed"); |
| free(msg); |
| return FALSE; |
| } |
| switch (msg->type) |
| { |
| case STR_INITIATE: |
| stroke_initiate(this, msg, out); |
| break; |
| case STR_ROUTE: |
| stroke_route(this, msg, out); |
| break; |
| case STR_UNROUTE: |
| stroke_unroute(this, msg, out); |
| break; |
| case STR_TERMINATE: |
| stroke_terminate(this, msg, out); |
| break; |
| case STR_TERMINATE_SRCIP: |
| stroke_terminate_srcip(this, msg, out); |
| break; |
| case STR_REKEY: |
| stroke_rekey(this, msg, out); |
| break; |
| case STR_STATUS: |
| stroke_status(this, msg, out, FALSE, TRUE); |
| break; |
| case STR_STATUS_ALL: |
| stroke_status(this, msg, out, TRUE, TRUE); |
| break; |
| case STR_STATUS_ALL_NOBLK: |
| stroke_status(this, msg, out, TRUE, FALSE); |
| break; |
| case STR_ADD_CONN: |
| stroke_add_conn(this, msg); |
| break; |
| case STR_DEL_CONN: |
| stroke_del_conn(this, msg); |
| break; |
| case STR_ADD_CA: |
| stroke_add_ca(this, msg, out); |
| break; |
| case STR_DEL_CA: |
| stroke_del_ca(this, msg, out); |
| break; |
| case STR_LOGLEVEL: |
| stroke_loglevel(this, msg, out); |
| break; |
| case STR_CONFIG: |
| stroke_config(this, msg, out); |
| break; |
| case STR_LIST: |
| stroke_list(this, msg, out); |
| break; |
| case STR_REREAD: |
| stroke_reread(this, msg, out); |
| break; |
| case STR_PURGE: |
| stroke_purge(this, msg, out); |
| break; |
| case STR_EXPORT: |
| stroke_export(this, msg, out); |
| break; |
| case STR_LEASES: |
| stroke_leases(this, msg, out); |
| break; |
| case STR_MEMUSAGE: |
| stroke_memusage(this, msg, out); |
| break; |
| case STR_USER_CREDS: |
| stroke_user_creds(this, msg, out); |
| break; |
| case STR_COUNTERS: |
| stroke_counters(this, msg, out); |
| break; |
| default: |
| DBG1(DBG_CFG, "received unknown stroke"); |
| break; |
| } |
| free(msg); |
| fclose(out); |
| return FALSE; |
| } |
| |
| METHOD(stroke_socket_t, destroy, void, |
| private_stroke_socket_t *this) |
| { |
| DESTROY_IF(this->service); |
| lib->credmgr->remove_set(lib->credmgr, &this->ca->set); |
| lib->credmgr->remove_set(lib->credmgr, &this->cred->set); |
| charon->backends->remove_backend(charon->backends, &this->config->backend); |
| charon->attributes->remove_provider(charon->attributes, |
| &this->attribute->provider); |
| charon->attributes->remove_handler(charon->attributes, |
| &this->handler->handler); |
| this->cred->destroy(this->cred); |
| this->ca->destroy(this->ca); |
| this->config->destroy(this->config); |
| this->attribute->destroy(this->attribute); |
| this->handler->destroy(this->handler); |
| this->control->destroy(this->control); |
| this->list->destroy(this->list); |
| this->counter->destroy(this->counter); |
| free(this); |
| } |
| |
| /* |
| * see header file |
| */ |
| stroke_socket_t *stroke_socket_create() |
| { |
| private_stroke_socket_t *this; |
| int max_concurrent; |
| char *uri; |
| |
| INIT(this, |
| .public = { |
| .destroy = _destroy, |
| }, |
| .prevent_loglevel_changes = lib->settings->get_bool(lib->settings, |
| "%s.plugins.stroke.prevent_loglevel_changes", FALSE, lib->ns), |
| ); |
| |
| this->ca = stroke_ca_create(); |
| this->cred = stroke_cred_create(this->ca); |
| this->attribute = stroke_attribute_create(); |
| this->handler = stroke_handler_create(); |
| this->config = stroke_config_create(this->ca, this->cred, this->attribute); |
| this->control = stroke_control_create(); |
| this->list = stroke_list_create(this->attribute); |
| this->counter = stroke_counter_create(); |
| |
| lib->credmgr->add_set(lib->credmgr, &this->ca->set); |
| lib->credmgr->add_set(lib->credmgr, &this->cred->set); |
| charon->backends->add_backend(charon->backends, &this->config->backend); |
| charon->attributes->add_provider(charon->attributes, |
| &this->attribute->provider); |
| charon->attributes->add_handler(charon->attributes, |
| &this->handler->handler); |
| |
| |
| max_concurrent = lib->settings->get_int(lib->settings, |
| "%s.plugins.stroke.max_concurrent", MAX_CONCURRENT_DEFAULT, |
| lib->ns); |
| uri = lib->settings->get_str(lib->settings, |
| "%s.plugins.stroke.socket", "unix://" STROKE_SOCKET, lib->ns); |
| this->service = lib->streams->create_service(lib->streams, uri, 10); |
| if (!this->service) |
| { |
| DBG1(DBG_CFG, "creating stroke socket failed"); |
| destroy(this); |
| return NULL; |
| } |
| this->service->on_accept(this->service, (stream_service_cb_t)on_accept, |
| this, JOB_PRIO_CRITICAL, max_concurrent); |
| |
| return &this->public; |
| } |