diff --git a/src/Makefile.am b/src/Makefile.am index 9e58ca33..780d9e4e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,7 +15,8 @@ openliprovisioner_SOURCES=provisioner/provisioner.c provisioner/provisioner.h \ provisioner/updateserver.h \ provisioner/updateserver_jsonparsing.c \ provisioner/updateserver_jsoncreation.c \ - provisioner/hup_reload.c + provisioner/hup_reload.c \ + provisioner/intercept_timers.c provisioner/intercept_timers.h openliprovisioner_LDFLAGS = -lpthread @PROVISIONER_LIBS@ openliprovisioner_LDADD = @ADD_LIBS@ diff --git a/src/configparser.c b/src/configparser.c index e64cbc24..780a90af 100644 --- a/src/configparser.c +++ b/src/configparser.c @@ -730,6 +730,31 @@ static void parse_intercept_common_fields(intercept_common_t *common, } } +static inline void init_intercept_common(intercept_common_t *common, + void *parent, openli_intercept_types_t intercept_type) { + prov_intercept_data_t *local; + + common->liid = NULL; + common->liid_len = 0; + common->authcc = NULL; + common->authcc_len = 0; + common->delivcc = NULL; + common->delivcc_len = 0; + common->destid = 0; + common->targetagency = NULL; + common->encryptkey = NULL; + common->tostart_time = 0; + common->toend_time = 0; + common->tomediate = OPENLI_INTERCEPT_OUTPUTS_ALL; + common->encrypt = OPENLI_PAYLOAD_ENCRYPTION_NONE; + common->hi1_seqno = 0; + common->local = calloc(1, sizeof(prov_intercept_data_t)); + + local = (prov_intercept_data_t *)(common->local); + local->intercept_type = intercept_type; + local->intercept_ref = (void *)parent; +} + static int parse_emailintercept_list(emailintercept_t **mailints, yaml_document_t *doc, yaml_node_t *inputs) { @@ -743,17 +768,8 @@ static int parse_emailintercept_list(emailintercept_t **mailints, unsigned int tgtcount = 0; newcept = (emailintercept_t *)calloc(1, sizeof(emailintercept_t)); - newcept->common.liid = NULL; - newcept->common.authcc = NULL; - newcept->common.delivcc = NULL; - newcept->common.destid = 0; - newcept->common.targetagency = NULL; - newcept->common.encryptkey = NULL; - newcept->common.tostart_time = 0; - newcept->common.toend_time = 0; - newcept->common.tomediate = OPENLI_INTERCEPT_OUTPUTS_ALL; - newcept->common.encrypt = OPENLI_PAYLOAD_ENCRYPTION_NONE; - newcept->common.hi1_seqno = 0; + init_intercept_common(&(newcept->common), newcept, + OPENLI_INTERCEPT_TYPE_EMAIL); newcept->awaitingconfirm = 1; newcept->targets = NULL; newcept->delivercompressed = OPENLI_EMAILINT_DELIVER_COMPRESSED_DEFAULT; @@ -837,25 +853,16 @@ static int parse_voipintercept_list(voipintercept_t **voipints, newcept->internalid = nextid; nextid ++; - newcept->common.liid = NULL; - newcept->common.authcc = NULL; - newcept->common.delivcc = NULL; + init_intercept_common(&(newcept->common), newcept, + OPENLI_INTERCEPT_TYPE_VOIP); newcept->active_cins = NULL; newcept->active_registrations = NULL; newcept->cin_callid_map = NULL; newcept->cin_sdp_map = NULL; newcept->targets = libtrace_list_init(sizeof(openli_sip_identity_t *)); newcept->active = 1; - newcept->common.destid = 0; - newcept->common.targetagency = NULL; - newcept->common.encryptkey = NULL; - newcept->common.hi1_seqno = 0; newcept->awaitingconfirm = 1; newcept->options = 0; - newcept->common.tostart_time = 0; - newcept->common.toend_time = 0; - newcept->common.tomediate = OPENLI_INTERCEPT_OUTPUTS_ALL; - newcept->common.encrypt = OPENLI_PAYLOAD_ENCRYPTION_NONE; /* Mappings describe the parameters for each intercept */ for (pair = node->data.mapping.pairs.start; @@ -917,28 +924,16 @@ static int parse_ipintercept_list(ipintercept_t **ipints, yaml_document_t *doc, /* Each sequence item is a new intercept */ newcept = (ipintercept_t *)malloc(sizeof(ipintercept_t)); + init_intercept_common(&(newcept->common), newcept, + OPENLI_INTERCEPT_TYPE_IP); - newcept->common.liid = NULL; - newcept->common.authcc = NULL; - newcept->common.delivcc = NULL; newcept->username = NULL; - newcept->common.destid = 0; - newcept->common.targetagency = NULL; - newcept->common.encryptkey = NULL; - newcept->common.hi1_seqno = 0; newcept->awaitingconfirm = 1; - newcept->common.liid_len = 0; newcept->username_len = 0; - newcept->common.authcc_len = 0; - newcept->common.delivcc_len = 0; newcept->vendmirrorid = OPENLI_VENDOR_MIRROR_NONE; newcept->accesstype = INTERNET_ACCESS_TYPE_UNDEFINED; newcept->statics = NULL; newcept->options = 0; - newcept->common.tostart_time = 0; - newcept->common.toend_time = 0; - newcept->common.tomediate = OPENLI_INTERCEPT_OUTPUTS_ALL; - newcept->common.encrypt = OPENLI_PAYLOAD_ENCRYPTION_NONE; /* Mappings describe the parameters for each intercept */ for (pair = node->data.mapping.pairs.start; diff --git a/src/intercept.h b/src/intercept.h index 0a090073..589a2a73 100644 --- a/src/intercept.h +++ b/src/intercept.h @@ -36,6 +36,13 @@ #define OPENLI_VENDOR_MIRROR_NONE (0xffffffff) +typedef enum { + OPENLI_INTERCEPT_TYPE_UNKNOWN = 0, + OPENLI_INTERCEPT_TYPE_IP = 1, + OPENLI_INTERCEPT_TYPE_VOIP = 2, + OPENLI_INTERCEPT_TYPE_EMAIL = 3, +} openli_intercept_types_t; + typedef enum { INTERNET_ACCESS_TYPE_UNDEFINED = 0, INTERNET_ACCESS_TYPE_DIALUP = 1, @@ -114,6 +121,13 @@ typedef struct intercept_common { intercept_outputs_t tomediate; payload_encryption_method_t encrypt; char *encryptkey; + + /** A pointer to use for storing "local" data against an instance of + * an intercept, i.e. the provisioner might want to associate + * certain data against each intercept that is not required by the + * collector or mediator. + */ + void *local; } intercept_common_t; typedef struct hi1_notify_data { diff --git a/src/provisioner/clientupdates.c b/src/provisioner/clientupdates.c index 57ece694..092b8015 100644 --- a/src/provisioner/clientupdates.c +++ b/src/provisioner/clientupdates.c @@ -393,6 +393,7 @@ int announce_hi1_notification_to_mediators(provision_state_t *state, hi1_notify_data_t ndata; struct timeval tv; + prov_intercept_data_t *ceptdata = (prov_intercept_data_t *)(intcomm->local); if (intcomm == NULL) { return -1; @@ -400,6 +401,41 @@ int announce_hi1_notification_to_mediators(provision_state_t *state, gettimeofday(&tv, NULL); + if (ceptdata && not_type == HI1_LI_ACTIVATED) { + if (ceptdata->start_hi1_sent) { + return 0; + } + if (intcomm->tostart_time > tv.tv_sec) { + return 0; + } + ceptdata->start_hi1_sent = 1; + ceptdata->end_hi1_sent = 0; + } else if (ceptdata && not_type == HI1_LI_DEACTIVATED) { + if (ceptdata->end_hi1_sent) { + return 0; + } + if (!ceptdata->start_hi1_sent) { + return 0; + } + ceptdata->end_hi1_sent = 1; + ceptdata->start_hi1_sent = 0; + } else if (ceptdata && not_type == HI1_LI_MODIFIED) { + if (ceptdata->end_hi1_sent) { + return 0; + } + if (!ceptdata->start_hi1_sent) { + if (intcomm->tostart_time > tv.tv_sec) { + return 0; + } else { + /* shouldn't get here ideally, but just in case we do then + * let's send an activated message instead. + */ + not_type = HI1_LI_ACTIVATED; + ceptdata->start_hi1_sent = 1; + } + } + } + ndata.notify_type = not_type; ndata.liid = intcomm->liid; ndata.authcc = intcomm->authcc; @@ -423,7 +459,7 @@ int announce_hi1_notification_to_mediators(provision_state_t *state, } SEND_ALL_MEDIATORS_END intcomm->hi1_seqno ++; - return 0; + return 1; } int remove_liid_mapping(provision_state_t *state, diff --git a/src/provisioner/hup_reload.c b/src/provisioner/hup_reload.c index 53552c61..df23bd33 100644 --- a/src/provisioner/hup_reload.c +++ b/src/provisioner/hup_reload.c @@ -30,6 +30,7 @@ #include "util.h" #include "configparser.h" #include "updateserver.h" +#include "intercept_timers.h" static inline int reload_staticips(provision_state_t *currstate, ipintercept_t *ipint, ipintercept_t *newequiv) { @@ -242,13 +243,156 @@ static int reload_coreservers(provision_state_t *state, coreserver_t *currserv, return 0; } +static void remove_withdrawn_intercept(provision_state_t *currstate, + intercept_common_t *common, char *target_info, int droppedmeds) { + + remove_liid_mapping(currstate, common->liid, common->liid_len, droppedmeds); + if (!droppedmeds) { + announce_hi1_notification_to_mediators(currstate, + common, target_info, HI1_LI_DEACTIVATED); + if (target_info) { + free(target_info); + } + } + + logger(LOG_INFO, "OpenLI provisioner: LIID %s has been withdrawn following a config reload.", + common->liid); +} + +static int enable_new_intercept(provision_state_t *currstate, + intercept_common_t *common, prov_intercept_conf_t *intconf, + char *target_info, int droppedmeds) { + + liid_hash_t *h = NULL; + struct timeval tv; + prov_agency_t *lea = NULL; + prov_intercept_data_t *local; + + + if (strcmp(common->targetagency, "pcapdisk") != 0) { + HASH_FIND_STR(intconf->leas, common->targetagency, lea); + if (lea == NULL) { + return 0; + } + } + + gettimeofday(&tv, NULL); + local = (prov_intercept_data_t *)(common->local); + if (local && (common->tostart_time > 0 || common->toend_time > 0)) { + + if (add_intercept_timer(currstate->epoll_fd, + common->tostart_time, tv.tv_sec, + local, PROV_EPOLL_INTERCEPT_START) < 0) { + logger(LOG_INFO, + "OpenLI provisioner: unable to schedule HI1 notification for starting email intercept %s", common->liid); + + return -1; + } + + if (add_intercept_timer(currstate->epoll_fd, + common->toend_time, tv.tv_sec, + local, PROV_EPOLL_INTERCEPT_HALT) < 0) { + logger(LOG_INFO, + "OpenLI provisioner: unable to schedule HI1 notification for halting email intercept %s", common->liid); + + return -1; + } + } + + /* Add the LIID mapping */ + h = add_liid_mapping(intconf, common->liid, common->targetagency); + + if (!droppedmeds && announce_hi1_notification_to_mediators(currstate, + common, target_info, HI1_LI_ACTIVATED) == -1) { + logger(LOG_INFO, + "OpenLI provisioner: unable to send HI1 notification for new Email intercept to mediators."); + return -1; + } + + if (!droppedmeds && announce_liidmapping_to_mediators(currstate, h) == -1) { + logger(LOG_INFO, + "OpenLI provisioner: unable to announce new Email intercept to mediators."); + return -1; + } + return 1; +} + +static int update_reconfigured_intercept(provision_state_t *currstate, + intercept_common_t *old_common, intercept_common_t *new_common, + prov_intercept_conf_t *intconf, int cept_changed, int agencychanged, + int droppedmeds, char *old_targets, char *new_targets) { + + char errorstring[1024]; + liid_hash_t *h = NULL; + + prov_intercept_data_t *local, *oldlocal; + /* save the "hi1 sent" status from the original intercept + * instance. + */ + oldlocal = (prov_intercept_data_t *)(old_common->local); + local = (prov_intercept_data_t *)(new_common->local); + + local->start_hi1_sent = oldlocal->start_hi1_sent; + local->end_hi1_sent = oldlocal->end_hi1_sent; + new_common->hi1_seqno = old_common->hi1_seqno; + + if (agencychanged || cept_changed) { + logger(LOG_INFO, + "OpenLI provisioner: Details for intercept %s have changed -- updating collectors", + new_common->liid); + } + + if (!droppedmeds && agencychanged) { + announce_hi1_notification_to_mediators(currstate, + old_common, old_targets, HI1_LI_DEACTIVATED); + new_common->hi1_seqno = 0; + announce_hi1_notification_to_mediators(currstate, + new_common, new_targets, HI1_LI_ACTIVATED); + } else if (!droppedmeds && cept_changed) { + announce_hi1_notification_to_mediators(currstate, + new_common, new_targets, HI1_LI_MODIFIED); + } + + + /* clear the old HI1 timers, since they will be pointing + * at an intercept instance that is going to be removed + * when we complete the config reload. + */ + free_prov_intercept_data(old_common, currstate->epoll_fd); + + /* add new intercept timers, and also send any required + * HI1 messages + */ + if (reset_intercept_timers(currstate, new_common, + new_targets, errorstring, 1024) < 0) { + logger(LOG_INFO, "OpenLI provisioner: unable to reset intercept timers: %s", errorstring); + } + + if (agencychanged) { + remove_liid_mapping(currstate, old_common->liid, + old_common->liid_len, droppedmeds); + + h = add_liid_mapping(intconf, new_common->liid, + new_common->targetagency); + if (!droppedmeds && announce_liidmapping_to_mediators( + currstate, h) == -1) { + logger(LOG_INFO, + "OpenLI provisioner: unable to announce new agency for intercept %s to mediators.", new_common->liid); + return -1; + } + } + + return 0; +} + static int reload_emailintercepts(provision_state_t *currstate, emailintercept_t *curremail, emailintercept_t *newemail, prov_intercept_conf_t *intconf, int droppedcols, int droppedmeds) { emailintercept_t *mailint, *tmp, *newequiv; - liid_hash_t *h = NULL; char *target_info; + prov_intercept_data_t *local, *oldlocal; + struct timeval tv; /* TODO error handling in the "inform other components about changes" * functions? @@ -257,23 +401,21 @@ static int reload_emailintercepts(provision_state_t *currstate, HASH_FIND(hh_liid, newemail, mailint->common.liid, mailint->common.liid_len, newequiv); + local = (prov_intercept_data_t *)(mailint->common.local); + if (!newequiv) { /* Intercept has been withdrawn entirely */ if (!droppedcols) { halt_existing_intercept(currstate, (void *)mailint, OPENLI_PROTO_HALT_EMAILINTERCEPT); } - remove_liid_mapping(currstate, mailint->common.liid, - mailint->common.liid_len, droppedmeds); - if (!droppedmeds) { - target_info = list_email_targets(mailint, 256); - announce_hi1_notification_to_mediators(currstate, - &(mailint->common), target_info, - HI1_LI_DEACTIVATED); - if (target_info) { - free(target_info); - } + target_info = list_email_targets(mailint, 256); + remove_withdrawn_intercept(currstate, &(mailint->common), + target_info, droppedmeds); + if (target_info) { + free(target_info); } + continue; } else { int intsame = email_intercept_equal(mailint, newequiv); @@ -282,42 +424,15 @@ static int reload_emailintercepts(provision_state_t *currstate, int changedtargets = compare_email_targets(currstate, mailint, newequiv); - newequiv->common.hi1_seqno = mailint->common.hi1_seqno; - newequiv->awaitingconfirm = 0; + char *old_target_info = list_email_targets(mailint, 256); + char *new_target_info = list_email_targets(newequiv, 256); - if (intsame && !agencychanged && changedtargets == 0) { - continue; - } - - logger(LOG_INFO, "OpenLI provisioner: Details for Email intercept %s have changed -- updating collectors", - mailint->common.liid); - - if (!droppedmeds) { - if (agencychanged) { - target_info = list_email_targets(mailint, 256); - announce_hi1_notification_to_mediators(currstate, - &(mailint->common), target_info, - HI1_LI_DEACTIVATED); - if (target_info) { - free(target_info); - } - newequiv->common.hi1_seqno = 0; - target_info = list_email_targets(newequiv, 256); - announce_hi1_notification_to_mediators(currstate, - &(newequiv->common), target_info, - HI1_LI_ACTIVATED); - if (target_info) { - free(target_info); - } - } else { - target_info = list_email_targets(newequiv, 256); - announce_hi1_notification_to_mediators(currstate, - &(newequiv->common), target_info, - HI1_LI_MODIFIED); - if (target_info) { - free(target_info); - } - } + newequiv->awaitingconfirm = 0; + if (update_reconfigured_intercept(currstate, &(mailint->common), + &(newequiv->common), intconf, (!intsame || changedtargets), + agencychanged, droppedmeds, old_target_info, + new_target_info) < 0) { + return -1; } if (!intsame && !droppedcols) { @@ -325,65 +440,34 @@ static int reload_emailintercepts(provision_state_t *currstate, OPENLI_PROTO_MODIFY_EMAILINTERCEPT); } - if (agencychanged) { - remove_liid_mapping(currstate, mailint->common.liid, - mailint->common.liid_len, droppedmeds); - - h = add_liid_mapping(intconf, newequiv->common.liid, - newequiv->common.targetagency); - if (!droppedmeds && announce_liidmapping_to_mediators( - currstate, h) == -1) { - logger(LOG_INFO, - "OpenLI provisioner: unable to announce new agency for Email intercept to mediators."); - return -1; - } + if (old_target_info) { + free(old_target_info); + } + if (new_target_info) { + free(new_target_info); } } } + gettimeofday(&tv, NULL); + HASH_ITER(hh_liid, newemail, mailint, tmp) { - int skip = 0; - prov_agency_t *lea = NULL; + int r = 0; if (!mailint->awaitingconfirm) { continue; } - - if (strcmp(mailint->common.targetagency, "pcapdisk") != 0) { - HASH_FIND_STR(intconf->leas, mailint->common.targetagency, lea); - if (lea == NULL) { - skip = 1; - } - } - - if (skip) { - continue; - } - - /* Add the LIID mapping */ - h = add_liid_mapping(intconf, mailint->common.liid, - mailint->common.targetagency); - target_info = list_email_targets(mailint, 256); - if (!droppedmeds && announce_hi1_notification_to_mediators(currstate, - &(mailint->common), target_info, - HI1_LI_ACTIVATED) == -1) { - if (target_info) { - free(target_info); - } - logger(LOG_INFO, - "OpenLI provisioner: unable to send HI1 notification for new Email intercept to mediators."); - return -1; - } + r = enable_new_intercept(currstate, &(mailint->common), intconf, + target_info, droppedmeds); if (target_info) { free(target_info); } - - if (!droppedmeds && announce_liidmapping_to_mediators(currstate, - h) == -1) { - logger(LOG_INFO, - "OpenLI provisioner: unable to announce new Email intercept to mediators."); - return -1; + if (r < 0) { + return r; + } + if (r == 0) { + continue; } if (!droppedcols && announce_single_intercept(currstate, @@ -408,8 +492,9 @@ static int reload_voipintercepts(provision_state_t *currstate, prov_intercept_conf_t *intconf, int droppedcols, int droppedmeds) { voipintercept_t *voipint, *tmp, *newequiv; - liid_hash_t *h = NULL; char *target_info; + prov_intercept_data_t *local, *oldlocal; + struct timeval tv; /* TODO error handling in the "inform other components about changes" * functions? @@ -418,6 +503,8 @@ static int reload_voipintercepts(provision_state_t *currstate, HASH_FIND(hh_liid, newvoip, voipint->common.liid, voipint->common.liid_len, newequiv); + local = (prov_intercept_data_t *)(voipint->common.local); + if (newequiv && currstate->ignorertpcomfort) { newequiv->options |= (1 << OPENLI_VOIPINT_OPTION_IGNORE_COMFORT); } @@ -428,16 +515,11 @@ static int reload_voipintercepts(provision_state_t *currstate, halt_existing_intercept(currstate, (void *)voipint, OPENLI_PROTO_HALT_VOIPINTERCEPT); } - remove_liid_mapping(currstate, voipint->common.liid, - voipint->common.liid_len, droppedmeds); - if (!droppedmeds) { - target_info = list_sip_targets(voipint, 256); - announce_hi1_notification_to_mediators(currstate, - &(voipint->common), target_info, - HI1_LI_DEACTIVATED); - if (target_info) { - free(target_info); - } + target_info = list_sip_targets(voipint, 256); + remove_withdrawn_intercept(currstate, &(voipint->common), + target_info, droppedmeds); + if (target_info) { + free(target_info); } continue; } else { @@ -446,43 +528,15 @@ static int reload_voipintercepts(provision_state_t *currstate, newequiv->common.targetagency); int changedtargets = compare_sip_targets(currstate, voipint, newequiv); + char *old_target_info = list_sip_targets(voipint, 256); + char *new_target_info = list_sip_targets(newequiv, 256); - newequiv->common.hi1_seqno = voipint->common.hi1_seqno; newequiv->awaitingconfirm = 0; - - if (intsame && !agencychanged && changedtargets == 0) { - continue; - } - - logger(LOG_INFO, "OpenLI provisioner: Details for VOIP intercept %s have changed -- updating collectors", - voipint->common.liid); - - if (!droppedmeds) { - if (agencychanged) { - target_info = list_sip_targets(voipint, 256); - announce_hi1_notification_to_mediators(currstate, - &(voipint->common), target_info, - HI1_LI_DEACTIVATED); - if (target_info) { - free(target_info); - } - newequiv->common.hi1_seqno = 0; - target_info = list_sip_targets(newequiv, 256); - announce_hi1_notification_to_mediators(currstate, - &(newequiv->common), target_info, - HI1_LI_ACTIVATED); - if (target_info) { - free(target_info); - } - } else { - target_info = list_sip_targets(newequiv, 256); - announce_hi1_notification_to_mediators(currstate, - &(newequiv->common), target_info, - HI1_LI_MODIFIED); - if (target_info) { - free(target_info); - } - } + if (update_reconfigured_intercept(currstate, &(voipint->common), + &(newequiv->common), intconf, (!intsame || changedtargets), + agencychanged, droppedmeds, old_target_info, + new_target_info) < 0) { + return -1; } if (!intsame && !droppedcols) { @@ -490,69 +544,37 @@ static int reload_voipintercepts(provision_state_t *currstate, OPENLI_PROTO_MODIFY_VOIPINTERCEPT); } - if (agencychanged) { - remove_liid_mapping(currstate, voipint->common.liid, - voipint->common.liid_len, droppedmeds); - - h = add_liid_mapping(intconf, newequiv->common.liid, - newequiv->common.targetagency); - if (!droppedmeds && announce_liidmapping_to_mediators( - currstate, h) == -1) { - logger(LOG_INFO, - "OpenLI provisioner: unable to announce new agency for VOIP intercept to mediators."); - return -1; - } + if (old_target_info) { + free(old_target_info); + } + if (new_target_info) { + free(new_target_info); } + } } + gettimeofday(&tv, NULL); HASH_ITER(hh_liid, newvoip, voipint, tmp) { - int skip = 0; - prov_agency_t *lea = NULL; + int r = 0; if (!voipint->awaitingconfirm) { continue; } - - if (strcmp(voipint->common.targetagency, "pcapdisk") != 0) { - HASH_FIND_STR(intconf->leas, voipint->common.targetagency, lea); - if (lea == NULL) { - skip = 1; - } - } - - if (skip) { - continue; - } - + target_info = list_sip_targets(voipint, 256); if (currstate->ignorertpcomfort) { voipint->options |= (1 << OPENLI_VOIPINT_OPTION_IGNORE_COMFORT); } - - /* Add the LIID mapping */ - h = add_liid_mapping(intconf, voipint->common.liid, - voipint->common.targetagency); - - target_info = list_sip_targets(voipint, 256); - if (!droppedmeds && announce_hi1_notification_to_mediators(currstate, - &(voipint->common), target_info, - HI1_LI_ACTIVATED) == -1) { - if (target_info) { - free(target_info); - } - logger(LOG_INFO, - "OpenLI provisioner: unable to send HI1 notification for new VOIP intercept to mediators."); - return -1; - } + r = enable_new_intercept(currstate, &(voipint->common), intconf, + target_info, droppedmeds); if (target_info) { free(target_info); } - - if (!droppedmeds && announce_liidmapping_to_mediators(currstate, - h) == -1) { - logger(LOG_INFO, - "OpenLI provisioner: unable to announce new VOIP intercept to mediators."); - return -1; + if (r < 0) { + return r; + } + if (r == 0) { + continue; } if (!droppedcols && announce_single_intercept(currstate, @@ -577,28 +599,24 @@ static int reload_ipintercepts(provision_state_t *currstate, prov_intercept_conf_t *intconf, int droppedcols, int droppedmeds) { ipintercept_t *ipint, *tmp, *newequiv; - liid_hash_t *h = NULL; + prov_intercept_data_t *local, *oldlocal; + struct timeval tv; - /* TODO error handling in the "inform other components about changes" - * functions? - */ HASH_ITER(hh_liid, currints, ipint, tmp) { HASH_FIND(hh_liid, newints, ipint->common.liid, ipint->common.liid_len, newequiv); + + local = (prov_intercept_data_t *)(ipint->common.local); + if (!newequiv) { /* Intercept has been withdrawn entirely */ if (!droppedcols) { halt_existing_intercept(currstate, (void *)ipint, OPENLI_PROTO_HALT_IPINTERCEPT); } - remove_liid_mapping(currstate, ipint->common.liid, - ipint->common.liid_len, droppedmeds); - if (!droppedmeds) { - announce_hi1_notification_to_mediators(currstate, - &(ipint->common), ipint->username, HI1_LI_DEACTIVATED); - } - logger(LOG_INFO, "OpenLI provisioner: LIID %s has been withdrawn", - ipint->common.liid); + remove_withdrawn_intercept(currstate, &(ipint->common), + ipint->username, droppedmeds); + continue; } else { int staticchanged = reload_staticips(currstate, ipint, newequiv); @@ -606,90 +624,38 @@ static int reload_ipintercepts(provision_state_t *currstate, int agencychanged = strcmp(ipint->common.targetagency, newequiv->common.targetagency); - newequiv->common.hi1_seqno = ipint->common.hi1_seqno; newequiv->awaitingconfirm = 0; - if (staticchanged == 0 && intsame && agencychanged == 0) { - continue; - } - - logger(LOG_INFO, "OpenLI provisioner: Details for IP intercept %s have changed -- updating collectors", - ipint->common.liid); - - if (!droppedmeds) { - if (agencychanged) { - announce_hi1_notification_to_mediators(currstate, - &(ipint->common), ipint->username, - HI1_LI_DEACTIVATED); - newequiv->common.hi1_seqno = 0; - announce_hi1_notification_to_mediators(currstate, - &(newequiv->common), newequiv->username, - HI1_LI_ACTIVATED); - } else { - announce_hi1_notification_to_mediators(currstate, - &(newequiv->common), newequiv->username, - HI1_LI_MODIFIED); - } + if (update_reconfigured_intercept(currstate, &(ipint->common), + &(newequiv->common), intconf, (!intsame || staticchanged), + agencychanged, droppedmeds, ipint->username, + newequiv->username) < 0) { + return -1; } if (!intsame && !droppedcols) { modify_existing_intercept_options(currstate, (void *)newequiv, OPENLI_PROTO_MODIFY_IPINTERCEPT); } - - if (agencychanged) { - remove_liid_mapping(currstate, ipint->common.liid, - ipint->common.liid_len, droppedmeds); - - h = add_liid_mapping(intconf, newequiv->common.liid, - newequiv->common.targetagency); - if (!droppedmeds && announce_liidmapping_to_mediators( - currstate, h) == -1) { - logger(LOG_INFO, - "OpenLI provisioner: unable to announce new agency for IP intercept to mediators."); - return -1; - } - } } } HASH_ITER(hh_liid, newints, ipint, tmp) { - int skip = 0; - prov_agency_t *lea = NULL; + int r = 0; if (!ipint->awaitingconfirm) { continue; } - if (strcmp(ipint->common.targetagency, "pcapdisk") != 0) { - HASH_FIND_STR(intconf->leas, ipint->common.targetagency, lea); - if (lea == NULL) { - skip = 1; - } + r = enable_new_intercept(currstate, &(ipint->common), intconf, + ipint->username, droppedmeds); + if (r < 0) { + return r; } - - if (skip) { + if (r == 0) { continue; } - /* Add the LIID mapping */ - h = add_liid_mapping(intconf, ipint->common.liid, - ipint->common.targetagency); - - if (!droppedmeds && announce_hi1_notification_to_mediators(currstate, - &(ipint->common), ipint->username, HI1_LI_ACTIVATED) == -1) { - logger(LOG_INFO, - "OpenLI provisioner: unable to send HI1 notification for new IP intercept to mediators."); - return -1; - } - - if (!droppedmeds && announce_liidmapping_to_mediators(currstate, - h) == -1) { - logger(LOG_INFO, - "OpenLI provisioner: unable to announce new IP intercept to mediators."); - return -1; - } - if (!droppedcols && announce_single_intercept(currstate, (void *)ipint, push_ipintercept_onto_net_buffer) == -1) { logger(LOG_INFO, diff --git a/src/provisioner/intercept_timers.c b/src/provisioner/intercept_timers.c new file mode 100644 index 00000000..50dd945a --- /dev/null +++ b/src/provisioner/intercept_timers.c @@ -0,0 +1,317 @@ +/* + * + * Copyright (c) 2018-2023 The University of Waikato, Hamilton, New Zealand. + * All rights reserved. + * + * This file is part of OpenLI. + * + * OpenLI was originally developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * OpenLI 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 3 of the License, or + * (at your option) any later version. + * + * OpenLI 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ + +#include "util.h" +#include "provisioner.h" +#include "logger.h" + +#include "intercept_timers.h" + +int add_intercept_timer(int epoll_fd, uint64_t tssec, uint64_t now, + prov_intercept_data_t *ceptdata, int timertype) { + + int fd; + prov_epoll_ev_t **timerptr; + struct epoll_event ev; + + if (tssec == 0 || tssec < now) { + return 0; + } + + if (timertype == PROV_EPOLL_INTERCEPT_START) { + timerptr = &(ceptdata->start_timer); + } else if (timertype == PROV_EPOLL_INTERCEPT_HALT) { + timerptr = &(ceptdata->end_timer); + } else { + return -1; + } + + if (*timerptr == NULL) { + *timerptr = calloc(1, sizeof(prov_epoll_ev_t)); + (*timerptr)->fd = -1; + } + if ((*timerptr)->fd != -1) { + epoll_ctl(epoll_fd, EPOLL_CTL_DEL, (*timerptr)->fd, &ev); + } + fd = epoll_add_timer(epoll_fd, tssec - now, *timerptr); + if (fd == -1) { + return -1; + } + (*timerptr)->fd = fd; + (*timerptr)->fdtype = timertype; + (*timerptr)->client = NULL; + (*timerptr)->cept = ceptdata; + + return 1; +} + +int halt_intercept_timer(prov_epoll_ev_t *timer, int epoll_fd) { + struct epoll_event ev; + + if (timer == NULL) { + return 0; + } + + if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, timer->fd, &ev) < 0) { + /* what error handling makes sense here? */ + return -1; + } + + close(timer->fd); + timer->fd = -1; + return 0; +} + +void free_prov_intercept_data(intercept_common_t *common, int epoll_fd) { + prov_intercept_data_t *timers = NULL; + + timers = (prov_intercept_data_t *)(common->local); + if (timers == NULL) { + return; + } + if (timers->start_timer) { + halt_intercept_timer(timers->start_timer, epoll_fd); + free(timers->start_timer); + } + if (timers->end_timer) { + halt_intercept_timer(timers->end_timer, epoll_fd); + free(timers->end_timer); + } + + free(timers); + common->local = NULL; +} + +int add_all_intercept_timers(int epoll_fd, prov_intercept_conf_t *conf) { + ipintercept_t *ipint; + voipintercept_t *vint; + emailintercept_t *mailint; + + prov_intercept_data_t *local; + struct timeval tv; + int failed = 0; + + gettimeofday(&tv, NULL); + + /* Do IP Intercepts */ + for (ipint = conf->ipintercepts; ipint != NULL; ipint = ipint->hh_liid.next) + { + local = (prov_intercept_data_t *)(ipint->common.local); + /* If the start time is before now, set the started flag to true + * so we don't end up sending an erroneous "started" message later + * on (i.e. after a config reload) + */ + if (tv.tv_sec > ipint->common.tostart_time) { + local->start_hi1_sent = 1; + } + if (add_intercept_timer(epoll_fd, ipint->common.tostart_time, + tv.tv_sec, local, PROV_EPOLL_INTERCEPT_START) < 0) { + failed = 1; + } + /* Same as above, but for the "deactivated" message. */ + if (tv.tv_sec > ipint->common.toend_time && + ipint->common.toend_time != 0) { + local->end_hi1_sent = 1; + local->start_hi1_sent = 0; + } + if (add_intercept_timer(epoll_fd, ipint->common.toend_time, + tv.tv_sec, local, PROV_EPOLL_INTERCEPT_HALT) < 0) { + failed = 1; + } + + } + + /* Now do the VOIP intercepts */ + for (vint = conf->voipintercepts; vint != NULL; vint = vint->hh_liid.next) + { + local = (prov_intercept_data_t *)(vint->common.local); + if (tv.tv_sec > vint->common.tostart_time) { + local->start_hi1_sent = 1; + } + if (add_intercept_timer(epoll_fd, vint->common.tostart_time, + tv.tv_sec, local, PROV_EPOLL_INTERCEPT_START) < 0) { + failed = 1; + } + if (tv.tv_sec > vint->common.toend_time && + vint->common.toend_time != 0) { + local->end_hi1_sent = 1; + local->start_hi1_sent = 0; + } + if (add_intercept_timer(epoll_fd, vint->common.toend_time, + tv.tv_sec, local, PROV_EPOLL_INTERCEPT_HALT) < 0) { + failed = 1; + } + } + + for (mailint = conf->emailintercepts; mailint != NULL; + mailint = mailint->hh_liid.next) { + local = (prov_intercept_data_t *)(mailint->common.local); + if (tv.tv_sec > mailint->common.tostart_time) { + local->start_hi1_sent = 1; + } + if (add_intercept_timer(epoll_fd, mailint->common.tostart_time, + tv.tv_sec, local, PROV_EPOLL_INTERCEPT_START) < 0) { + failed = 1; + } + if (tv.tv_sec > mailint->common.toend_time && + mailint->common.toend_time != 0) { + local->end_hi1_sent = 1; + local->start_hi1_sent = 0; + } + if (add_intercept_timer(epoll_fd, mailint->common.toend_time, + tv.tv_sec, local, PROV_EPOLL_INTERCEPT_HALT) < 0) { + failed = 1; + } + } + return failed; +} + +int remove_all_intercept_timers(int epoll_fd, prov_intercept_conf_t *conf) { + ipintercept_t *ipint; + voipintercept_t *vint; + emailintercept_t *mailint; + + /* Do IP Intercepts */ + for (ipint = conf->ipintercepts; ipint != NULL; ipint = ipint->hh_liid.next) + { + free_prov_intercept_data(&(ipint->common), epoll_fd); + } + + /* Now do the VOIP intercepts */ + for (vint = conf->voipintercepts; vint != NULL; vint = vint->hh_liid.next) + { + free_prov_intercept_data(&(vint->common), epoll_fd); + } + + for (mailint = conf->emailintercepts; mailint != NULL; + mailint = mailint->hh_liid.next) { + free_prov_intercept_data(&(mailint->common), epoll_fd); + } + + return 0; +} + +int reset_intercept_timers(provision_state_t *state, + intercept_common_t *existing, char *target_info, + char *errorstring, int errorstrlen) { + + prov_intercept_data_t *timers = (prov_intercept_data_t *)(existing->local); + struct timeval tv; + + if (timers == NULL) { + return 0; + } + + halt_intercept_timer(timers->start_timer, state->epoll_fd); + halt_intercept_timer(timers->end_timer, state->epoll_fd); + + gettimeofday(&tv, NULL); + + if (existing->tostart_time > 0 && existing->toend_time > 0 && + existing->tostart_time >= existing->toend_time) { + snprintf(errorstring, errorstrlen, "'starttime' parameter must be a timestamp BEFORE the 'endtime' timestamp"); + return -1; + } + + if (existing->tostart_time > 0 && existing->tostart_time > + tv.tv_sec) { + if (timers->start_hi1_sent && !timers->end_hi1_sent) { + /* start time has been shifted to a later time, but we had + * already started intercepting so we need to announce the + * deactivation. + */ + announce_hi1_notification_to_mediators(state, + existing, target_info, HI1_LI_DEACTIVATED); + } + + if (add_intercept_timer(state->epoll_fd, existing->tostart_time, + tv.tv_sec, timers, PROV_EPOLL_INTERCEPT_START) < 0) { + snprintf(errorstring, errorstrlen, + "unable to create 'intercept start' timer for intercept %s", + existing->liid); + return -1; + } + + } else if (existing->tostart_time >= 0 && !timers->start_hi1_sent) { + /* our start time has changed to a time BEFORE now, so we + * are going to start intercepting... + */ + if (existing->toend_time == 0 || existing->toend_time > tv.tv_sec) { + /* but only if the end time is still in the future (or + * indefinite... + */ + announce_hi1_notification_to_mediators(state, + existing, target_info, HI1_LI_ACTIVATED); + } + } + + if (existing->toend_time > 0 && existing->toend_time > tv.tv_sec) { + if (add_intercept_timer(state->epoll_fd, existing->toend_time, + tv.tv_sec, timers, PROV_EPOLL_INTERCEPT_HALT) < 0) { + snprintf(errorstring, errorstrlen, + "unable to create 'intercept end' timer for intercept %s", + existing->liid); + return -1; + } + if (timers->end_hi1_sent) { + if (existing->tostart_time < tv.tv_sec) { + /* the old end time had been reached, so we have already + * sent a deactivated message. But now the end time has + * been changed to further in the future so we need to + * announce that the intercept is restarting as of now. + */ + announce_hi1_notification_to_mediators(state, existing, + target_info, HI1_LI_ACTIVATED); + } + } + + timers->end_hi1_sent = 0; + } else if (existing->toend_time > 0 && !timers->end_hi1_sent + && timers->start_hi1_sent) { + /* end time has moved to a time BEFORE now, and we've had + * previously been intercepting so we need to announce that + * we've stopped. + */ + announce_hi1_notification_to_mediators(state, + existing, target_info, HI1_LI_DEACTIVATED); + + } else if (existing->toend_time == 0) { + if (timers->end_hi1_sent && existing->tostart_time < tv.tv_sec) { + announce_hi1_notification_to_mediators(state, existing, + target_info, HI1_LI_ACTIVATED); + } + /* Reset this, so we can correctly send a DEACTIVATED if the + * intercept is removed later on. + */ + timers->end_hi1_sent = 0; + + } + return 1; + +} + + +// vim: set sw=4 tabstop=4 softtabstop=4 expandtab : diff --git a/src/provisioner/intercept_timers.h b/src/provisioner/intercept_timers.h new file mode 100644 index 00000000..c4ebafa1 --- /dev/null +++ b/src/provisioner/intercept_timers.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018-2023 The University of Waikato, Hamilton, New Zealand. + * All rights reserved. + * + * This file is part of OpenLI. + * + * OpenLI was originally developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * OpenLI 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 3 of the License, or + * (at your option) any later version. + * + * OpenLI 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ + +#ifndef OPENLI_PROVISIONER_INTERCEPT_TIMERS_H_ +#define OPENLI_PROVISIONER_INTERCEPT_TIMERS_H_ + +#include "intercept.h" +#include "util.h" +#include "provisioner.h" + +int add_intercept_timer(int epoll_fd, uint64_t tssec, uint64_t now, + prov_intercept_data_t *ceptdata, int timertype); + +int halt_intercept_timer(prov_epoll_ev_t *timer, int epoll_fd); + +void free_prov_intercept_data(intercept_common_t *common, int epoll_fd); + +int add_all_intercept_timers(int epoll_fd, prov_intercept_conf_t *conf); + +int remove_all_intercept_timers(int epoll_fd, prov_intercept_conf_t *conf); + +int reset_intercept_timers(provision_state_t *state, + intercept_common_t *existing, char *target_info, + char *errorstring, int errorstrlen); + +#endif diff --git a/src/provisioner/provisioner.c b/src/provisioner/provisioner.c index 230711c4..1a513973 100644 --- a/src/provisioner/provisioner.c +++ b/src/provisioner/provisioner.c @@ -51,6 +51,7 @@ #include "openli_tls.h" #include "provisioner_client.h" #include "updateserver.h" +#include "intercept_timers.h" volatile int provisioner_halt = 0; volatile int reload_config = 0; @@ -71,6 +72,9 @@ static inline char *get_event_description(prov_epoll_ev_t *pev) { if (pev->fdtype == PROV_EPOLL_UPDATE) return "updater"; if (pev->fdtype == PROV_EPOLL_MAIN_TIMER) return "main timer"; if (pev->fdtype == PROV_EPOLL_FD_IDLETIMER) return "client idle timer"; + if (pev->fdtype == PROV_EPOLL_INTERCEPT_START) + return "intercept start timer"; + if (pev->fdtype == PROV_EPOLL_INTERCEPT_HALT) return "intercept halt timer"; return "unknown"; } @@ -1520,6 +1524,58 @@ static int process_signal(provision_state_t *state, int sigfd) { return 0; } +static int send_intercept_hi1(provision_state_t *state, prov_epoll_ev_t *pev, + hi1_notify_t hi1type) { + ipintercept_t *ipint = NULL; + emailintercept_t *mailint = NULL; + voipintercept_t *vint = NULL; + intercept_common_t *common; + struct epoll_event ev; + + char *target_info = NULL; + + if (pev == NULL) { + return -1; + } + + epoll_ctl(state->epoll_fd, EPOLL_CTL_DEL, pev->fd, &ev); + close(pev->fd); + pev->fd = -1; + if (pev->cept == NULL) { + return 0; + } + + if (pev->cept->intercept_type == OPENLI_INTERCEPT_TYPE_EMAIL) { + mailint = (emailintercept_t *)(pev->cept->intercept_ref); + target_info = list_email_targets(mailint, 256); + common = &(mailint->common); + } else if (pev->cept->intercept_type == OPENLI_INTERCEPT_TYPE_VOIP) { + vint = (voipintercept_t *)(pev->cept->intercept_ref); + target_info = list_sip_targets(vint, 256); + common = &(vint->common); + } else if (pev->cept->intercept_type == OPENLI_INTERCEPT_TYPE_IP) { + ipint = (ipintercept_t *)(pev->cept->intercept_ref); + if (ipint->username) { + target_info = strdup(ipint->username); + } + common = &(ipint->common); + } else { + return -1; + } + + if (announce_hi1_notification_to_mediators(state, common, target_info, + hi1type) < 0) { + logger(LOG_INFO, "OpenLI provisioner: unable to send HI1 notification for intercept %s (which has just %s).", + common->liid, + hi1type == HI1_LI_ACTIVATED ? "started" : "ended"); + free(target_info); + return -1; + } + + free(target_info); + return 1; +} + static void remove_idle_client(provision_state_t *state, prov_epoll_ev_t *pev) { prov_sock_state_t *cs = (prov_sock_state_t *)(pev->client->state); @@ -1612,6 +1668,12 @@ static int check_epoll_fd(provision_state_t *state, struct epoll_event *ev) { case PROV_EPOLL_MEDIATE_CONN: ret = accept_mediator(state); break; + case PROV_EPOLL_INTERCEPT_START: + ret = send_intercept_hi1(state, pev, HI1_LI_ACTIVATED); + break; + case PROV_EPOLL_INTERCEPT_HALT: + ret = send_intercept_hi1(state, pev, HI1_LI_DEACTIVATED); + break; case PROV_EPOLL_MAIN_TIMER: if (ev->events & EPOLLIN) { return 1; @@ -1906,6 +1968,12 @@ int main(int argc, char *argv[]) { } } + if ((ret = add_all_intercept_timers(provstate.epoll_fd, + &(provstate.interceptconf))) != 0) { + logger(LOG_INFO, "OpenLI: failed to create all start and end timers for configured intercepts. Exiting."); + return -1; + } + /* * XXX could also sanity check intercept->mediator mappings too... */ @@ -1944,6 +2012,7 @@ int main(int argc, char *argv[]) { run(&provstate); + remove_all_intercept_timers(provstate.epoll_fd, &(provstate.interceptconf)); clear_prov_state(&provstate); if (daemonmode && pidfile) { diff --git a/src/provisioner/provisioner.h b/src/provisioner/provisioner.h index f1f56827..5e35427f 100644 --- a/src/provisioner/provisioner.h +++ b/src/provisioner/provisioner.h @@ -49,6 +49,7 @@ typedef int MHD_socket; #endif typedef struct prov_client prov_client_t; +typedef struct prov_intercept_data prov_intercept_data_t; /** Represents an event that has been added to the epoll event set */ typedef struct prov_epoll_ev { @@ -62,6 +63,11 @@ typedef struct prov_epoll_ev { * for some event types). */ prov_client_t *client; + + /** A reference to the intercept that this fd belongs to (only used for + * some event types) + */ + prov_intercept_data_t *cept; } prov_epoll_ev_t; @@ -98,6 +104,12 @@ enum { /** Idle timeout for a client has expired */ PROV_EPOLL_FD_IDLETIMER, + + /** Timer to fire when a delayed intercept begins */ + PROV_EPOLL_INTERCEPT_START, + + /** Timer to fire when an intercept is scheduled to cease */ + PROV_EPOLL_INTERCEPT_HALT, }; /** A LIID->agency mapping, used to ensure mediators route the intercept @@ -229,6 +241,17 @@ typedef struct mediator_address { UT_hash_handle hh; } mediator_address_t; +struct prov_intercept_data { + prov_epoll_ev_t *start_timer; + prov_epoll_ev_t *end_timer; + + openli_intercept_types_t intercept_type; + void *intercept_ref; + + uint8_t start_hi1_sent; + uint8_t end_hi1_sent; +}; + /** Global state for the provisioner instance */ typedef struct prov_state { diff --git a/src/provisioner/updateserver_jsonparsing.c b/src/provisioner/updateserver_jsonparsing.c index 8dc49da6..b62c4aa4 100644 --- a/src/provisioner/updateserver_jsonparsing.c +++ b/src/provisioner/updateserver_jsonparsing.c @@ -28,11 +28,13 @@ #include #include +#include #include "provisioner.h" #include "updateserver.h" #include "logger.h" #include "util.h" +#include "intercept_timers.h" struct json_agency { struct json_object *hi3addr; @@ -272,19 +274,28 @@ static inline void new_intercept_liidmapping(provision_state_t *state, static int parse_intercept_common_json(struct json_intercept *jsonp, intercept_common_t *common, const char *cepttype, - update_con_info_t *cinfo, bool is_new) { + update_con_info_t *cinfo, bool is_new, int epoll_fd) { int parseerr = 0; char *encryptmethodstring = NULL; + struct timeval tv; + prov_intercept_data_t *timers = NULL; if (is_new) { common->tostart_time = 0; common->toend_time = 0; common->encrypt = OPENLI_PAYLOAD_ENCRYPTION_NONE; + timers = calloc(1, sizeof(prov_intercept_data_t)); + timers->start_timer = NULL; + timers->end_timer = NULL; + timers->start_hi1_sent = 0; + timers->end_hi1_sent = 0; + common->local = timers; } else { common->tostart_time = (uint64_t)-1; common->toend_time = (uint64_t)-1; common->encrypt = OPENLI_PAYLOAD_ENCRYPTION_NOT_SPECIFIED; + common->local = NULL; } if (common->liid == NULL) { @@ -334,6 +345,35 @@ static int parse_intercept_common_json(struct json_intercept *jsonp, return -1; } } + + /* If we are new, we can just go ahead and add any timers that + * we need for this intercept. + */ + if (timers && (common->tostart_time > 0 || common->toend_time > 0)) { + gettimeofday(&tv, NULL); + + if (common->tostart_time > 0 && common->toend_time > 0 && + common->tostart_time >= common->toend_time) { + snprintf(cinfo->answerstring, 4096, "'starttime' parameter must be a timestamp BEFORE the 'endtime' timestamp"); + return -1; + } + + if (common->tostart_time > 0 && common->tostart_time > tv.tv_sec) { + if (add_intercept_timer(epoll_fd, common->tostart_time, + tv.tv_sec, timers, PROV_EPOLL_INTERCEPT_START) < 0) { + snprintf(cinfo->answerstring, 4096, "unable to create a 'intercept start' timer for intercept %s", common->liid); + return -1; + } + + } + if (common->toend_time > 0 && common->toend_time > tv.tv_sec) { + if (add_intercept_timer(epoll_fd, common->toend_time, + tv.tv_sec, timers, PROV_EPOLL_INTERCEPT_HALT) < 0) { + snprintf(cinfo->answerstring, 4096, "unable to create a 'intercept end' timer for intercept %s", common->liid); + return -1; + } + } + } } @@ -345,9 +385,10 @@ static int parse_intercept_common_json(struct json_intercept *jsonp, static int update_intercept_common(intercept_common_t *parsed, intercept_common_t *existing, int *changed, int *agencychanged, - provision_state_t *state, update_con_info_t *cinfo) { + int *timeschanged, provision_state_t *state, update_con_info_t *cinfo) { payload_encryption_method_t enc; + prov_intercept_data_t *timers = (prov_intercept_data_t *)(existing->local); /* Check if encryption options are valid -- if not, roll back without * changing anything. @@ -382,9 +423,9 @@ static int update_intercept_common(intercept_common_t *parsed, if (*agencychanged) { new_intercept_liidmapping(state, existing->targetagency, existing->liid); + timers->start_hi1_sent = 0; } - if (parsed->encrypt != existing->encrypt && parsed->encrypt != OPENLI_PAYLOAD_ENCRYPTION_NOT_SPECIFIED) { *changed = 1; @@ -393,7 +434,7 @@ static int update_intercept_common(intercept_common_t *parsed, MODIFY_STRING_MEMBER(parsed->encryptkey, existing->encryptkey, changed); if (compare_intercept_times(parsed, existing) == 1) { - *changed = 1; + *timeschanged = 1; } return 0; @@ -417,6 +458,7 @@ int remove_voip_intercept(update_con_info_t *cinfo, provision_state_t *state, target_info = list_sip_targets(found, 256); announce_hi1_notification_to_mediators(state, &(found->common), target_info, HI1_LI_DEACTIVATED); + free_prov_intercept_data(&(found->common), state->epoll_fd); free_single_voipintercept(found); if (target_info) { free(target_info); @@ -447,6 +489,7 @@ int remove_email_intercept(update_con_info_t *cinfo, provision_state_t *state, target_info = list_email_targets(found, 256); announce_hi1_notification_to_mediators(state, &(found->common), target_info, HI1_LI_DEACTIVATED); + free_prov_intercept_data(&(found->common), state->epoll_fd); free_single_emailintercept(found); if (target_info) { free(target_info); @@ -475,6 +518,7 @@ int remove_ip_intercept(update_con_info_t *cinfo, provision_state_t *state, 0); announce_hi1_notification_to_mediators(state, &(found->common), found->username, HI1_LI_DEACTIVATED); + free_prov_intercept_data(&(found->common), state->epoll_fd); free_single_ipintercept(found); logger(LOG_INFO, "OpenLI: removed IP intercept '%s' via update socket.", @@ -995,6 +1039,7 @@ int add_new_emailintercept(update_con_info_t *cinfo, provision_state_t *state) { int parseerr = 0; char *target_info; char *delivcompressstring = NULL; + prov_intercept_data_t *timers = NULL; INIT_JSON_INTERCEPT_PARSING extract_intercept_json_objects(&emailjson, parsed); @@ -1005,10 +1050,14 @@ int add_new_emailintercept(update_con_info_t *cinfo, provision_state_t *state) { mailint->targets = NULL; if (parse_intercept_common_json(&emailjson, &(mailint->common), - "Email intercept", cinfo, true) < 0) { + "Email intercept", cinfo, true, state->epoll_fd) < 0) { goto cepterr; } + timers = (prov_intercept_data_t *)(mailint->common.local); + timers->intercept_type = OPENLI_INTERCEPT_TYPE_EMAIL; + timers->intercept_ref = (void *)mailint; + EXTRACT_JSON_STRING_PARAM("delivercompressed", "email intercept", emailjson.delivercompressed, delivcompressstring, &parseerr, false); @@ -1108,6 +1157,7 @@ int add_new_voipintercept(update_con_info_t *cinfo, provision_state_t *state) { voipintercept_t *vint = NULL; int r; char *target_info; + prov_intercept_data_t *timers = NULL; INIT_JSON_INTERCEPT_PARSING extract_intercept_json_objects(&voipjson, parsed); @@ -1125,9 +1175,12 @@ int add_new_voipintercept(update_con_info_t *cinfo, provision_state_t *state) { } if (parse_intercept_common_json(&voipjson, &(vint->common), - "VOIP intercept", cinfo, true) < 0) { + "VOIP intercept", cinfo, true, state->epoll_fd) < 0) { goto cepterr; } + timers = (prov_intercept_data_t *)(vint->common.local); + timers->intercept_type = OPENLI_INTERCEPT_TYPE_VOIP; + timers->intercept_ref = (void *)vint; r = 0; if (voipjson.siptargets != NULL) { @@ -1218,6 +1271,7 @@ int add_new_ipintercept(update_con_info_t *cinfo, provision_state_t *state) { char *accessstring = NULL; char *radiusidentstring = NULL; ipintercept_t *ipint = NULL; + prov_intercept_data_t *timers = NULL; INIT_JSON_INTERCEPT_PARSING extract_intercept_json_objects(&ipjson, parsed); @@ -1229,9 +1283,13 @@ int add_new_ipintercept(update_con_info_t *cinfo, provision_state_t *state) { ipint->options = 0; if (parse_intercept_common_json(&ipjson, &(ipint->common), - "IP intercept", cinfo, true) < 0) { + "IP intercept", cinfo, true, state->epoll_fd) < 0) { goto cepterr; } + timers = (prov_intercept_data_t *)(ipint->common.local); + timers->intercept_type = OPENLI_INTERCEPT_TYPE_IP; + timers->intercept_ref = (void *)ipint; + EXTRACT_JSON_INT_PARAM("vendmirrorid", "IP intercept", ipjson.vendmirrorid, ipint->vendmirrorid, &parseerr, false); EXTRACT_JSON_STRING_PARAM("user", "IP intercept", ipjson.user, @@ -1405,7 +1463,7 @@ int modify_emailintercept(update_con_info_t *cinfo, provision_state_t *state) { char *delivcompressstring = NULL; char *liidstr = NULL; - int parseerr = 0, changed = 0, agencychanged = 0; + int parseerr = 0, changed = 0, agencychanged = 0, timeschanged = 0; INIT_JSON_INTERCEPT_PARSING extract_intercept_json_objects(&emailjson, parsed); @@ -1435,12 +1493,12 @@ int modify_emailintercept(update_con_info_t *cinfo, provision_state_t *state) { mailint->targets = NULL; if (parse_intercept_common_json(&emailjson, &(mailint->common), - "Email intercept", cinfo, false) < 0) { + "Email intercept", cinfo, false, state->epoll_fd) < 0) { goto cepterr; } if (update_intercept_common(&(mailint->common), &(found->common), - &changed, &agencychanged, state, cinfo) < 0) { + &changed, &agencychanged, ×changed, state, cinfo) < 0) { goto cepterr; } @@ -1486,15 +1544,25 @@ int modify_emailintercept(update_con_info_t *cinfo, provision_state_t *state) { changed = 1; } - if (changed) { + if ((changed || timeschanged) && !agencychanged) { modify_existing_intercept_options(state, (void *)found, OPENLI_PROTO_MODIFY_EMAILINTERCEPT); } - if (changedtargets) { + if (changedtargets || timeschanged || agencychanged) { target_info = list_email_targets(found, 256); - announce_hi1_notification_to_mediators(state, &(found->common), - target_info, HI1_LI_MODIFIED); + if (agencychanged) { + announce_hi1_notification_to_mediators(state, &(found->common), + target_info, HI1_LI_ACTIVATED); + } else { + announce_hi1_notification_to_mediators(state, &(found->common), + target_info, HI1_LI_MODIFIED); + } + if (timeschanged) { + reset_intercept_timers(state, &(found->common), + target_info, cinfo->answerstring, 4096); + } + if (target_info) { free(target_info); } @@ -1536,6 +1604,7 @@ int modify_voipintercept(update_con_info_t *cinfo, provision_state_t *state) { char *liidstr = NULL, *target_info; int changed = 0, agencychanged = 0, parseerr = 0; + int timeschanged = 0; INIT_JSON_INTERCEPT_PARSING extract_intercept_json_objects(&voipjson, parsed); @@ -1565,12 +1634,12 @@ int modify_voipintercept(update_con_info_t *cinfo, provision_state_t *state) { vint->targets = libtrace_list_init(sizeof(openli_sip_identity_t *)); if (parse_intercept_common_json(&voipjson, &(vint->common), - "VOIP intercept", cinfo, false) < 0) { + "VOIP intercept", cinfo, false, state->epoll_fd) < 0) { goto cepterr; } if (update_intercept_common(&(vint->common), &(found->common), - &changed, &agencychanged, state, cinfo) < 0) { + &changed, &agencychanged, ×changed, state, cinfo) < 0) { goto cepterr; } @@ -1597,15 +1666,26 @@ int modify_voipintercept(update_con_info_t *cinfo, provision_state_t *state) { * */ - if (changed) { + if ((changed || timeschanged) && !agencychanged) { modify_existing_intercept_options(state, (void *)found, OPENLI_PROTO_MODIFY_VOIPINTERCEPT); } - if (changedtargets) { + if (changedtargets || timeschanged || agencychanged) { target_info = list_sip_targets(found, 256); - announce_hi1_notification_to_mediators(state, &(found->common), - target_info, HI1_LI_MODIFIED); + if (agencychanged) { + announce_hi1_notification_to_mediators(state, &(found->common), + target_info, HI1_LI_ACTIVATED); + } else { + announce_hi1_notification_to_mediators(state, &(found->common), + target_info, HI1_LI_MODIFIED); + } + + if (timeschanged) { + reset_intercept_timers(state, &(found->common), target_info, + cinfo->answerstring, 4096); + } + if (target_info) { free(target_info); } @@ -1647,6 +1727,7 @@ int modify_ipintercept(update_con_info_t *cinfo, provision_state_t *state) { char *accessstring = NULL; char *radiusidentstring = NULL; int parseerr = 0, changed = 0, agencychanged = 0; + int timeschanged = 0; INIT_JSON_INTERCEPT_PARSING extract_intercept_json_objects(&ipjson, parsed); @@ -1677,12 +1758,12 @@ int modify_ipintercept(update_con_info_t *cinfo, provision_state_t *state) { ipint->common.liid = liidstr; if (parse_intercept_common_json(&ipjson, &(ipint->common), - "IP intercept", cinfo, false) < 0) { + "IP intercept", cinfo, false, state->epoll_fd) < 0) { goto cepterr; } if (update_intercept_common(&(ipint->common), &(found->common), - &changed, &agencychanged, state, cinfo) < 0) { + &changed, &agencychanged, ×changed, state, cinfo) < 0) { goto cepterr; } @@ -1780,13 +1861,17 @@ int modify_ipintercept(update_con_info_t *cinfo, provision_state_t *state) { found->username, HI1_LI_ACTIVATED); } - if (changed) { + if (changed || timeschanged) { modify_existing_intercept_options(state, (void *)found, OPENLI_PROTO_MODIFY_IPINTERCEPT); if (!agencychanged) { announce_hi1_notification_to_mediators(state, &(found->common), found->username, HI1_LI_MODIFIED); } + if (timeschanged) { + reset_intercept_timers(state, &(found->common), found->username, + cinfo->answerstring, 4096); + } } logger(LOG_INFO,