diff --git a/README.md b/README.md index 71c31eb0..344c64b7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ OpenLI -- open source ETSI-compliant Lawful Intercept software -Version: 1.1.0 +Version: 1.1.1 --------------------------------------------------------------------------- diff --git a/configure.ac b/configure.ac index b0a51622..703dad47 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # Super primitive configure script -AC_INIT([openli],[1.1.0],[shane@alcock.co.nz]) +AC_INIT([openli],[1.1.1],[shane@alcock.co.nz]) AM_INIT_AUTOMAKE([subdir-objects]) AC_CONFIG_SRCDIR(src/collector/collector.c) @@ -81,19 +81,24 @@ if test "x$enable_collector" != "xno"; then COLLECTOR_LIBS="$COLLECTOR_LIBS -losipparser2 -lb64" fi -if test "x$enable_provisioner" != "xno"; then +if test "x$enable_provisioner" != "xno" -o "x$enable_collector" != "xno"; then AC_CHECK_LIB([microhttpd], [MHD_destroy_post_processor],libmicrohttpd_found=1,libmicrohttpd_found=0) if test "$libmicrohttpd_found" = 0; then AC_MSG_ERROR(Required library libmicrohttpd not found; use LDFLAGS to specify library location) fi + + COLLECTOR_LIBS="$COLLECTOR_LIBS -lmicrohttpd" + PROVISIONER_LIBS="$PROVISIONER_LIBS -lmicrohttpd" +fi + +if test "x$enable_provisioner" != "xno"; then AC_CHECK_LIB([json-c], [json_tokener_new],libjsonc_found=1,libjsonc_found=0) if test "$libjsonc_found" = 0; then AC_MSG_ERROR(Required library libjson-c not found; use LDFLAGS to specify library location) fi - PROVISIONER_LIBS="$PROVISIONER_LIBS -lmicrohttpd -ljson-c" - COLLECTOR_LIBS="$COLLECTOR_LIBS -lmicrohttpd -ljson-c" + PROVISIONER_LIBS="$PROVISIONER_LIBS -ljson-c" if test "x$libssl11_found" = "x1"; then AC_CHECK_LIB([sqlcipher], [sqlite3_key], sqlcipher_found=1, sqlcipher_found=0) diff --git a/debian/changelog b/debian/changelog index 7251f169..34503c96 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,23 @@ +openli (1.1.1-1) unstable; urgency=medium + + * Add ability to encrypt CC and IRI payload, as per Annex G of + ETSI TS 102 232-1 (AES-192-CBC encryption only thus far). + * Fix bug where certain intercept config changes were not always + passed on to collectors if the changes occurred while the + provisioner was down. + * Fix double free bug when halting the VOIP sync thread for a + collector. + * Fix bug where a RADIUS session could produce CCs but not IRIs, + if the Username AVP happened to match a target CSID. + * Fix linking failure if the collector is built on its own. + * Correct various problems with the IMAP parsing for FETCH replies. + * Fix segmentation faults when the email ingestion socket receives + an incomplete message. + * Fix memory errors in the REST API when a field is assigned an + empty string value. + + -- Shane Alcock Mon, 31 Jul 2023 11:26:50 +1200 + openli (1.1.0-1) unstable; urgency=medium Changes since 1.0.15 release: diff --git a/doc/ProvisionerDoc.md b/doc/ProvisionerDoc.md index 942460ea..5de09727 100644 --- a/doc/ProvisionerDoc.md +++ b/doc/ProvisionerDoc.md @@ -536,12 +536,18 @@ An email target is a JSON object that contains just a single field: * `address` -- the email address of the target +--- + All intercept types also support the following optional key-value elements: * `starttime` -- do not intercept any traffic observed before this - unix timestamp + unix timestamp. Default is 0, which will + intercept all traffic from the moment the + intercept is provisioned. * `endtime` -- do not intercept any traffic observed after this - unix timestamp + unix timestamp. Default is 0, which will + continue to intercept traffic until the intercept + is explicitly halted. * `outputhandovers` -- If set to "all", then both IRI and CCs will be produced by OpenLI for this intercept. If set to "irionly", then only IRIs will be @@ -549,6 +555,18 @@ All intercept types also support the following optional key-value elements: If set to "cconly", then only CCs will be produced by OpenLI for this intercept. The default setting is "all". +* `payloadencryption` -- Specifies if the CC and IRI contents should be + encrypted and, if so, which encryption method to + use. If set to "none", no encryption is performed. + The encryption method supported right now is + "aes-192-cbc". + The default setting is "none". +* `encryptionkey` -- The encryption key to use when encrypting CC and + IRI contents. This option is mandatory if + `payloadencryption` is NOT set to "none". The + ideal key length is 24 characters. Shorter keys + will be padded with null bytes, longer keys will be + truncated to 24 characters. ### SIP Target Specifics diff --git a/doc/exampleconfigs/running-intercept-example.yaml b/doc/exampleconfigs/running-intercept-example.yaml index 696f07cd..e69f4e3c 100644 --- a/doc/exampleconfigs/running-intercept-example.yaml +++ b/doc/exampleconfigs/running-intercept-example.yaml @@ -132,6 +132,10 @@ ipintercepts: # phone user, using GTPv2 packets to detect the start and end of the target's # sessions. Note that the accesstype must be set to "mobile". The user field # is set to the target's MSISDN (i.e. phone number). +# +# This intercept also wraps the intercepted traffic in an Encryption Container, +# which may be required in some jurisdictions. Any intercept type can use +# payload encryption. - liid: TH473NNOQ # LIID, should be provided by requesting agency authcountrycode: NZ # Authorisation country code deliverycountrycode: NZ # Delivery country code @@ -139,6 +143,9 @@ ipintercepts: mediator: 6001 # ID of the mediator to send intercept via agencyid: "Police" # ID of agency to send intercept to accesstype: "mobile" # Must be "mobile" for UMTS intercepts + payloadencryption: "aes-192-cbc" # Encrypt IP content using AES-192-CBC + encryptionkey: "alongencryptionkeyisgood" # Key to use for encryption, + # should be provided by the agency # This intercept demonstrates how to configure an intercept for a target that # has static IP allocations. The target has both an IPv4 and IPv6 allocation diff --git a/rpm/openli.spec b/rpm/openli.spec index 0e8cb0ae..096e2aad 100644 --- a/rpm/openli.spec +++ b/rpm/openli.spec @@ -1,5 +1,5 @@ Name: openli -Version: 1.1.0 +Version: 1.1.1 Release: 1%{?dist} Summary: Software for performing ETSI-compliant lawful intercept @@ -282,6 +282,9 @@ fi %changelog +* Mon Jul 31 2023 Shane Alcock - 1.1.1-1 +- Updated for 1.1.1 release + * Fri May 26 2023 Shane Alcock - 1.1.0-1 - Updated for 1.1.0 release diff --git a/src/Makefile.am b/src/Makefile.am index ecd60253..9e58ca33 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -65,6 +65,9 @@ openlicollector_SOURCES=collector/collector.c configparser.c configparser.h \ collector/emailprotocols/imap.c \ collector/emailprotocols/pop3.c \ collector/emailiri.c collector/emailiri.h collector/emailcc.c \ + collector/etsiencoding/etsiencoding.h \ + collector/etsiencoding/etsiencoding.c \ + collector/etsiencoding/encryptcontainer.c \ $(PLUGIN_SRCS) openlicollector_LDADD = @ADD_LIBS@ -L$(abs_top_srcdir)/extlib/libpatricia/.libs diff --git a/src/collector/collector.c b/src/collector/collector.c index bc807d41..13731b23 100644 --- a/src/collector/collector.c +++ b/src/collector/collector.c @@ -1988,7 +1988,11 @@ int main(int argc, char *argv[]) { glob->encoders[i].freegenerics = NULL; glob->encoders[i].saved_intercept_templates = NULL; glob->encoders[i].saved_global_templates = NULL; + glob->encoders[i].saved_encryption_templates = NULL; + glob->encoders[i].encrypt_byte_counter = 0; + glob->encoders[i].encrypt_byte_startts = 0; + glob->encoders[i].evp_ctx = NULL; glob->encoders[i].seqtrackers = glob->seqtracker_threads; glob->encoders[i].forwarders = glob->forwarding_threads; diff --git a/src/collector/collector_base.h b/src/collector/collector_base.h index 39d65fab..431afff2 100644 --- a/src/collector/collector_base.h +++ b/src/collector/collector_base.h @@ -36,6 +36,7 @@ #include #include #include +#include #include "export_shared.h" #include "etsili_core.h" @@ -252,6 +253,11 @@ typedef struct encoder_state { Pvoid_t saved_intercept_templates; Pvoid_t saved_global_templates; + Pvoid_t saved_encryption_templates; + + uint32_t encrypt_byte_counter; + uint32_t encrypt_byte_startts; + EVP_CIPHER_CTX *evp_ctx; int seqtrackers; int forwarders; @@ -266,6 +272,8 @@ typedef struct encoder_job { openli_export_recv_t *origreq; char *liid; uint8_t cept_version; + payload_encryption_method_t encryptmethod; + char *encryptkey; } PACKED openli_encoding_job_t; void destroy_encoder_worker(openli_encoder_t *enc); diff --git a/src/collector/collector_publish.h b/src/collector/collector_publish.h index 3500c72a..7d20bc07 100644 --- a/src/collector/collector_publish.h +++ b/src/collector/collector_publish.h @@ -153,6 +153,8 @@ typedef struct published_intercept_msg { char *authcc; char *delivcc; int seqtrackerid; + payload_encryption_method_t encryptmethod; + char *encryptkey; } published_intercept_msg_t; typedef struct provisioner_msg { diff --git a/src/collector/collector_push_messaging.c b/src/collector/collector_push_messaging.c index 8d5b35fb..5dccb612 100644 --- a/src/collector/collector_push_messaging.c +++ b/src/collector/collector_push_messaging.c @@ -35,6 +35,30 @@ #include "intercept.h" #include "internetaccess.h" +static inline void update_intercept_common(intercept_common_t *found, + intercept_common_t *replace) { + + char *tmp; + tmp = found->authcc; + found->authcc = replace->authcc; + found->authcc_len = replace->authcc_len; + replace->authcc = tmp; + + tmp = found->delivcc; + found->delivcc = replace->delivcc; + found->delivcc_len = replace->delivcc_len; + replace->delivcc = tmp; + + found->tostart_time = replace->tostart_time; + found->toend_time = replace->toend_time; + found->tomediate = replace->tomediate; + found->encrypt = replace->encrypt; + + tmp = found->encryptkey; + found->encryptkey = replace->encryptkey; + replace->encryptkey = tmp; +} + static int remove_rtp_stream(colthread_local_t *loc, char *rtpstreamkey) { rtpstreaminf_t *rtp; @@ -191,7 +215,12 @@ static int add_ipv4_intercept(colthread_local_t *loc, ipsession_t *sess) { HASH_FIND(hh, tgt->intercepts, sess->streamkey, strlen(sess->streamkey), check); - assert(check == NULL); + if (check) { + logger(LOG_INFO, "OpenLI: encountered duplicate stream key '%s' for address %u -- replacing...", sess->streamkey, tgt->address); + HASH_DELETE(hh, tgt->intercepts, check); + free_single_ipsession(check); + } + HASH_ADD_KEYPTR(hh, tgt->intercepts, sess->streamkey, strlen(sess->streamkey), sess); @@ -242,7 +271,11 @@ static int add_ipv6_intercept(colthread_local_t *loc, ipsession_t *sess) { HASH_FIND(hh, tgt->intercepts, sess->streamkey, strlen(sess->streamkey), check); - assert(check == NULL); + if (check) { + logger(LOG_INFO, "OpenLI: encountered duplicate stream key '%s' for address %s -- replacing...", sess->streamkey, prefixstr); + HASH_DELETE(hh, tgt->intercepts, check); + free_single_ipsession(check); + } HASH_ADD_KEYPTR(hh, tgt->intercepts, sess->streamkey, strlen(sess->streamkey), sess); @@ -278,26 +311,13 @@ static int update_ipv4_intercept(colthread_local_t *loc, ipsession_t *toup) { ipsession_t *found; ipv4_target_t *v4; - char *tmp; found = find_ipv4_intercept(loc, toup, &v4); if (!found) { return 0; } - tmp = found->common.authcc; - found->common.authcc = toup->common.authcc; - found->common.authcc_len = toup->common.authcc_len; - toup->common.authcc = tmp; - - tmp = found->common.delivcc; - found->common.delivcc = toup->common.delivcc; - found->common.delivcc_len = toup->common.delivcc_len; - toup->common.delivcc = tmp; - - found->common.tostart_time = toup->common.tostart_time; - found->common.toend_time = toup->common.toend_time; - found->common.tomediate = toup->common.tomediate; + update_intercept_common(&(found->common), &(toup->common)); return 1; } @@ -360,27 +380,13 @@ static int update_ipv6_intercept(colthread_local_t *loc, ipsession_t *toup) { ipsession_t *found; ipv6_target_t *v6; char prefixstr[100]; - char *tmp; found = find_ipv6_intercept(loc, toup, &v6, prefixstr, 100); if (!found) { return 0; } - tmp = found->common.authcc; - found->common.authcc = toup->common.authcc; - found->common.authcc_len = toup->common.authcc_len; - toup->common.authcc = tmp; - - tmp = found->common.delivcc; - found->common.delivcc = toup->common.delivcc; - found->common.delivcc_len = toup->common.delivcc_len; - toup->common.delivcc = tmp; - - found->common.tostart_time = toup->common.tostart_time; - found->common.toend_time = toup->common.toend_time; - found->common.tomediate = toup->common.tomediate; - + update_intercept_common(&(found->common), &(toup->common)); return 1; } @@ -792,7 +798,6 @@ void handle_change_voip_intercept(libtrace_thread_t *t, colthread_local_t *loc, rtpstreaminf_t *tochange) { rtpstreaminf_t *rtp; - char *tmp; if (tochange->streamkey == NULL) { return; @@ -807,20 +812,7 @@ void handle_change_voip_intercept(libtrace_thread_t *t, colthread_local_t *loc, return; } - tmp = rtp->common.authcc; - rtp->common.authcc = tochange->common.authcc; - rtp->common.authcc_len = tochange->common.authcc_len; - tochange->common.authcc = tmp; - - tmp = rtp->common.delivcc; - rtp->common.delivcc = tochange->common.delivcc; - rtp->common.delivcc_len = tochange->common.delivcc_len; - tochange->common.delivcc = tmp; - - rtp->common.tostart_time = tochange->common.tostart_time; - rtp->common.toend_time = tochange->common.toend_time; - rtp->common.tomediate = tochange->common.tomediate; - + update_intercept_common(&(rtp->common), &(tochange->common)); free_single_rtpstream(tochange); } @@ -829,7 +821,6 @@ void handle_change_vendmirror_intercept(libtrace_thread_t *t, vendmirror_intercept_t *found; vendmirror_intercept_list_t *parent; - char *tmp; HASH_FIND(hh, loc->activemirrorintercepts, &(vend->sessionid), sizeof(vend->sessionid), parent); @@ -848,19 +839,7 @@ void handle_change_vendmirror_intercept(libtrace_thread_t *t, return; } - tmp = found->common.authcc; - found->common.authcc = vend->common.authcc; - found->common.authcc_len = vend->common.authcc_len; - vend->common.authcc = tmp; - - tmp = found->common.delivcc; - found->common.delivcc = vend->common.delivcc; - found->common.delivcc_len = vend->common.delivcc_len; - vend->common.delivcc = tmp; - - found->common.tostart_time = vend->common.tostart_time; - found->common.toend_time = vend->common.toend_time; - found->common.tomediate = vend->common.tomediate; + update_intercept_common(&(found->common), &(vend->common)); free_single_vendmirror_intercept(vend); } @@ -868,25 +847,11 @@ void handle_change_iprange_intercept(libtrace_thread_t *t, colthread_local_t *loc, staticipsession_t *ipr) { staticipsession_t *sessrec; - char *tmp; HASH_FIND(hh, loc->activestaticintercepts, ipr->key, strlen(ipr->key), sessrec); if (sessrec) { - sessrec->common.tostart_time = ipr->common.tostart_time; - sessrec->common.toend_time = ipr->common.toend_time; - sessrec->common.tomediate = ipr->common.tomediate; - - tmp = sessrec->common.authcc; - sessrec->common.authcc = ipr->common.authcc; - sessrec->common.authcc_len = ipr->common.authcc_len; - ipr->common.authcc = tmp; - - tmp = sessrec->common.delivcc; - sessrec->common.delivcc = ipr->common.delivcc; - sessrec->common.delivcc_len = ipr->common.delivcc_len; - ipr->common.delivcc = tmp; - + update_intercept_common(&(sessrec->common), &(ipr->common)); } free_single_staticipsession(ipr); diff --git a/src/collector/collector_seqtracker.c b/src/collector/collector_seqtracker.c index 4868f7f6..8b78709a 100644 --- a/src/collector/collector_seqtracker.c +++ b/src/collector/collector_seqtracker.c @@ -44,6 +44,9 @@ static inline void free_intercept_msg(exporter_intercept_msg_t *msg) { if (msg->delivcc) { free(msg->delivcc); } + if (msg->encryptkey) { + free(msg->encryptkey); + } } static inline void free_cinsequencing(exporter_intercept_state_t *intstate) { @@ -192,12 +195,15 @@ static void track_new_intercept(seqtracker_thread_data_t *seqdata, free(cept->liid); free(intstate->details.authcc); free(intstate->details.delivcc); + free(intstate->details.encryptkey); /* leave the CIN seqno state as is for now */ intstate->details.authcc = cept->authcc; intstate->details.delivcc = cept->delivcc; intstate->details.authcc_len = strlen(cept->authcc); intstate->details.delivcc_len = strlen(cept->delivcc); + intstate->details.encryptkey = cept->encryptkey; + intstate->details.encryptmethod = cept->encryptmethod; intstate->version ++; } else { @@ -210,6 +216,8 @@ static void track_new_intercept(seqtracker_thread_data_t *seqdata, intstate->details.liid_len = strlen(cept->liid); intstate->details.authcc_len = strlen(cept->authcc); intstate->details.delivcc_len = strlen(cept->delivcc); + intstate->details.encryptkey = cept->encryptkey; + intstate->details.encryptmethod = cept->encryptmethod; intstate->cinsequencing = NULL; intstate->version = 0; @@ -260,11 +268,20 @@ static int modify_tracked_intercept(seqtracker_thread_data_t *seqdata, free(intstate->details.authcc); } intstate->details.authcc = msg->authcc; + intstate->details.authcc_len = strlen(msg->authcc); if (intstate->details.delivcc) { free(intstate->details.delivcc); } intstate->details.delivcc = msg->delivcc; + intstate->details.delivcc_len = strlen(msg->delivcc); + + if (intstate->details.encryptkey) { + free(intstate->details.encryptkey); + } + intstate->details.encryptkey = msg->encryptkey; + intstate->details.encryptmethod = msg->encryptmethod; + remove_preencoded(seqdata, intstate); preencode_etsi_fields(seqdata, intstate); @@ -301,6 +318,9 @@ static int remove_tracked_intercept(seqtracker_thread_data_t *seqdata, if (msg->delivcc) { free(msg->delivcc); } + if (msg->encryptkey) { + free(msg->encryptkey); + } free_intercept_state(seqdata, intstate); return 1; } @@ -357,6 +377,12 @@ static int run_encoding_job(seqtracker_thread_data_t *seqdata, job.cinstr = strdup(cinseq->cin_string); job.cin = (int64_t)cin; job.cept_version = intstate->version; + job.encryptmethod = intstate->details.encryptmethod; + if (intstate->details.encryptkey) { + job.encryptkey = strdup(intstate->details.encryptkey); + } else { + job.encryptkey = NULL; + } if (recvd->type == OPENLI_EXPORT_IPMMCC || recvd->type == OPENLI_EXPORT_IPCC || diff --git a/src/collector/collector_sync.c b/src/collector/collector_sync.c index 114c2b2b..20771635 100644 --- a/src/collector/collector_sync.c +++ b/src/collector/collector_sync.c @@ -971,9 +971,14 @@ static void push_ipintercept_update_to_threads(collector_sync_t *sync, ipint->common.delivcc_len = modified->common.delivcc_len; modified->common.delivcc = tmp; + tmp = ipint->common.encryptkey; + ipint->common.encryptkey = modified->common.encryptkey; + modified->common.encryptkey = tmp; + ipint->common.tostart_time = modified->common.tostart_time; ipint->common.toend_time = modified->common.toend_time; ipint->common.tomediate = modified->common.tomediate; + ipint->common.encrypt = modified->common.encrypt; /* Update all static IP ranges for this intercept */ HASH_ITER(hh, ipint->statics, ipr, tmpr) { @@ -1141,6 +1146,12 @@ static inline openli_export_recv_t *create_intercept_details_msg( expmsg->data.cept.liid = strdup(common->liid); expmsg->data.cept.authcc = strdup(common->authcc); expmsg->data.cept.delivcc = strdup(common->delivcc); + expmsg->data.cept.encryptmethod = common->encrypt; + if (common->encryptkey) { + expmsg->data.cept.encryptkey = strdup(common->encryptkey); + } else { + expmsg->data.cept.encryptkey = NULL; + } expmsg->data.cept.seqtrackerid = common->seqtrackerid; return expmsg; @@ -1302,29 +1313,12 @@ static void remove_ip_intercept(collector_sync_t *sync, ipintercept_t *ipint) { free_single_ipintercept(ipint); } -static int modify_ipintercept(collector_sync_t *sync, uint8_t *intmsg, - uint16_t msglen) { +static int update_modified_intercept(collector_sync_t *sync, + ipintercept_t *ipint, ipintercept_t *modified) { - ipintercept_t *ipint, *modified; openli_export_recv_t *expmsg; int changed = 0; - - modified = calloc(1, sizeof(ipintercept_t)); - - if (decode_ipintercept_modify(intmsg, msglen, modified) == -1) { - if (sync->instruct_log) { - logger(LOG_INFO, - "OpenLI: received invalid IP intercept modification from provisioner."); - } - return -1; - } - - HASH_FIND(hh_liid, sync->ipintercepts, modified->common.liid, - modified->common.liid_len, ipint); - - if (!ipint) { - return insert_new_ipintercept(sync, modified); - } + int encodingchanged = 0; if (strcmp(ipint->username, modified->username) != 0) { push_ipintercept_halt_to_threads(sync, ipint); @@ -1353,8 +1347,6 @@ static int modify_ipintercept(collector_sync_t *sync, uint8_t *intmsg, ipint->common.toend_time != modified->common.toend_time) { logger(LOG_INFO, "OpenLI: IP intercept %s has changed start / end times -- now %lu, %lu", ipint->common.liid, modified->common.tostart_time, modified->common.toend_time); - ipint->common.tostart_time = modified->common.tostart_time; - ipint->common.toend_time = modified->common.toend_time; update_intercept_time_event(&(sync->upcoming_intercept_events), ipint, &(ipint->common), &(modified->common)); changed = 1; @@ -1367,22 +1359,61 @@ static int modify_ipintercept(collector_sync_t *sync, uint8_t *intmsg, logger(LOG_INFO, "OpenLI: IP intercept %s has changed mediation mode to: %s", ipint->common.liid, space); - ipint->common.tomediate = modified->common.tomediate; changed = 1; + } + if (ipint->common.encrypt != modified->common.encrypt) { + char space[1024]; + intercept_encryption_mode_as_string(modified->common.encrypt, space, + 1024); + logger(LOG_INFO, + "OpenLI: IP intercept %s has changed encryption mode to: %s", + ipint->common.liid, space); + changed = 1; + encodingchanged = 1; + goto actonchange; + } + + if (ipint->common.encryptkey && modified->common.encryptkey) { + if (strcmp(ipint->common.encryptkey, modified->common.encryptkey) != 0) + { + changed = 1; + encodingchanged = 1; + goto actonchange; + } + } else if (ipint->common.encryptkey == NULL && modified->common.encryptkey) + { + changed = 1; + encodingchanged = 1; + goto actonchange; + } else if (ipint->common.encryptkey && modified->common.encryptkey == NULL) + { + changed = 1; + encodingchanged = 1; + goto actonchange; } if (strcmp(ipint->common.delivcc, modified->common.delivcc) != 0 || strcmp(ipint->common.authcc, modified->common.authcc) != 0) { changed = 1; - expmsg = create_intercept_details_msg(&(ipint->common)); + encodingchanged = 1; + goto actonchange; + } + +actonchange: + if (encodingchanged) { + expmsg = create_intercept_details_msg(&(modified->common)); expmsg->type = OPENLI_EXPORT_INTERCEPT_CHANGED; publish_openli_msg(sync->zmq_pubsocks[ipint->common.seqtrackerid], expmsg); } if (changed) { + /* Note: this will replace the values in 'ipint' with the new ones + * from 'modified' so don't panic that we haven't changed them + * earlier in this method... + */ push_ipintercept_update_to_threads(sync, ipint, modified); } @@ -1390,6 +1421,31 @@ static int modify_ipintercept(collector_sync_t *sync, uint8_t *intmsg, return 0; } +static int modify_ipintercept(collector_sync_t *sync, uint8_t *intmsg, + uint16_t msglen) { + + ipintercept_t *ipint, *modified; + + modified = calloc(1, sizeof(ipintercept_t)); + + if (decode_ipintercept_modify(intmsg, msglen, modified) == -1) { + if (sync->instruct_log) { + logger(LOG_INFO, + "OpenLI: received invalid IP intercept modification from provisioner."); + } + return -1; + } + + HASH_FIND(hh_liid, sync->ipintercepts, modified->common.liid, + modified->common.liid_len, ipint); + + if (!ipint) { + return insert_new_ipintercept(sync, modified); + } + + return update_modified_intercept(sync, ipint, modified); +} + static int halt_ipintercept(collector_sync_t *sync, uint8_t *intmsg, uint16_t msglen) { @@ -1556,31 +1612,23 @@ static int new_ipintercept(collector_sync_t *sync, uint8_t *intmsg, logger(LOG_INFO, "OpenLI: duplicate IP ID %s seen, but targets are different (was %s, now %s).", x->common.liid, x->username, cept->username); - remove_ip_intercept(sync, x); - x = NULL; } } - if (x != NULL && cept->vendmirrorid != x->vendmirrorid) { + if (cept->vendmirrorid != x->vendmirrorid) { logger(LOG_INFO, "OpenLI: duplicate IP ID %s seen, but Vendor Mirroring intercept IDs are different (was %u, now %u).", x->common.liid, x->vendmirrorid, cept->vendmirrorid); - remove_ip_intercept(sync, x); - x = NULL; } - if (x != NULL) { - if (cept->accesstype != x->accesstype) { - logger(LOG_INFO, - "OpenLI: duplicate IP ID %s seen, but access type has changed to %s.", x->common.liid, accesstype_to_string(cept->accesstype)); - /* Only affects IRIs so don't need to modify collector threads */ - x->accesstype = cept->accesstype; - } - x->awaitingconfirm = 0; - free_single_ipintercept(cept); - /* our collector threads should already know about this intercept */ - return 1; + if (cept->accesstype != x->accesstype) { + logger(LOG_INFO, + "OpenLI: duplicate IP ID %s seen, but access type has changed to %s.", x->common.liid, accesstype_to_string(cept->accesstype)); + /* Only affects IRIs so don't need to modify collector threads */ + x->accesstype = cept->accesstype; } + x->awaitingconfirm = 0; + return update_modified_intercept(sync, x, cept); } return insert_new_ipintercept(sync, cept); @@ -2160,9 +2208,30 @@ static inline internet_user_t *lookup_userid(collector_sync_t *sync, return iuser; } +static inline int identity_match_intercept(ipintercept_t *ipint, + user_identity_t *uid) { + + /* If the user has specifically said that the intercept target can + * not be identified using the username, then matching against the + * username is not allowed */ + + if (uid->method == USER_IDENT_RADIUS_USERNAME && + ((ipint->options & (1 << OPENLI_IPINT_OPTION_RADIUS_IDENT_USER))\ + == 0)) { + return 0; + } + + if (uid->method == USER_IDENT_RADIUS_CSID && + ((ipint->options & (1 << OPENLI_IPINT_OPTION_RADIUS_IDENT_CSID)) == 0)) { + return 0; + } + + return 1; +} + static int newly_active_session(collector_sync_t *sync, user_intercept_list_t *userint, internet_user_t *iuser, - access_session_t *sess) { + access_session_t *sess, user_identity_t *uid) { int mapret = 0; sync_sendq_t *sendq, *tmpq; @@ -2185,6 +2254,9 @@ static int newly_active_session(collector_sync_t *sync, * packets involving the session IP. */ HASH_ITER(hh_user, userint->intlist, ipint, tmp) { + if (!identity_match_intercept(ipint, uid)) { + continue; + } HASH_ITER(hh, (sync_sendq_t *)(sync->glob->collector_queues), sendq, tmpq) { push_single_ipintercept(sync, sendq->q, ipint, sess); @@ -2199,27 +2271,6 @@ static int newly_active_session(collector_sync_t *sync, } -static inline int identity_match_intercept(ipintercept_t *ipint, - user_identity_t *uid) { - - /* If the user has specifically said that the intercept target can - * not be identified using the username, then matching against the - * username is not allowed */ - - if (uid->method == USER_IDENT_RADIUS_USERNAME && - ((ipint->options & (1 << OPENLI_IPINT_OPTION_RADIUS_IDENT_USER))\ - == 0)) { - return 0; - } - - if (uid->method == USER_IDENT_RADIUS_CSID && - ((ipint->options & (1 << OPENLI_IPINT_OPTION_RADIUS_IDENT_CSID)) == 0)) { - return 0; - } - - return 1; -} - static inline int is_default_radius_username(collector_sync_t *sync, user_identity_t *uid) { @@ -2308,7 +2359,8 @@ static int update_user_sessions(collector_sync_t *sync, libtrace_packet_t *pkt, if (oldstate != newstate) { if (newstate == SESSION_STATE_ACTIVE) { - ret = newly_active_session(sync, userint, iuser, sess); + ret = newly_active_session(sync, userint, iuser, sess, + &(identities[i])); if (ret < 0) { logger(LOG_INFO, "OpenLI: error while processing new active IP session in sync thread."); break; diff --git a/src/collector/collector_sync_voip.c b/src/collector/collector_sync_voip.c index fe8dd2a0..d2c2dcba 100644 --- a/src/collector/collector_sync_voip.c +++ b/src/collector/collector_sync_voip.c @@ -138,6 +138,9 @@ void clean_sync_voip_data(collector_sync_voip_t *sync) { sync_epoll_t *syncev, *tmp; free_voip_cinmap(sync->knowncallids); + HASH_ITER(hh, sync->timeouts, syncev, tmp) { + HASH_DELETE(hh, sync->timeouts, syncev); + } if (sync->voipintercepts) { free_all_voipintercepts(&(sync->voipintercepts)); } @@ -153,9 +156,6 @@ void clean_sync_voip_data(collector_sync_voip_t *sync) { free(sync->expiring_streams); } - HASH_ITER(hh, sync->timeouts, syncev, tmp) { - HASH_DELETE(hh, sync->timeouts, syncev); - } sync->voipintercepts = NULL; sync->knowncallids = NULL; @@ -320,6 +320,13 @@ static void push_voip_intercept_update_to_threads(collector_sync_voip_t *sync, expmsg->data.cept.liid = strdup(vint->common.liid); expmsg->data.cept.authcc = strdup(vint->common.authcc); expmsg->data.cept.delivcc = strdup(vint->common.delivcc); + expmsg->data.cept.encryptmethod = vint->common.encrypt; + if (vint->common.encryptkey) { + expmsg->data.cept.encryptkey = strdup(vint->common.encryptkey); + } else { + expmsg->data.cept.encryptkey = NULL; + } + expmsg->data.cept.seqtrackerid = vint->common.seqtrackerid; publish_openli_msg(sync->zmq_pubsocks[vint->common.seqtrackerid], expmsg); HASH_ITER(hh, (sync_sendq_t *)(sync->glob->collector_queues), sendq, tmp) { @@ -1593,90 +1600,127 @@ static int update_sip_state(collector_sync_voip_t *sync, } -static int modify_voipintercept(collector_sync_voip_t *sync, uint8_t *intmsg, - uint16_t msglen) { +static int update_modified_voipintercept(collector_sync_voip_t *sync, + voipintercept_t *vint, voipintercept_t *tomod) { - voipintercept_t *vint, tomod; - int changed = 0; - - if (decode_voipintercept_modify(intmsg, msglen, &tomod) == -1) { - if (sync->log_bad_instruct) { - logger(LOG_INFO, - "OpenLI: received invalid VOIP intercept modification from provisioner."); - } - return -1; - } - - HASH_FIND(hh_liid, sync->voipintercepts, tomod.common.liid, - tomod.common.liid_len, vint); - if (!vint) { - if (sync->log_bad_instruct) { - logger(LOG_INFO, - "OpenLI: received modification for VOIP intercept %s but it is not present in the sync intercept list?", - tomod.common.liid); - } - return 0; - } + int changed = 0, keychanged = 0; + char *tmp; sync->log_bad_instruct = 1; - if (tomod.options != vint->options) { - if (tomod.options & (1UL << OPENLI_VOIPINT_OPTION_IGNORE_COMFORT)) { + if (tomod->options != vint->options) { + if (tomod->options & (1UL << OPENLI_VOIPINT_OPTION_IGNORE_COMFORT)) { logger(LOG_INFO, "OpenLI: VOIP intercept %s is now ignoring RTP comfort noise", - tomod.common.liid); + tomod->common.liid); } else { logger(LOG_INFO, "OpenLI: VOIP intercept %s is now intercepting RTP comfort noise", - tomod.common.liid); + tomod->common.liid); } } - if (tomod.common.tostart_time != vint->common.tostart_time || - tomod.common.toend_time != vint->common.toend_time) { + if (tomod->common.tostart_time != vint->common.tostart_time || + tomod->common.toend_time != vint->common.toend_time) { changed = 1; logger(LOG_INFO, - "OpenLI: VOIP intercept %s has changed start / end times -- now %lu, %lu", tomod.common.liid, tomod.common.tostart_time, tomod.common.toend_time); + "OpenLI: VOIP intercept %s has changed start / end times -- now %lu, %lu", tomod->common.liid, tomod->common.tostart_time, tomod->common.toend_time); } - if (tomod.common.tomediate != vint->common.tomediate) { + if (tomod->common.tomediate != vint->common.tomediate) { char space[1024]; changed = 1; - intercept_mediation_mode_as_string(tomod.common.tomediate, space, + intercept_mediation_mode_as_string(tomod->common.tomediate, space, 1024); logger(LOG_INFO, "OpenLI: VOIP intercept %s has changed mediation mode to: %s", vint->common.liid, space); } - if (strcmp(tomod.common.delivcc, vint->common.delivcc) != 0 || - strcmp(tomod.common.authcc, vint->common.authcc) != 0) { - char *tmp; + if (tomod->common.encrypt != vint->common.encrypt) { + char space[1024]; + changed = 1; + intercept_encryption_mode_as_string(tomod->common.encrypt, space, + 1024); + logger(LOG_INFO, + "OpenLI: VOIP intercept %s has changed encryption mode to: %s", + vint->common.liid, space); + } + + if (vint->common.encryptkey && tomod->common.encryptkey) { + if (strcmp(vint->common.encryptkey, tomod->common.encryptkey) != 0) + { + keychanged = 1; + } + } else if (vint->common.encryptkey == NULL && tomod->common.encryptkey) { + keychanged = 1; + } else if (vint->common.encryptkey && tomod->common.encryptkey == NULL) { + keychanged = 1; + } + + if (keychanged) { + changed = 1; + tmp = vint->common.encryptkey; + vint->common.encryptkey = tomod->common.encryptkey; + tomod->common.encryptkey = tmp; + } + + if (strcmp(tomod->common.delivcc, vint->common.delivcc) != 0 || + strcmp(tomod->common.authcc, vint->common.authcc) != 0) { changed = 1; tmp = vint->common.authcc; - vint->common.authcc = tomod.common.authcc; - vint->common.authcc_len = tomod.common.authcc_len; - tomod.common.authcc = tmp; + vint->common.authcc = tomod->common.authcc; + vint->common.authcc_len = tomod->common.authcc_len; + tomod->common.authcc = tmp; tmp = vint->common.delivcc; - vint->common.delivcc = tomod.common.delivcc; - vint->common.delivcc_len = tomod.common.delivcc_len; - tomod.common.delivcc = tmp; + vint->common.delivcc = tomod->common.delivcc; + vint->common.delivcc_len = tomod->common.delivcc_len; + tomod->common.delivcc = tmp; } - vint->options = tomod.options; - vint->common.tostart_time = tomod.common.tostart_time; - vint->common.toend_time = tomod.common.toend_time; - vint->common.tomediate = tomod.common.tomediate; + vint->options = tomod->options; + vint->common.tostart_time = tomod->common.tostart_time; + vint->common.toend_time = tomod->common.toend_time; + vint->common.tomediate = tomod->common.tomediate; + vint->common.encrypt = tomod->common.encrypt; if (changed) { push_voip_intercept_update_to_threads(sync, vint); } return 0; +} + +static int modify_voipintercept(collector_sync_voip_t *sync, uint8_t *intmsg, + uint16_t msglen) { + + voipintercept_t *vint, *tomod; + + tomod = calloc(1, sizeof(voipintercept_t)); + if (decode_voipintercept_modify(intmsg, msglen, tomod) == -1) { + if (sync->log_bad_instruct) { + logger(LOG_INFO, + "OpenLI: received invalid VOIP intercept modification from provisioner."); + } + return -1; + } + HASH_FIND(hh_liid, sync->voipintercepts, tomod->common.liid, + tomod->common.liid_len, vint); + if (!vint) { + if (sync->log_bad_instruct) { + logger(LOG_INFO, + "OpenLI: received modification for VOIP intercept %s but it is not present in the sync intercept list?", + tomod->common.liid); + } + return 0; + } + + update_modified_voipintercept(sync, vint, tomod); + free_single_voipintercept(tomod); } static inline void remove_voipintercept(collector_sync_voip_t *sync, @@ -1692,6 +1736,7 @@ static inline void remove_voipintercept(collector_sync_voip_t *sync, expmsg->data.cept.liid = strdup(vint->common.liid); expmsg->data.cept.authcc = strdup(vint->common.authcc); expmsg->data.cept.delivcc = strdup(vint->common.delivcc); + expmsg->data.cept.seqtrackerid = vint->common.seqtrackerid; pthread_mutex_lock(sync->glob->stats_mutex); sync->glob->stats->voipintercepts_ended_diff ++; @@ -2007,10 +2052,9 @@ static int new_voipintercept(collector_sync_voip_t *sync, uint8_t *intmsg, HASH_FIND(hh_liid, sync->voipintercepts, toadd->common.liid, toadd->common.liid_len, vint); if (vint) { - vint->internalid = toadd->internalid; vint->awaitingconfirm = 0; vint->active = 1; - vint->options = toadd->options; + update_modified_voipintercept(sync, vint, toadd); free_single_voipintercept(toadd); return 0; } else { @@ -2028,6 +2072,13 @@ static int new_voipintercept(collector_sync_voip_t *sync, uint8_t *intmsg, expmsg->data.cept.liid = strdup(vint->common.liid); expmsg->data.cept.authcc = strdup(vint->common.authcc); expmsg->data.cept.delivcc = strdup(vint->common.delivcc); + expmsg->data.cept.encryptmethod = vint->common.encrypt; + if (vint->common.encryptkey) { + expmsg->data.cept.encryptkey = strdup(vint->common.encryptkey); + } else { + expmsg->data.cept.encryptkey = NULL; + } + expmsg->data.cept.seqtrackerid = vint->common.seqtrackerid; pthread_mutex_lock(sync->glob->stats_mutex); sync->glob->stats->voipintercepts_added_diff ++; diff --git a/src/collector/email_ingest_service.c b/src/collector/email_ingest_service.c index d94cdb70..e51aed6c 100644 --- a/src/collector/email_ingest_service.c +++ b/src/collector/email_ingest_service.c @@ -87,6 +87,11 @@ static int init_email_ingest_state(email_ingestor_state_t *state, return 0; } +#define CALLOC_THISMSG \ + if (con_info->thismsg == NULL) { \ + con_info->thismsg = calloc(1, sizeof(openli_email_captured_t)); \ + } + static MHD_RESULT iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key, const char *filename, const char *content_type, const char *transfer_encoding, const char *data, uint64_t off, @@ -95,25 +100,34 @@ static MHD_RESULT iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, email_connection_t *con_info = (email_connection_t *)(coninfo_cls); char *ptr; - if (con_info->thismsg == NULL) { - con_info->thismsg = calloc(1, sizeof(openli_email_captured_t)); + if (memchr(data, '\0', size + 1) == NULL) { + logger(LOG_INFO, "OpenLI: WARNING -- ingested email content does not end in a null character, it may have been truncated. Ignoring it..."); + return MHD_YES; } if (strcmp(key, "TARGET_ID") == 0) { + CALLOC_THISMSG con_info->thismsg->target_id = strdup(data); } else if (strcmp(key, "REMOTE_IP") == 0) { + CALLOC_THISMSG con_info->thismsg->remote_ip = strdup(data); } else if (strcmp(key, "REMOTE_PORT") == 0) { + CALLOC_THISMSG con_info->thismsg->remote_port = strdup(data); } else if (strcmp(key, "HOST_IP") == 0) { + CALLOC_THISMSG con_info->thismsg->host_ip = strdup(data); } else if (strcmp(key, "HOST_PORT") == 0) { + CALLOC_THISMSG con_info->thismsg->host_port = strdup(data); } else if (strcmp(key, "DATA_SOURCE") == 0) { + CALLOC_THISMSG con_info->thismsg->datasource = strdup(data); } else if (strcmp(key, "SESSION_ID") == 0) { + CALLOC_THISMSG con_info->thismsg->session_id = strdup(data); } else if (strcmp(key, "DIRECTION") == 0) { + CALLOC_THISMSG if (strcasecmp(data, "out") == 0) { con_info->thismsg->direction = OPENLI_EMAIL_DIRECTION_OUTBOUND; } else if (strcasecmp(data, "in") == 0) { @@ -123,11 +137,14 @@ static MHD_RESULT iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, } } else if (strcmp(key, "TIMESTAMP") == 0) { + CALLOC_THISMSG con_info->thismsg->timestamp = strtoul(data, NULL, 10); } else if (strcmp(key, "MAIL_ID") == 0) { + CALLOC_THISMSG con_info->thismsg->mail_id = strtoul(data, NULL, 10); } else if (strcmp(key, "SERVICE") == 0) { + CALLOC_THISMSG if (strcasecmp(data, "smtp") == 0) { con_info->thismsg->type = OPENLI_EMAIL_TYPE_SMTP; @@ -145,6 +162,7 @@ static MHD_RESULT iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, } else if (strcmp(key, "BUFFER") == 0) { int datalen = 0; + CALLOC_THISMSG ptr = (char *)data; while (*ptr == 0x0a || *ptr == 0x0d) { ptr ++; @@ -159,6 +177,8 @@ static MHD_RESULT iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, con_info->thismsg->own_content = 1; con_info->thismsg->content = strdup(ptr); con_info->thismsg->msg_length = datalen; + } else { + return MHD_YES; } //logger(LOG_INFO, "KEY %s", key); @@ -298,7 +318,7 @@ static MHD_RESULT answer_email_connection(void *cls, con_info->parentstate = state; if (strcmp(method, "POST") == 0) { con_info->postproc = MHD_create_post_processor(connection, - 16 * 1024, iterate_post, (void *)con_info); + 128 * 1024, iterate_post, (void *)con_info); if (con_info->postproc == NULL) { free(con_info); return MHD_NO; diff --git a/src/collector/email_worker.c b/src/collector/email_worker.c index e32ce22a..687e8041 100644 --- a/src/collector/email_worker.c +++ b/src/collector/email_worker.c @@ -569,6 +569,12 @@ static void start_email_intercept(openli_email_worker_t *state, expmsg->data.cept.authcc = strdup(em->common.authcc); expmsg->data.cept.delivcc = strdup(em->common.delivcc); expmsg->data.cept.seqtrackerid = em->common.seqtrackerid; + expmsg->data.cept.encryptmethod = em->common.encrypt; + if (em->common.encryptkey) { + expmsg->data.cept.encryptkey = strdup(em->common.encryptkey); + } else { + expmsg->data.cept.encryptkey = NULL; + } publish_openli_msg(state->zmq_pubsocks[em->common.seqtrackerid], expmsg); @@ -576,32 +582,91 @@ static void start_email_intercept(openli_email_worker_t *state, em->awaitingconfirm = 0; } -static void update_email_intercept(openli_email_worker_t *state, - emailintercept_t *found, emailintercept_t *latest) { +static int update_modified_email_intercept(openli_email_worker_t *state, + emailintercept_t *found, emailintercept_t *decode) { + openli_export_recv_t *expmsg; + int encodingchanged = 0, keychanged = 0; - if (found->common.authcc) { - free(found->common.authcc); + if (decode->common.tostart_time != found->common.tostart_time || + decode->common.toend_time != found->common.toend_time) { + logger(LOG_INFO, + "OpenLI: Email intercept %s has changed start / end times -- now %lu, %lu", + found->common.liid, decode->common.tostart_time, + decode->common.toend_time); + found->common.tostart_time = decode->common.tostart_time; + found->common.toend_time = decode->common.toend_time; } - found->common.authcc = latest->common.authcc; - found->common.authcc_len = latest->common.authcc_len; - latest->common.authcc = NULL; - if (found->common.delivcc) { - free(found->common.delivcc); + if (decode->common.tomediate != found->common.tomediate) { + char space[1024]; + intercept_mediation_mode_as_string(decode->common.tomediate, space, + 1024); + logger(LOG_INFO, + "OpenLI: Email intercept %s has changed mediation mode to: %s", + decode->common.liid, space); + found->common.tomediate = decode->common.tomediate; } - found->common.delivcc = latest->common.delivcc; - found->common.delivcc_len = latest->common.delivcc_len; - latest->common.delivcc = NULL; - found->common.tostart_time = latest->common.tostart_time; - found->common.toend_time = latest->common.toend_time; - found->common.tomediate = latest->common.tomediate; + if (decode->common.encrypt != found->common.encrypt) { + char space[1024]; + intercept_encryption_mode_as_string(decode->common.encrypt, space, + 1024); + logger(LOG_INFO, + "OpenLI: Email intercept %s has changed encryption mode to: %s", + decode->common.liid, space); + found->common.encrypt = decode->common.encrypt; + encodingchanged = 1; + } - /* XXX targetagency and destid shouldn't matter, unless we actually - * use them in this thread. - * - * I think they're only relevant in the forwarding thread though */ + if (found->common.encryptkey && decode->common.encryptkey) { + if (strcmp(found->common.encryptkey, decode->common.encryptkey) != 0) { + keychanged = 1; + } + } else if (found->common.encryptkey == NULL && decode->common.encryptkey) { + keychanged = 1; + } else if (found->common.encryptkey && decode->common.encryptkey == NULL) { + keychanged = 1; + } + if (keychanged) { + char *tmp; + encodingchanged = 1; + tmp = found->common.encryptkey; + found->common.encryptkey = decode->common.encryptkey; + decode->common.encryptkey = tmp; + } + + if (strcmp(decode->common.delivcc, found->common.delivcc) != 0 || + strcmp(decode->common.authcc, found->common.authcc) != 0) { + char *tmp; + tmp = decode->common.authcc; + decode->common.authcc = found->common.authcc; + found->common.authcc = tmp; + tmp = decode->common.delivcc; + decode->common.delivcc = found->common.delivcc; + found->common.delivcc = tmp; + encodingchanged = 1; + } + + if (encodingchanged) { + expmsg = (openli_export_recv_t *)calloc(1, sizeof(openli_export_recv_t)); + expmsg->type = OPENLI_EXPORT_INTERCEPT_CHANGED; + expmsg->data.cept.liid = strdup(found->common.liid); + expmsg->data.cept.authcc = strdup(found->common.authcc); + expmsg->data.cept.delivcc = strdup(found->common.delivcc); + expmsg->data.cept.seqtrackerid = found->common.seqtrackerid; + expmsg->data.cept.encryptmethod = found->common.encrypt; + if (found->common.encryptkey) { + expmsg->data.cept.encryptkey = strdup(found->common.encryptkey); + } else { + expmsg->data.cept.encryptkey = NULL; + } + + publish_openli_msg(state->zmq_pubsocks[found->common.seqtrackerid], + expmsg); + } + free_single_emailintercept(decode); + return 0; } static void remove_email_intercept(openli_email_worker_t *state, @@ -631,6 +696,7 @@ static void remove_email_intercept(openli_email_worker_t *state, } HASH_DELETE(hh_liid, state->allintercepts, em); + logger(LOG_INFO, "DEVDEBUG: removing email intercept %s", em->common.liid); if (state->emailid == 0 && removetargets != 0) { expmsg = (openli_export_recv_t *)calloc(1, @@ -696,10 +762,10 @@ static int add_new_email_intercept(openli_email_worker_t *state, tgt->awaitingconfirm = 1; } - update_email_intercept(state, found, em); + update_modified_email_intercept(state, found, em); found->awaitingconfirm = 0; - free_single_emailintercept(em); ret = 1; + logger(LOG_INFO, "OpenLI: updated email intercept for %s after re-announcement by provisioner", found->common.liid); } else { start_email_intercept(state, em, 0); if (state->emailid == 0) { @@ -720,7 +786,6 @@ static int modify_email_intercept(openli_email_worker_t *state, provisioner_msg_t *provmsg) { emailintercept_t *decode, *found; - openli_export_recv_t *expmsg; decode = calloc(1, sizeof(emailintercept_t)); if (decode_emailintercept_modify(provmsg->msgbody, provmsg->msglen, @@ -736,48 +801,7 @@ static int modify_email_intercept(openli_email_worker_t *state, return 0; } - if (decode->common.tostart_time != found->common.tostart_time || - decode->common.toend_time != found->common.toend_time) { - logger(LOG_INFO, - "OpenLI: Email intercept %s has changed start / end times -- now %lu, %lu", - found->common.liid, decode->common.tostart_time, - decode->common.toend_time); - found->common.tostart_time = decode->common.tostart_time; - found->common.toend_time = decode->common.toend_time; - } - - if (decode->common.tomediate != found->common.tomediate) { - char space[1024]; - intercept_mediation_mode_as_string(decode->common.tomediate, space, - 1024); - logger(LOG_INFO, - "OpenLI: Email intercept %s has changed mediation mode to: %s", - decode->common.liid, space); - found->common.tomediate = decode->common.tomediate; - } - - if (strcmp(decode->common.delivcc, found->common.delivcc) != 0 || - strcmp(decode->common.authcc, found->common.authcc) != 0) { - char *tmp; - tmp = decode->common.authcc; - decode->common.authcc = found->common.authcc; - found->common.authcc = tmp; - tmp = decode->common.delivcc; - decode->common.delivcc = found->common.delivcc; - found->common.delivcc = tmp; - - expmsg = (openli_export_recv_t *)calloc(1, sizeof(openli_export_recv_t)); - expmsg->type = OPENLI_EXPORT_INTERCEPT_DETAILS; - expmsg->data.cept.liid = strdup(found->common.liid); - expmsg->data.cept.authcc = strdup(found->common.authcc); - expmsg->data.cept.delivcc = strdup(found->common.delivcc); - expmsg->data.cept.seqtrackerid = found->common.seqtrackerid; - - publish_openli_msg(state->zmq_pubsocks[found->common.seqtrackerid], - expmsg); - } - - free_single_emailintercept(decode); + update_modified_email_intercept(state, found, decode); return 0; } @@ -1017,6 +1041,13 @@ static int find_and_update_active_session(openli_email_worker_t *state, emailsession_t *sess; int r = 0; + if (cap->session_id == NULL) { + logger(LOG_INFO, + "OpenLI: error creating email session -- session_id is NULL"); + free_captured_email(cap); + return -1; + } + snprintf(sesskey, 256, "%s-%s", email_type_to_string(cap->type), cap->session_id); @@ -1074,8 +1105,9 @@ static int process_received_packet(openli_email_worker_t *state) { cap = convert_packet_to_email_captured(recvd.data.pkt, recvd.type); - if (cap == NULL) { + if (cap == NULL || cap->session_id == NULL) { logger(LOG_INFO, "OpenLI: unable to derive email session ID from received packet in email thread %d", state->emailid); + free_captured_email(cap); return -1; } if (cap->content != NULL) { @@ -1109,7 +1141,8 @@ static int process_ingested_capture(openli_email_worker_t *state) { break; } - if (cap == NULL) { + if (cap == NULL || cap->session_id == NULL) { + free_captured_email(cap); break; } find_and_update_active_session(state, cap); diff --git a/src/collector/emailprotocols/imap.c b/src/collector/emailprotocols/imap.c index 94fb052d..35386d4d 100644 --- a/src/collector/emailprotocols/imap.c +++ b/src/collector/emailprotocols/imap.c @@ -1018,47 +1018,121 @@ static int parse_id_command(emailsession_t *sess, imap_session_t *imapsess) { } static int find_next_crlf(imap_session_t *sess, int start_index) { - int rem; - uint8_t *found; + int rem, regres; + uint8_t *found = NULL; uint8_t *openparent = NULL; uint8_t *closeparent = NULL; - + uint8_t *curly = NULL; + regmatch_t matches[1]; + regex_t regex; int nests = 0; + if (regcomp(®ex, "\\{\\d+\\}", REG_EXTENDED) != 0) { + logger(LOG_INFO, "OpenLI: failed to compile regex pattern for matching curly braces in IMAP content?"); + return -1; + } + rem = sess->contbufused - start_index; + sess->contbuffer[sess->contbufused] = '\0'; while (1) { - openparent = (uint8_t *)memmem(sess->contbuffer + start_index, rem, - "(", 1); - found = (uint8_t *)memmem(sess->contbuffer + start_index, rem, "\r\n", - 2); - closeparent = (uint8_t *)memmem(sess->contbuffer + start_index, rem, - ")", 1); - - if (openparent == NULL && closeparent == NULL && nests == 0) { - break; - } + assert(nests >= 0); + if (nests == 0) { + openparent = (uint8_t *)memmem(sess->contbuffer + start_index, rem, + "(", 1); + found = (uint8_t *)memmem(sess->contbuffer + start_index, rem, + "\r\n", 2); + + /* No open parenthesis, just need to check if we have \r\n */ + if (openparent == NULL) { + break; + } - if (closeparent == NULL && nests > 0) { - return 0; - } + if (found && found < openparent) { + /* There is an open parenthesis, but it is after the next + * \r\n so process the line break first. + */ + break; + } - if ((openparent == NULL || found < openparent) && nests == 0) { - break; - } + /* Open parenthesis: we cannot look for \r\n until we've seen + * the matching close parenthesis. + */ + nests ++; + start_index = (openparent - sess->contbuffer) + 1; - if (openparent == NULL || closeparent < openparent) { - nests -= 1; - start_index = (closeparent - sess->contbuffer) + 1; } else { - nests += 1; - start_index = (openparent - sess->contbuffer) + 1; + openparent = (uint8_t *)memmem(sess->contbuffer + start_index, rem, + "(", 1); + closeparent = (uint8_t *)memmem(sess->contbuffer + start_index, rem, + ")", 1); + + regres = regexec(®ex, sess->contbuffer + start_index, 1, + matches, 0); + if (regres == 0) { + curly = sess->contbuffer + start_index + matches[0].rm_so; + } else { + curly = NULL; + } + + found = NULL; + if (openparent != NULL && + (closeparent == NULL || openparent < closeparent) && + (curly == NULL || openparent < curly)) { + /* Next interesting token is another nested open parenthesis, + * so add another layer of nesting */ + + nests ++; + start_index = (openparent - sess->contbuffer) + 1; + } else if (curly != NULL && + (closeparent == NULL || curly < closeparent) + && (openparent == NULL || curly < openparent)) { + /* curly braces indicate a section containing some sort + * of body content, and contain the length of the body + * inside the braces. We want to skip over the entire + * body and not try to parse it, because there could be + * parentheses and curly braces in there that will mess + * us up (especially if they're not balanced!). + */ + char *endptr = NULL; + unsigned long toskip = strtoul(curly + 1, &endptr, 10); + + if (toskip >= rem) { + /* The whole section is not here yet, so we can't + * skip it until it arrives */ + found = NULL; + break; + } + + start_index = (((uint8_t *)endptr + toskip) + - sess->contbuffer) + 1; + + } else if (closeparent != NULL && + (openparent == NULL || closeparent < openparent) && + (curly == NULL || closeparent < curly)) { + /* A close parenthesis means that our innermost nested + * parentheses are now balanced. + */ + nests --; + start_index = (closeparent - sess->contbuffer) + 1; + } else { + /* None of the above tokens are present, so we must need + * more data to finish parsing... + */ + + /* Nothing to do, just make sure found remains NULL */ + found = NULL; + break; + } } + /* Always update remaining before looping again! */ rem = sess->contbufused - start_index; } + regfree(®ex); if (found) { + /* +2 because we have to move past the \r\n, naturally */ sess->contbufread = (found - sess->contbuffer) + 2; return 1; } diff --git a/src/collector/encoder_worker.c b/src/collector/encoder_worker.c index 031f9faa..1a964c21 100644 --- a/src/collector/encoder_worker.c +++ b/src/collector/encoder_worker.c @@ -206,6 +206,8 @@ void destroy_encoder_worker(openli_encoder_t *enc) { } JLFA(rcint, enc->saved_global_templates); + etsili_destroy_encrypted_templates(enc); + if (enc->encoder) { free_wandder_encoder(enc->encoder); } @@ -236,12 +238,19 @@ void destroy_encoder_worker(openli_encoder_t *enc) { if (job.cinstr) { free(job.cinstr); } + if (job.encryptkey) { + free(job.encryptkey); + } drained ++; } while (x > 0); zmq_close(enc->zmq_recvjobs[i]); } + if (enc->evp_ctx) { + EVP_CIPHER_CTX_free(enc->evp_ctx); + } + if (enc->zmq_control) { zmq_close(enc->zmq_control); } @@ -293,96 +302,6 @@ static int encode_rawip(openli_encoder_t *enc, openli_encoding_job_t *job, return 0; } -static inline uint8_t DERIVE_INTEGER_LENGTH(uint64_t x) { - if (x < 128) return 1; - if (x < 32768) return 2; - if (x < 8388608) return 3; - if (x < 2147483648) return 4; - return 5; -} - -static inline uint8_t encode_pspdu_sequence(uint8_t *space, uint8_t space_len, - uint32_t contentsize, char *liid, uint16_t liidlen) { - - uint8_t len_space_req = DERIVE_INTEGER_LENGTH(contentsize); - int i; - uint16_t l; - - if (liidlen > space_len - 8) { - logger(LOG_INFO, - "OpenLI: invalid LIID for PSPDU: %s (%u %u)", liid, liidlen, space_len); - return 0; - } - - l = htons(liidlen); - memcpy(space, &l, sizeof(uint16_t)); - memcpy(space + 2, liid, liidlen); - space += (2 + liidlen); - - *space = (uint8_t)((WANDDER_CLASS_UNIVERSAL_CONSTRUCT << 5) | - WANDDER_TAG_SEQUENCE); - space ++; - - if (len_space_req == 1) { - *space = (uint8_t)contentsize; - return 2 + (2 + liidlen); - } - - if (len_space_req > (space_len - 2)) { - logger(LOG_INFO, - "OpenLI: invalid PSPDU sequence length %u", contentsize); - return 0; - } - - *space = len_space_req | 0x80; - space ++; - - for (i = len_space_req - 1; i >= 0; i--) { - *(space + i) = (contentsize & 0xff); - contentsize = contentsize >> 8; - } - - return len_space_req + 2 + (2 + liidlen); -} - -static int create_encoded_message_body(openli_encoded_result_t *res, - encoded_header_template_t *hdr_tplate, uint8_t *bodycontent, - uint16_t bodylen, char *liid, uint16_t liidlen) { - - uint8_t pspdu[108]; - uint8_t pspdu_len; - /* Create a msgbody by concatenating hdr_tplate and ipcc_tplate, plus - * a preceding pS-PDU sequence with the appropriate length... - */ - pspdu_len = encode_pspdu_sequence(pspdu, sizeof(pspdu), - hdr_tplate->header_len + bodylen, liid, liidlen); - - if (pspdu_len == 0) { - return -1; - } - - res->msgbody = calloc(1, sizeof(wandder_encoded_result_t)); - res->msgbody->encoder = NULL; - res->msgbody->len = pspdu_len + hdr_tplate->header_len + bodylen; - - res->msgbody->encoded = malloc(res->msgbody->len); - res->msgbody->alloced = res->msgbody->len; - res->msgbody->next = NULL; - - memcpy(res->msgbody->encoded, pspdu, pspdu_len); - memcpy(res->msgbody->encoded + pspdu_len, hdr_tplate->header, - hdr_tplate->header_len); - memcpy(res->msgbody->encoded + pspdu_len + hdr_tplate->header_len, - bodycontent, bodylen); - - /* Set the remaining msg->header properties */ - res->header.magic = htonl(OPENLI_PROTO_MAGIC); - res->header.bodylen = htons(res->msgbody->len); - res->header.internalid = 0; - - return 0; -} - static int encode_templated_ipiri(openli_encoder_t *enc, openli_encoding_job_t *job, encoded_header_template_t *hdr_tplate, openli_encoded_result_t *res) { @@ -414,18 +333,22 @@ static int encode_templated_ipiri(openli_encoder_t *enc, return -1; } - if (create_encoded_message_body(res, hdr_tplate, body->encoded, body->len, - job->liid, - job->preencoded[OPENLI_PREENCODE_LIID].vallen) < 0) { - wandder_release_encoded_result(enc->encoder, body); - free_ipiri_parameters(params); - return -1; + if (job->encryptmethod != OPENLI_PAYLOAD_ENCRYPTION_NONE) { + if (create_encrypted_message_body(enc, res, hdr_tplate, + body->encoded, body->len, NULL, 0, job) < 0) { + wandder_release_encoded_result(enc->encoder, body); + free_ipiri_parameters(params); + return -1; + } + } else { + if (create_etsi_encoded_result(res, hdr_tplate, body->encoded, + body->len, NULL, 0, job) < 0) { + wandder_release_encoded_result(enc->encoder, body); + free_ipiri_parameters(params); + return -1; + } } - res->ipcontents = NULL; - res->ipclen = 0; - res->header.intercepttype = htons(OPENLI_PROTO_ETSI_IRI); - wandder_release_encoded_result(enc->encoder, body); free_ipiri_parameters(params); @@ -492,18 +415,21 @@ static int encode_templated_ipmmcc(openli_encoder_t *enc, } } - if (create_encoded_message_body(res, hdr_tplate, - ipmmcc_tplate->cc_content.cc_wrap, - ipmmcc_tplate->cc_content.cc_wrap_len, - job->liid, - job->preencoded[OPENLI_PREENCODE_LIID].vallen) < 0) { - return -1; - } + if (job->encryptmethod != OPENLI_PAYLOAD_ENCRYPTION_NONE) { + if (create_encrypted_message_body(enc, res, hdr_tplate, + ipmmcc_tplate->cc_content.cc_wrap, + ipmmcc_tplate->cc_content.cc_wrap_len, + NULL, 0, job) < 0) { + return -1; + } - /* No ipcontents in the result, as it is encoded already in cc_content */ - res->ipcontents = NULL; - res->ipclen = 0; - res->header.intercepttype = htons(OPENLI_PROTO_ETSI_CC); + } else { + if (create_etsi_encoded_result(res, hdr_tplate, + ipmmcc_tplate->cc_content.cc_wrap, + ipmmcc_tplate->cc_content.cc_wrap_len, NULL, 0, job) < 0) { + return -1; + } + } /* Success */ return 1; @@ -532,17 +458,20 @@ static int encode_templated_emailiri(openli_encoder_t *enc, return -1; } - if (create_encoded_message_body(res, hdr_tplate, body->encoded, body->len, - job->liid, - job->preencoded[OPENLI_PREENCODE_LIID].vallen) < 0) { - wandder_release_encoded_result(enc->encoder, body); - return -1; + if (job->encryptmethod != OPENLI_PAYLOAD_ENCRYPTION_NONE) { + if (create_encrypted_message_body(enc, res, hdr_tplate, + body->encoded, body->len, NULL, 0, job) < 0) { + wandder_release_encoded_result(enc->encoder, body); + return -1; + } + } else { + if (create_etsi_encoded_result(res, hdr_tplate, body->encoded, + body->len, NULL, 0, job) < 0) { + wandder_release_encoded_result(enc->encoder, body); + return -1; + } } - res->ipcontents = NULL; - res->ipclen = 0; - res->header.intercepttype = htons(OPENLI_PROTO_ETSI_IRI); - wandder_release_encoded_result(enc->encoder, body); free_emailiri_parameters(irijob->customparams); @@ -596,16 +525,20 @@ static int encode_templated_umtsiri(openli_encoder_t *enc, return -1; } - if (create_encoded_message_body(res, hdr_tplate, body->encoded, body->len, - job->liid, - job->preencoded[OPENLI_PREENCODE_LIID].vallen) < 0) { - wandder_release_encoded_result(enc->encoder, body); - return -1; - } + if (job->encryptmethod != OPENLI_PAYLOAD_ENCRYPTION_NONE) { + if (create_encrypted_message_body(enc, res, hdr_tplate, + body->encoded, body->len, NULL, 0, job) < 0) { - res->ipcontents = NULL; - res->ipclen = 0; - res->header.intercepttype = htons(OPENLI_PROTO_ETSI_IRI); + wandder_release_encoded_result(enc->encoder, body); + return -1; + } + } else { + if (create_etsi_encoded_result(res, hdr_tplate, body->encoded, + body->len, NULL, 0, job) < 0) { + wandder_release_encoded_result(enc->encoder, body); + return -1; + } + } wandder_release_encoded_result(enc->encoder, body); free_umtsiri_parameters(irijob->customparams); @@ -645,17 +578,22 @@ static int encode_templated_ipmmiri(openli_encoder_t *enc, return -1; } - if (create_encoded_message_body(res, hdr_tplate, body->encoded, body->len, - job->liid, - job->preencoded[OPENLI_PREENCODE_LIID].vallen) < 0) { - wandder_release_encoded_result(enc->encoder, body); - return -1; + if (job->encryptmethod != OPENLI_PAYLOAD_ENCRYPTION_NONE) { + if (create_encrypted_message_body(enc, res, hdr_tplate, + body->encoded, body->len, + (uint8_t *)(irijob->content), irijob->contentlen, job) < 0) { + wandder_release_encoded_result(enc->encoder, body); + return -1; + } + } else { + if (create_etsi_encoded_result(res, hdr_tplate, body->encoded, + body->len, (uint8_t *)(irijob->content), irijob->contentlen, + job) < 0) { + wandder_release_encoded_result(enc->encoder, body); + return -1; + } } - res->ipcontents = (uint8_t *)(irijob->content); - res->ipclen = irijob->contentlen; - res->header.intercepttype = htons(OPENLI_PROTO_ETSI_IRI); - wandder_release_encoded_result(enc->encoder, body); /* Success */ @@ -693,19 +631,22 @@ static int encode_templated_umtscc(openli_encoder_t *enc, /* We have very specific templates for each observed packet size, so * this will not require updating */ - if (create_encoded_message_body(res, hdr_tplate, - umtscc_tplate->cc_content.cc_wrap, - umtscc_tplate->cc_content.cc_wrap_len, - job->liid, - job->preencoded[OPENLI_PREENCODE_LIID].vallen) < 0) { - return -1; + if (job->encryptmethod != OPENLI_PAYLOAD_ENCRYPTION_NONE) { + if (create_encrypted_message_body(enc, res, hdr_tplate, + umtscc_tplate->cc_content.cc_wrap, + umtscc_tplate->cc_content.cc_wrap_len, + (uint8_t *)ccjob->ipcontent, ccjob->ipclen, job) < 0) { + return -1; + } + } else { + if (create_etsi_encoded_result(res, hdr_tplate, + umtscc_tplate->cc_content.cc_wrap, + umtscc_tplate->cc_content.cc_wrap_len, + (uint8_t *)ccjob->ipcontent, ccjob->ipclen, job) < 0) { + return -1; + } } - /* Set ipcontents in the result */ - res->ipcontents = (uint8_t *)ccjob->ipcontent; - res->ipclen = ccjob->ipclen; - res->header.intercepttype = htons(OPENLI_PROTO_ETSI_CC); - /* Success */ return 1; @@ -756,20 +697,24 @@ static int encode_templated_emailcc(openli_encoder_t *enc, } /* We have very specific templates for each observed packet size, so * this will not require updating */ - - if (create_encoded_message_body(res, hdr_tplate, - emailcc_tplate->cc_content.cc_wrap, - emailcc_tplate->cc_content.cc_wrap_len, - job->liid, - job->preencoded[OPENLI_PREENCODE_LIID].vallen) < 0) { - return -1; + if (job->encryptmethod != OPENLI_PAYLOAD_ENCRYPTION_NONE) { + if (create_encrypted_message_body(enc, res, hdr_tplate, + emailcc_tplate->cc_content.cc_wrap, + emailcc_tplate->cc_content.cc_wrap_len, + (uint8_t *)emailccjob->cc_content, + emailccjob->cc_content_len, job) < 0) { + return -1; + } + } else { + if (create_etsi_encoded_result(res, hdr_tplate, + emailcc_tplate->cc_content.cc_wrap, + emailcc_tplate->cc_content.cc_wrap_len, + (uint8_t *)emailccjob->cc_content, + emailccjob->cc_content_len, job) < 0) { + return -1; + } } - /* Set ipcontents in the result */ - res->ipcontents = (uint8_t *)emailccjob->cc_content; - res->ipclen = emailccjob->cc_content_len; - res->header.intercepttype = htons(OPENLI_PROTO_ETSI_CC); - /* Success */ return 1; } @@ -804,20 +749,24 @@ static int encode_templated_ipcc(openli_encoder_t *enc, } /* We have very specific templates for each observed packet size, so * this will not require updating */ - - if (create_encoded_message_body(res, hdr_tplate, - ipcc_tplate->cc_content.cc_wrap, - ipcc_tplate->cc_content.cc_wrap_len, - job->liid, - job->preencoded[OPENLI_PREENCODE_LIID].vallen) < 0) { - return -1; + if (job->encryptmethod != OPENLI_PAYLOAD_ENCRYPTION_NONE) { + if (create_encrypted_message_body(enc, res, hdr_tplate, + ipcc_tplate->cc_content.cc_wrap, + ipcc_tplate->cc_content.cc_wrap_len, + (uint8_t *)ipccjob->ipcontent, + ipccjob->ipclen, job) < 0) { + return -1; + } + } else { + if (create_etsi_encoded_result(res, hdr_tplate, + ipcc_tplate->cc_content.cc_wrap, + ipcc_tplate->cc_content.cc_wrap_len, + (uint8_t *)ipccjob->ipcontent, + ipccjob->ipclen, job) < 0) { + return -1; + } } - /* Set ipcontents in the result */ - res->ipcontents = (uint8_t *)ipccjob->ipcontent; - res->ipclen = ipccjob->ipclen; - res->header.intercepttype = htons(OPENLI_PROTO_ETSI_CC); - /* Success */ return 1; @@ -960,6 +909,9 @@ static int process_job(openli_encoder_t *enc, void *socket) { if (job.liid) { free(job.liid); } + if (job.encryptkey) { + free(job.encryptkey); + } if (job.origreq) { free_published_message(job.origreq); } @@ -974,6 +926,9 @@ static int process_job(openli_encoder_t *enc, void *socket) { result[batch].origreq = job.origreq; result[batch].encodedby = enc->workerid; + if (job.encryptkey) { + free(job.encryptkey); + } batch++; } diff --git a/src/collector/encoder_worker.h b/src/collector/encoder_worker.h index b8051e2e..0e1195de 100644 --- a/src/collector/encoder_worker.h +++ b/src/collector/encoder_worker.h @@ -37,6 +37,7 @@ #include "netcomms.h" #include "etsili_core.h" #include "export_shared.h" +#include "etsiencoding/etsiencoding.h" enum { TEMPLATE_TYPE_IPCC_DIRFROM, diff --git a/src/collector/etsiencoding/encryptcontainer.c b/src/collector/etsiencoding/encryptcontainer.c new file mode 100644 index 00000000..17e0dcbf --- /dev/null +++ b/src/collector/etsiencoding/encryptcontainer.c @@ -0,0 +1,458 @@ +/* + * + * Copyright (c) 2023 The OpenLI Foundation + * 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 +#include +#include +#include +#include +#include "etsili_core.h" +#include "logger.h" +#include "intercept.h" +#include "etsiencoding.h" + +static void DEVDEBUG_dump_contents(uint8_t *buf, uint16_t len) { + + int i = 0; + FILE *f; + + for (i = 0; i < len; i++) { + printf("%02x ", *(buf + i)); + if ((i % 16) == 15) { + printf("\n"); + } + } + printf("\n"); + + f = fopen("/tmp/encrypt.debug", "w"); + fwrite(buf, len, 1, f); + fclose(f); + +} + +static inline uint32_t job_origreq_to_encrypted_payload_type( + openli_encoding_job_t *job) { + + switch(job->origreq->type) { + case OPENLI_EXPORT_EMAILIRI: + case OPENLI_EXPORT_EMAILCC: + return OPENLI_ENCRYPTED_PAYLOAD_TYPE_PART2; + case OPENLI_EXPORT_IPCC: + case OPENLI_EXPORT_IPIRI: + return OPENLI_ENCRYPTED_PAYLOAD_TYPE_PART3; + case OPENLI_EXPORT_UMTSCC: + case OPENLI_EXPORT_UMTSIRI: + return OPENLI_ENCRYPTED_PAYLOAD_TYPE_PART7; + case OPENLI_EXPORT_IPMMCC: + case OPENLI_EXPORT_IPMMIRI: + return OPENLI_ENCRYPTED_PAYLOAD_TYPE_PART5; + } + + return OPENLI_ENCRYPTED_PAYLOAD_TYPE_UNKNOWN; +} + +void etsili_destroy_encrypted_templates(openli_encoder_t *enc) { + Word_t indexint; + PWord_t pval; + int rcint; + + indexint = 0; + JLF(pval, enc->saved_encryption_templates, indexint); + while (pval) { + encoded_encrypt_template_t *t; + + t = (encoded_encrypt_template_t *)(*pval); + if (t->start) { + free(t->start); + } + free(t); + JLN(pval, enc->saved_encryption_templates, indexint); + } + JLFA(rcint, enc->saved_encryption_templates); + + +} + +static int encode_encrypt_container(wandder_encoder_t *encoder, + wandder_encode_job_t *precomputed, payload_encryption_method_t method, + uint8_t *enccontent, uint16_t enclen, openli_encoding_job_t *job) { + + wandder_encode_job_t *jobarray[3]; + uint32_t payloadtype = job_origreq_to_encrypted_payload_type(job); + + jobarray[0] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_2]); // Payload + jobarray[1] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_4]); // encryptionContainer + + + if (method == OPENLI_PAYLOAD_ENCRYPTION_AES_192_CBC) { + jobarray[2] = &(precomputed[OPENLI_PREENCODE_AES_192_CBC]); + } else { + jobarray[2] = &(precomputed[OPENLI_PREENCODE_NO_ENCRYPTION]); + } + + wandder_encode_next_preencoded(encoder, jobarray, 3); + + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, enccontent, enclen); + + wandder_encode_next(encoder, WANDDER_TAG_ENUM, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, &payloadtype, + sizeof(uint32_t)); + END_ENCODED_SEQUENCE(encoder, 2); + return 0; +} + +static int etsili_update_encrypted_template( + encoded_encrypt_template_t *tplate, uint8_t *enccontent, + uint16_t enclen, openli_encoding_job_t *job) { + + uint32_t payloadtype = job_origreq_to_encrypted_payload_type(job); + uint8_t ptype; + assert(enclen == tplate->payloadlen); + assert(payloadtype < 255); + + memcpy(tplate->payload, enccontent, enclen); + + ptype = (payloadtype & 0xff); + memcpy(tplate->payload_type, &ptype, sizeof(uint8_t)); + return 0; +} + +static int etsili_create_encrypted_template(wandder_encoder_t *encoder, + wandder_encode_job_t *precomputed, payload_encryption_method_t method, + uint8_t *enccontent, uint16_t enclen, + encoded_encrypt_template_t *tplate, openli_encoding_job_t *job) { + + wandder_encoded_result_t *encres; + wandder_decoder_t *dec; + + if (tplate == NULL) { + logger(LOG_INFO, "OpenLI: called etsili_create_encrypted_template with NULL template?"); + return -1; + } + + if (encoder == NULL) { + logger(LOG_INFO, "OpenLI: called etsili_create_encrypted_template with NULL encoder?"); + return -1; + } + + reset_wandder_encoder(encoder); + if (encode_encrypt_container(encoder, precomputed, method, enccontent, + enclen, job) < 0){ + return -1; + } + encres = wandder_encode_finish(encoder); + + if (encres == NULL || encres->len == 0 || encres->encoded == NULL) { + logger(LOG_INFO, "OpenLI: failed to encode ETSI encrypted container for template"); + if (encres) { + wandder_release_encoded_result(encoder, encres); + } + return -1; + } + + /* Copy the encoded header to the template */ + tplate->start = malloc(encres->len); + memcpy(tplate->start, encres->encoded, encres->len); + tplate->totallen = encres->len; + + + /* Find the encryptionPayload and save a pointer to the value location so + * we can overwrite it when another encrypted record wants to use this + * template. + */ + dec = init_wandder_decoder(NULL, tplate->start, tplate->totallen, 0); + if (dec == NULL) { + logger(LOG_INFO, "OpenLI: unable to create decoder for templated ETSI encrypted payload"); + return -1; + } + + wandder_decode_next(dec); // payload + wandder_decode_next(dec); // encryptionContainer + wandder_decode_next(dec); // encryptionType + wandder_decode_next(dec); // encryptedPayload + + tplate->payload = wandder_get_itemptr(dec); + tplate->payloadlen = enclen; + wandder_decode_next(dec); // encryptedPayloadType + tplate->payload_type = wandder_get_itemptr(dec); + + /* Release the encoded result -- the caller will use the templated copy */ + wandder_release_encoded_result(encoder, encres); + free_wandder_decoder(dec); + return 0; +} + +static encoded_encrypt_template_t *lookup_encrypted_template( + openli_encoder_t *enc, uint16_t length, + payload_encryption_method_t method, uint8_t *is_new) { + + PWord_t pval; + uint32_t key; + encoded_encrypt_template_t *tplate = NULL; + + key = (method << 16) + length; + JLG(pval, enc->saved_encryption_templates, key); + + if (pval == NULL) { + tplate = calloc(1, sizeof(encoded_encrypt_template_t)); + tplate->key = key; + JLI(pval, enc->saved_encryption_templates, key); + *pval = (Word_t)tplate; + *is_new = 1; + } else { + tplate = (encoded_encrypt_template_t *)(*pval); + *is_new = 0; + } + + return tplate; +} + +static int encrypt_aes_192_cbc(EVP_CIPHER_CTX *ctx, + uint8_t *buf, uint16_t buflen, uint8_t *dest, + uint16_t destlen, uint32_t seqno, char *encryptkey) { + + uint8_t IV_128[16]; + uint8_t key[24]; + uint32_t swapseqno; + size_t keylen = strlen(encryptkey); + int len, i; + + assert(buflen <= destlen); + + /* Generate the IV */ + swapseqno = htonl(seqno); + + for (i = 0; i < 16; i+=sizeof(uint32_t)) { + memcpy(&(IV_128[i]), &swapseqno, sizeof(uint32_t)); + } + + if (keylen > 24) { + keylen = 24; + } + memset(key, 0, 24); + memcpy(key, encryptkey, keylen); + + /* Do the encryption */ + if (EVP_EncryptInit_ex(ctx, EVP_aes_192_cbc(), NULL, key, IV_128) != 1) { + logger(LOG_INFO, "OpenLI: unable to initialise EVP encryption operation -- openssl error %s", ERR_error_string(ERR_get_error(), NULL)); + return -1; + } + + if (EVP_EncryptUpdate(ctx, dest, &len, buf, (int)buflen) != 1) { + logger(LOG_INFO, "OpenLI: unable to perform EVP encryption operation -- openssl error %s", ERR_error_string(ERR_get_error(), NULL)); + return -1; + } + + if (EVP_EncryptFinal_ex(ctx, dest + len, &len) != 1) { + logger(LOG_INFO, "OpenLI: unable to finish EVP encryption operation -- openssl error %s", ERR_error_string(ERR_get_error(), NULL)); + return -1; + } + + return 0; + +} + +int create_encrypted_message_body(openli_encoder_t *enc, + openli_encoded_result_t *res, + encoded_header_template_t *hdr_tplate, + uint8_t *payloadbody, uint16_t bodylen, + uint8_t *ipcontents, uint16_t ipclen, + openli_encoding_job_t *job) { + + uint32_t inplen; + uint32_t enclen = 0, newbodylen = 0; + uint8_t containerlen = 0, is_new = 0; + uint8_t *buf, *ptr; + uint8_t *encrypted; + uint32_t bytecounter; + uint32_t bc_increase; + encoded_encrypt_template_t *tplate = NULL; + + if (payloadbody == NULL) { + logger(LOG_INFO, "OpenLI: cannot encrypt an ETSI PDU that does not have valid encoded payload"); + return -1; + } + + /* Calculate length of encryptable data, including padding. */ + inplen = bodylen; + inplen += 10; // 10 bytes for byteCounter + newbodylen = inplen; + if (inplen < 128) { + inplen += 2; // 2 bytes (1 for identifier, 1 for length) for + // EncryptedPayload + containerlen = 1; + } else if (inplen < 32768) { + inplen += 4; // 3 bytes (1 for identifer, 3 for length) + containerlen = 3; + } else { + inplen += 5; // inplen can't exceed 65536, so we can cap this at + // 4 length bytes + containerlen = 4; + } + + if (job->encryptmethod == OPENLI_PAYLOAD_ENCRYPTION_AES_192_CBC) { + enclen = AES_OUTPUT_SIZE(inplen); + } else { + enclen = inplen; + } + + /* Add 16 bytes extra, just to be safe... + */ + buf = calloc(enclen + 16, sizeof(uint8_t)); + encrypted = calloc(enclen + 16, sizeof(uint8_t)); + + /* Take the contents of body_tplate (minus the initial "payload" field). + * Add EncryptedPayload and byteCounter fields to the front to get + * the "unencrypted" version of the payload. + * + * We shouldn't need the overhead of an encoder to add the two preceding + * fields (I hope). + */ + + /* Starting with the EncryptedPayload header -- a bit fiddly because of + * the different possible sizes for the length field */ + ptr = buf; + *ptr = 0x30; + ptr ++; + + if (containerlen > 1) { + *ptr = ((uint8_t)(containerlen - 1)) | 0x80; + ptr ++; + } + + if (newbodylen >= 32768) { + *ptr = (uint8_t)(newbodylen >> 16); + ptr ++; + } + if (newbodylen >= 128) { + *ptr = (uint8_t)(newbodylen >> 8); + ptr ++; + } + *ptr = (uint8_t)(newbodylen & 0xff); + ptr ++; + + /* Now do the byteCounter */ + *ptr = 0x80; /* field 0 */ + ptr++; + *ptr = 0x08; /* length is always 8 */ + ptr++; + + /* next four bytes are the unix timestamp when we first started */ + if (enc->encrypt_byte_startts == 0) { + struct timeval tv; + gettimeofday(&tv, NULL); + /* this never changes so we can just store it pre-byteswapped */ + enc->encrypt_byte_startts = htonl(tv.tv_sec); + } + memcpy(ptr, &enc->encrypt_byte_startts, sizeof(uint32_t)); + + ptr += sizeof(uint32_t); + + /* followed by the byte counter (in network byte order) */ + bytecounter = htonl(enc->encrypt_byte_counter); + memcpy(ptr, &bytecounter, sizeof(uint32_t)); + ptr += sizeof(uint32_t); + + /* Of course, byte counter has to be incremented based on the size + * of the "unencrypted" record, not the encrypted one... + */ + bc_increase = calculate_pspdu_length(inplen + hdr_tplate->header_len); + enc->encrypt_byte_counter += bc_increase; + + + /* Put the body contents and any additional IP packet content into + * the buffer to be encrypted + */ + if (payloadbody != NULL) { + memcpy(ptr, payloadbody, bodylen - ipclen); + /* "payload" is item 2 in a PS-PDU, but is item 1 in an encrypted + * container :shrug: + */ + *ptr = 0xA1; + ptr += (bodylen - ipclen); + } + + if (ipcontents != NULL) { + memcpy(ptr, ipcontents, ipclen); + ptr += ipclen; + } + + /* If this is our first time through, we'll need an encryption context */ + if (enc->evp_ctx == NULL) { + enc->evp_ctx = EVP_CIPHER_CTX_new(); + if (enc->evp_ctx == NULL) { + logger(LOG_INFO, "OpenLI: unable to create EVP encryption context -- openssl error %s", ERR_error_string(ERR_get_error(), NULL)); + return -1; + } + } + + /* Do the encryption */ + if (job->encryptmethod == OPENLI_PAYLOAD_ENCRYPTION_AES_192_CBC) { + if (encrypt_aes_192_cbc(enc->evp_ctx, buf, enclen, encrypted, enclen, + job->seqno, job->encryptkey) < 0) { + return -1; + } + } else { + memcpy(encrypted, buf, enclen); + } + + free(buf); + + /* Lookup the template for a message of this length and encryption method */ + tplate = lookup_encrypted_template(enc, enclen, job->encryptmethod, + &is_new); + + /* If we need to create a template, then do so -- otherwise, update + * the one that we already have. + */ + if (is_new) { + if (etsili_create_encrypted_template(enc->encoder, job->preencoded, + job->encryptmethod, encrypted, enclen, tplate, job) < 0) { + free(encrypted); + return -1; + } + } else { + if (etsili_update_encrypted_template(tplate, encrypted, enclen, + job) < 0) { + free(encrypted); + return -1; + } + } + + /* We should now have a suitable header template and body template to + * create a complete ETSI PSPDU record */ + if (create_etsi_encoded_result(res, hdr_tplate, tplate->start, + tplate->totallen, NULL, 0, job) < 0) { + free(encrypted); + return -1; + } + + free(encrypted); + return 0; +} + +// vim: set sw=4 tabstop=4 softtabstop=4 expandtab : diff --git a/src/collector/etsiencoding/etsiencoding.c b/src/collector/etsiencoding/etsiencoding.c new file mode 100644 index 00000000..d4b2e3a1 --- /dev/null +++ b/src/collector/etsiencoding/etsiencoding.c @@ -0,0 +1,133 @@ +/* + * + * Copyright (c) 2023 The OpenLI Foundation + * 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 +#include +#include "etsili_core.h" +#include "logger.h" +#include "intercept.h" +#include "etsiencoding.h" + +static inline uint8_t encode_pspdu_sequence(uint8_t *space, uint8_t space_len, + uint32_t contentsize, char *liid, uint16_t liidlen) { + + uint8_t len_space_req = DERIVE_INTEGER_LENGTH(contentsize); + int i; + uint16_t l; + + if (liidlen > space_len - 8) { + logger(LOG_INFO, + "OpenLI: invalid LIID for PSPDU: %s (%u %u)", liid, liidlen, space_len); + return 0; + } + + l = htons(liidlen); + memcpy(space, &l, sizeof(uint16_t)); + memcpy(space + 2, liid, liidlen); + space += (2 + liidlen); + + *space = (uint8_t)((WANDDER_CLASS_UNIVERSAL_CONSTRUCT << 5) | + WANDDER_TAG_SEQUENCE); + space ++; + + if (len_space_req == 1) { + *space = (uint8_t)contentsize; + return 2 + (2 + liidlen); + } + + *space = len_space_req | 0x80; + space ++; + + for (i = len_space_req - 1; i >= 0; i--) { + *(space + i) = (contentsize & 0xff); + contentsize = contentsize >> 8; + } + + return len_space_req + 2 + (2 + liidlen); +} + + +int create_etsi_encoded_result(openli_encoded_result_t *res, + encoded_header_template_t *hdr_tplate, + uint8_t *body_content, uint16_t bodylen, + uint8_t *trailing, uint16_t traillen, + openli_encoding_job_t *job) { + + uint8_t pspdu[108]; + uint8_t pspdu_len; + + /* Create a msgbody by concatenating hdr_tplate and body, plus + * a preceding pS-PDU sequence with the appropriate length... + */ + pspdu_len = encode_pspdu_sequence(pspdu, sizeof(pspdu), + hdr_tplate->header_len + bodylen, job->liid, + job->preencoded[OPENLI_PREENCODE_LIID].vallen); + + if (pspdu_len == 0) { + return -1; + } + + res->msgbody = calloc(1, sizeof(wandder_encoded_result_t)); + res->msgbody->encoder = NULL; + res->msgbody->len = pspdu_len + hdr_tplate->header_len + bodylen; + + res->msgbody->encoded = malloc(res->msgbody->len); + res->msgbody->alloced = res->msgbody->len; + res->msgbody->next = NULL; + + memcpy(res->msgbody->encoded, pspdu, pspdu_len); + memcpy(res->msgbody->encoded + pspdu_len, hdr_tplate->header, + hdr_tplate->header_len); + memcpy(res->msgbody->encoded + pspdu_len + hdr_tplate->header_len, + body_content, bodylen); + + /* Set the remaining msg->header properties */ + res->header.magic = htonl(OPENLI_PROTO_MAGIC); + res->header.bodylen = htons(res->msgbody->len); + res->header.internalid = 0; + + switch(job->origreq->type) { + case OPENLI_EXPORT_IPCC: + case OPENLI_EXPORT_IPMMCC: + case OPENLI_EXPORT_UMTSCC: + case OPENLI_EXPORT_EMAILCC: + res->header.intercepttype = htons(OPENLI_PROTO_ETSI_CC); + break; + case OPENLI_EXPORT_IPIRI: + case OPENLI_EXPORT_IPMMIRI: + case OPENLI_EXPORT_UMTSIRI: + case OPENLI_EXPORT_EMAILIRI: + res->header.intercepttype = htons(OPENLI_PROTO_ETSI_IRI); + break; + } + + res->ipcontents = trailing; + res->ipclen = traillen; + + return 0; +} + +// vim: set sw=4 tabstop=4 softtabstop=4 expandtab : diff --git a/src/collector/etsiencoding/etsiencoding.h b/src/collector/etsiencoding/etsiencoding.h new file mode 100644 index 00000000..69c87d57 --- /dev/null +++ b/src/collector/etsiencoding/etsiencoding.h @@ -0,0 +1,83 @@ +/* + * + * Copyright (c) 2023 The OpenLI Foundation + * 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_ETSIENCODING_H_ +#define OPENLI_ETSIENCODING_H_ + +#include +#include +#include +#include +#include + +#include "intercept.h" +#include "etsili_core.h" +#include "collector_base.h" + +/* 16 byte block size for AES, and 16 bytes for the IV + * + * size = ((input_size + block_size - 1) / block_size) * block_size + */ +#define AES_OUTPUT_SIZE(inpsize) \ + (((inpsize + 16 - 1) / 16) * 16) + +typedef struct encoded_encrypt_template { + uint32_t key; + uint32_t totallen; + uint32_t payloadlen; + uint8_t *start; + uint8_t *payload; + uint8_t *payload_type; +} encoded_encrypt_template_t; + +enum { + OPENLI_ENCRYPTED_PAYLOAD_TYPE_UNKNOWN = 1, + OPENLI_ENCRYPTED_PAYLOAD_TYPE_PART2 = 2, + OPENLI_ENCRYPTED_PAYLOAD_TYPE_PART3 = 3, + OPENLI_ENCRYPTED_PAYLOAD_TYPE_PART4 = 4, + OPENLI_ENCRYPTED_PAYLOAD_TYPE_PART5 = 5, + OPENLI_ENCRYPTED_PAYLOAD_TYPE_PART6 = 6, + OPENLI_ENCRYPTED_PAYLOAD_TYPE_PART7 = 7, + OPENLI_ENCRYPTED_PAYLOAD_TYPE_PART1 = 8 +}; + +int create_encrypted_message_body(openli_encoder_t *enc, + openli_encoded_result_t *res, + encoded_header_template_t *hdr_tplate, + uint8_t *payloadbody, uint16_t bodylen, + uint8_t *ipcontents, uint16_t ipclen, + openli_encoding_job_t *job); + +int create_etsi_encoded_result(openli_encoded_result_t *res, + encoded_header_template_t *hdr_tplate, + uint8_t *body_content, uint16_t bodylen, + uint8_t *trailing, uint16_t traillen, + openli_encoding_job_t *job); + +void etsili_destroy_encrypted_templates(openli_encoder_t *enc); +#endif + +// vim: set sw=4 tabstop=4 softtabstop=4 expandtab : diff --git a/src/collector/export_shared.h b/src/collector/export_shared.h index e3baafd8..0a67229d 100644 --- a/src/collector/export_shared.h +++ b/src/collector/export_shared.h @@ -32,6 +32,7 @@ #include #include "etsili_core.h" +#include "intercept.h" typedef struct exporter_intercept_msg { char *liid; @@ -40,6 +41,9 @@ typedef struct exporter_intercept_msg { int authcc_len; char *delivcc; int delivcc_len; + + payload_encryption_method_t encryptmethod; + char *encryptkey; } exporter_intercept_msg_t; typedef struct cin_seqno { diff --git a/src/configparser.c b/src/configparser.c index 1635297c..b23fc238 100644 --- a/src/configparser.c +++ b/src/configparser.c @@ -700,6 +700,22 @@ static void parse_intercept_common_fields(intercept_common_t *common, SET_CONFIG_STRING_OPTION(common->targetagency, value); } + if (key->type == YAML_SCALAR_NODE && + value->type == YAML_SCALAR_NODE && + strcmp((char *)key->data.scalar.value, "payloadencryption") == 0) { + if (strcasecmp((char *)value->data.scalar.value, "none") == 0) { + common->encrypt = OPENLI_PAYLOAD_ENCRYPTION_NONE; + } else if (strcasecmp((char *)value->data.scalar.value, "aes-192-cbc") == 0) { + common->encrypt = OPENLI_PAYLOAD_ENCRYPTION_AES_192_CBC; + } + } + + if (key->type == YAML_SCALAR_NODE && + value->type == YAML_SCALAR_NODE && + strcmp((char *)key->data.scalar.value, "encryptionkey") == 0) { + SET_CONFIG_STRING_OPTION(common->encryptkey, value); + } + if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && strcmp((char *)key->data.scalar.value, "outputhandovers") == 0) { @@ -732,9 +748,11 @@ static int parse_emailintercept_list(emailintercept_t **mailints, 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; newcept->awaitingconfirm = 1; newcept->targets = NULL; @@ -757,6 +775,16 @@ static int parse_emailintercept_list(emailintercept_t **mailints, } tgtcount = HASH_CNT(hh, newcept->targets); + if (newcept->common.encryptkey == NULL && + newcept->common.encrypt != OPENLI_PAYLOAD_ENCRYPTION_NONE) { + if (newcept->common.liid == NULL) { + newcept->common.liid = strdup("unidentified intercept"); + } + logger(LOG_INFO, "OpenLI: Email intercept configuration for '%s' asks for encryption but has not provided an encryption key -- skipping", + newcept->common.liid); + free_single_emailintercept(newcept); + continue; + } if (newcept->common.liid != NULL && newcept->common.authcc != NULL && newcept->common.delivcc != NULL && tgtcount > 0 && @@ -766,7 +794,9 @@ static int parse_emailintercept_list(emailintercept_t **mailints, newcept->common.liid_len, newcept); } else { logger(LOG_INFO, "OpenLI: Email Intercept configuration was incomplete -- skipping."); + free_single_emailintercept(newcept); } + } return 0; @@ -799,12 +829,14 @@ static int parse_voipintercept_list(voipintercept_t **voipints, 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; @@ -824,6 +856,16 @@ static int parse_voipintercept_list(voipintercept_t **voipints, } + if (newcept->common.encryptkey == NULL && + newcept->common.encrypt != OPENLI_PAYLOAD_ENCRYPTION_NONE) { + if (newcept->common.liid == NULL) { + newcept->common.liid = strdup("unidentified intercept"); + } + logger(LOG_INFO, "OpenLI: VoIP intercept configuration for '%s' asks for encryption but has not provided an encryption key -- skipping", + newcept->common.liid); + free_single_voipintercept(newcept); + continue; + } if (newcept->common.liid != NULL && newcept->common.authcc != NULL && newcept->common.delivcc != NULL && libtrace_list_get_size(newcept->targets) > 0 && @@ -833,6 +875,7 @@ static int parse_voipintercept_list(voipintercept_t **voipints, newcept->common.liid_len, newcept); } else { logger(LOG_INFO, "OpenLI: VOIP Intercept configuration was incomplete -- skipping."); + free_single_voipintercept(newcept); } } @@ -862,6 +905,7 @@ static int parse_ipintercept_list(ipintercept_t **ipints, yaml_document_t *doc, 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; @@ -875,6 +919,7 @@ static int parse_ipintercept_list(ipintercept_t **ipints, yaml_document_t *doc, 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; @@ -947,6 +992,17 @@ static int parse_ipintercept_list(ipintercept_t **ipints, yaml_document_t *doc, } } + if (newcept->common.encryptkey == NULL && + newcept->common.encrypt != OPENLI_PAYLOAD_ENCRYPTION_NONE) { + if (newcept->common.liid == NULL) { + newcept->common.liid = strdup("unidentified intercept"); + } + logger(LOG_INFO, "OpenLI: IP intercept configuration for '%s' asks for encryption but has not provided an encryption key -- skipping", + newcept->common.liid); + free_single_ipintercept(newcept); + continue; + } + if (newcept->common.liid != NULL && newcept->common.authcc != NULL && newcept->common.delivcc != NULL && newcept->username != NULL && @@ -966,6 +1022,7 @@ static int parse_ipintercept_list(ipintercept_t **ipints, yaml_document_t *doc, logger(LOG_INFO, "OpenLI: provisioner configuration error: 'user' must be specified for an IP intercept"); } logger(LOG_INFO, "OpenLI: IP Intercept configuration was incomplete -- skipping."); + free_single_ipintercept(newcept); } } diff --git a/src/etsili_core.c b/src/etsili_core.c index c590ab77..bc896f61 100644 --- a/src/etsili_core.c +++ b/src/etsili_core.c @@ -43,9 +43,6 @@ uint8_t etsi_emailccoid[4] = {0x05, 0x02, 0x0f, 0x02}; uint8_t etsi_umtsirioid[9] = {0x00, 0x04, 0x00, 0x02, 0x02, 0x04, 0x01, 0x0f, 0x05}; uint8_t etsi_hi1operationoid[8] = {0x00, 0x04, 0x00, 0x02, 0x02, 0x00, 0x01, 0x06}; -#define END_ENCODED_SEQUENCE(enc, x) \ - wandder_encode_endseq_repeat(enc, x); - static inline void encode_tri_body(wandder_encoder_t *encoder) { ENC_CSEQUENCE(encoder, 2); // Payload ENC_CSEQUENCE(encoder, 2); // TRIPayload @@ -1241,6 +1238,7 @@ void etsili_preencode_static_fields( wandder_encode_job_t *p; int tvclass = 1; uint32_t dirin = 0, dirout = 1, dirunk = 2; + uint32_t noencrypt = 1, aes_192_cbc = 3; memset(pendarray, 0, sizeof(wandder_encode_job_t) * OPENLI_PREENCODE_LAST); @@ -1428,6 +1426,18 @@ void etsili_preencode_static_fields( p->encodeas = WANDDER_TAG_ENUM; wandder_encode_preencoded_value(p, &dirunk, sizeof(dirunk)); + p = &(pendarray[OPENLI_PREENCODE_NO_ENCRYPTION]); + p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; + p->identifier = 0; + p->encodeas = WANDDER_TAG_ENUM; + wandder_encode_preencoded_value(p, &noencrypt, sizeof(noencrypt)); + + p = &(pendarray[OPENLI_PREENCODE_AES_192_CBC]); + p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; + p->identifier = 0; + p->encodeas = WANDDER_TAG_ENUM; + wandder_encode_preencoded_value(p, &aes_192_cbc, sizeof(aes_192_cbc)); + } void etsili_clear_preencoded_fields(wandder_encode_job_t *pendarray) { @@ -1816,4 +1826,21 @@ int etsili_create_ipcc_template(wandder_encoder_t *encoder, } +inline uint8_t DERIVE_INTEGER_LENGTH(uint64_t x) { + if (x < 128) return 1; + if (x < 32768) return 2; + if (x < 8388608) return 3; + if (x < 2147483648) return 4; + return 5; +} + +int calculate_pspdu_length(uint32_t contentsize) { + uint8_t len_space_req = DERIVE_INTEGER_LENGTH(contentsize); + + if (len_space_req == 1) { + return contentsize + 2; + } + return len_space_req + 2 + contentsize; +} + // vim: set sw=4 tabstop=4 softtabstop=4 expandtab : diff --git a/src/etsili_core.h b/src/etsili_core.h index 0651ac12..955050c5 100644 --- a/src/etsili_core.h +++ b/src/etsili_core.h @@ -39,6 +39,9 @@ #define ENC_CSEQUENCE(enc, x) wandder_encode_next(enc, WANDDER_TAG_SEQUENCE, \ WANDDER_CLASS_CONTEXT_CONSTRUCT, x, NULL, 0) +#define END_ENCODED_SEQUENCE(enc, x) \ + wandder_encode_endseq_repeat(enc, x); + #define ETSI_DIR_FROM_TARGET 0 #define ETSI_DIR_TO_TARGET 1 #define ETSI_DIR_INDETERMINATE 2 @@ -186,6 +189,8 @@ typedef enum { OPENLI_PREENCODE_DIRFROM, OPENLI_PREENCODE_DIRTO, OPENLI_PREENCODE_DIRUNKNOWN, + OPENLI_PREENCODE_NO_ENCRYPTION, + OPENLI_PREENCODE_AES_192_CBC, OPENLI_PREENCODE_LAST } preencode_index_t; @@ -237,6 +242,9 @@ typedef struct encoded_global_template { encoded_cc_template_t cc_content; } encoded_global_template_t; +uint8_t DERIVE_INTEGER_LENGTH(uint64_t x); + +int calculate_pspdu_length(uint32_t contentsize); wandder_encoded_result_t *encode_umtscc_body(wandder_encoder_t *encoder, wandder_encode_job_t *precomputed, void *ipcontent, uint32_t iplen, diff --git a/src/intercept.c b/src/intercept.c index ef3fac77..39b11336 100644 --- a/src/intercept.c +++ b/src/intercept.c @@ -49,6 +49,13 @@ static inline void copy_intercept_common(intercept_common_t *src, dest->tostart_time = src->tostart_time; dest->toend_time = src->toend_time; dest->tomediate = src->tomediate; + dest->encrypt = src->encrypt; + + if (src->encryptkey) { + dest->encryptkey = strdup(src->encryptkey); + } else { + dest->encryptkey = NULL; + } } int are_sip_identities_same(openli_sip_identity_t *a, @@ -86,6 +93,17 @@ void intercept_mediation_mode_as_string(intercept_outputs_t mode, } +void intercept_encryption_mode_as_string(payload_encryption_method_t method, + char *space, int spacelen) { + + if (method == OPENLI_PAYLOAD_ENCRYPTION_AES_192_CBC) { + snprintf(space, spacelen, "AES-192-CBC"); + } else { + snprintf(space, spacelen, "None"); + } + +} + sipregister_t *create_sipregister(voipintercept_t *vint, char *callid, uint32_t cin) { sipregister_t *newreg; @@ -220,6 +238,10 @@ static inline void free_intercept_common(intercept_common_t *cept) { if (cept->targetagency) { free(cept->targetagency); } + + if (cept->encryptkey) { + free(cept->encryptkey); + } } char *list_email_targets(emailintercept_t *m, int maxchars) { @@ -933,6 +955,14 @@ const char *get_access_type_string(internet_access_method_t method) { return "undefined"; } +payload_encryption_method_t map_encrypt_method_string(char *encstr) { + if (strcasecmp(encstr, "aes-192-cbc") == 0) { + return OPENLI_PAYLOAD_ENCRYPTION_AES_192_CBC; + } + + return OPENLI_PAYLOAD_ENCRYPTION_NONE; +} + internet_access_method_t map_access_type_string(char *confstr) { if (strcasecmp(confstr, "dialup") == 0 || diff --git a/src/intercept.h b/src/intercept.h index c491fe76..106d7214 100644 --- a/src/intercept.h +++ b/src/intercept.h @@ -49,6 +49,17 @@ typedef enum { INTERNET_ACCESS_TYPE_MOBILE = 32, /* Not a "real" value */ } internet_access_method_t; +typedef enum { + OPENLI_PAYLOAD_ENCRYPTION_NOT_SPECIFIED = 0, + OPENLI_PAYLOAD_ENCRYPTION_NONE = 1, + OPENLI_PAYLOAD_ENCRYPTION_NATIONAL = 2, + OPENLI_PAYLOAD_ENCRYPTION_AES_192_CBC = 3, + OPENLI_PAYLOAD_ENCRYPTION_AES_256_CBC = 4, + OPENLI_PAYLOAD_ENCRYPTION_BLOWFISH_192_CBC = 5, + OPENLI_PAYLOAD_ENCRYPTION_BLOWFISH_256_CBC = 6, + OPENLI_PAYLOAD_ENCRYPTION_THREEDES_CBC = 7, +} payload_encryption_method_t; + typedef enum { OPENLI_VOIPINT_OPTION_IGNORE_COMFORT = 0, } voipintercept_options_t; @@ -93,6 +104,8 @@ typedef struct intercept_common { uint64_t tostart_time; uint64_t toend_time; intercept_outputs_t tomediate; + payload_encryption_method_t encrypt; + char *encryptkey; } intercept_common_t; typedef struct hi1_notify_data { @@ -212,24 +225,6 @@ typedef struct vendmirror_intercept vendmirror_intercept_t; typedef struct staticipsession staticipsession_t; typedef struct sipregister sipregister_t; -#define voip_intercept_equal(a,b) \ - ((strcmp(a->common.authcc, b->common.authcc) == 0) && \ - (strcmp(a->common.delivcc, b->common.delivcc) == 0) && \ - (strcmp(a->common.targetagency, b->common.targetagency) == 0) && \ - (a->common.tostart_time == b->common.tostart_time) && \ - (a->common.toend_time == b->common.toend_time) && \ - (a->common.tomediate == b->common.tomediate) && \ - (a->options == b->options)) - -#define email_intercept_equal(a,b) \ - ((strcmp(a->common.authcc, b->common.authcc) == 0) && \ - (strcmp(a->common.delivcc, b->common.delivcc) == 0) && \ - (strcmp(a->common.targetagency, b->common.targetagency) == 0) && \ - (a->common.tostart_time == b->common.tostart_time) && \ - (a->common.toend_time == b->common.toend_time) && \ - (a->common.tomediate == b->common.tomediate)) - - typedef struct voipintercept { uint64_t internalid; @@ -443,9 +438,12 @@ const char *get_access_type_string(internet_access_method_t method); const char *get_radius_ident_string(uint32_t radoptions); internet_access_method_t map_access_type_string(char *confstr); uint32_t map_radius_ident_string(char *confstr); +payload_encryption_method_t map_encrypt_method_string(char *encstr); void intercept_mediation_mode_as_string(intercept_outputs_t mode, char *space, int spacelen); +void intercept_encryption_mode_as_string(payload_encryption_method_t method, + char *space, int spacelen); #endif // vim: set sw=4 tabstop=4 softtabstop=4 expandtab : diff --git a/src/netcomms.c b/src/netcomms.c index 44c32983..9267a6a0 100644 --- a/src/netcomms.c +++ b/src/netcomms.c @@ -353,20 +353,85 @@ int push_lea_withdrawal_onto_net_buffer(net_buffer_t *nb, liagency_t *lea) { return (int)totallen; } +#define INTERCEPT_COMMON_LEN(common) \ + (common.liid_len + common.authcc_len + sizeof(common.tostart_time) + \ + sizeof(common.toend_time) + sizeof(common.tomediate) + \ + strlen(common.targetagency) + sizeof(common.destid) + \ + sizeof(common.encrypt) + common.delivcc_len + \ + (common.encryptkey ? (strlen(common.encryptkey) + 4) : 0) + (9 * 4)) + #define VENDMIRROR_IPINTERCEPT_MODIFY_BODY_LEN(ipint) \ - (ipint->common.liid_len + ipint->common.authcc_len + \ + (INTERCEPT_COMMON_LEN(ipint->common) + \ ipint->username_len + sizeof(ipint->accesstype) + \ - sizeof(ipint->options) + sizeof(ipint->common.tomediate) + \ - sizeof(ipint->common.tostart_time) + sizeof(ipint->common.toend_time) \ - + sizeof(ipint->vendmirrorid) + (9 * 4)) + sizeof(ipint->options) + sizeof(ipint->vendmirrorid) + (4 * 4)) #define IPINTERCEPT_MODIFY_BODY_LEN(ipint) \ - (ipint->common.liid_len + ipint->common.authcc_len + \ - ipint->common.delivcc_len + \ + (INTERCEPT_COMMON_LEN(ipint->common) + \ ipint->username_len + sizeof(ipint->accesstype) + \ - sizeof(ipint->common.tomediate) + \ - sizeof(ipint->common.tostart_time) + sizeof(ipint->common.toend_time) \ - + sizeof(ipint->options) + (9 * 4)) + sizeof(ipint->options) + (3 * 4)) + +static int _push_intercept_common_fields(net_buffer_t *nb, + intercept_common_t *common) { + + if (push_tlv(nb, OPENLI_PROTO_FIELD_LIID, (uint8_t *)common->liid, + strlen(common->liid)) == -1) { + return -1; + } + + if (push_tlv(nb, OPENLI_PROTO_FIELD_AUTHCC, (uint8_t *)common->authcc, + strlen(common->authcc)) == -1) { + return -1; + } + + if (push_tlv(nb, OPENLI_PROTO_FIELD_DELIVCC, (uint8_t *)common->delivcc, + strlen(common->delivcc)) == -1) { + return -1; + } + + if (push_tlv(nb, OPENLI_PROTO_FIELD_LEAID, (uint8_t *)common->targetagency, + strlen(common->targetagency)) == -1) { + return -1; + } + + if (push_tlv(nb, OPENLI_PROTO_FIELD_INTERCEPT_START_TIME, + (uint8_t *)&(common->tostart_time), + sizeof(common->tostart_time)) == -1) { + return -1; + } + + if (push_tlv(nb, OPENLI_PROTO_FIELD_INTERCEPT_END_TIME, + (uint8_t *)&(common->toend_time), + sizeof(common->toend_time)) == -1) { + return -1; + } + + if (push_tlv(nb, OPENLI_PROTO_FIELD_MEDIATORID, + (uint8_t *)&(common->destid), + sizeof(common->destid)) == -1) { + return -1; + } + + if (push_tlv(nb, OPENLI_PROTO_FIELD_TOMEDIATE, + (uint8_t *)&(common->tomediate), + sizeof(common->tomediate)) == -1) { + return -1; + } + + if (push_tlv(nb, OPENLI_PROTO_FIELD_PAYLOAD_ENCRYPTION, + (uint8_t *)&(common->encrypt), + sizeof(common->encrypt)) == -1) { + return -1; + } + + if (common->encryptkey) { + if (push_tlv(nb, OPENLI_PROTO_FIELD_ENCRYPTION_KEY, + (uint8_t *)(common->encryptkey), + strlen(common->encryptkey)) == -1) { + return -1; + } + } + +} static int _push_ipintercept_modify(net_buffer_t *nb, ipintercept_t *ipint) { @@ -395,20 +460,7 @@ static int _push_ipintercept_modify(net_buffer_t *nb, ipintercept_t *ipint) { } /* Push on each intercept field */ - - if (push_tlv(nb, OPENLI_PROTO_FIELD_LIID, (uint8_t *)ipint->common.liid, - strlen(ipint->common.liid)) == -1) { - goto pushmodfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_AUTHCC, (uint8_t *)ipint->common.authcc, - strlen(ipint->common.authcc)) == -1) { - goto pushmodfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_DELIVCC, - (uint8_t *)ipint->common.delivcc, - strlen(ipint->common.delivcc)) == -1) { + if (_push_intercept_common_fields(nb, &(ipint->common)) == -1) { goto pushmodfail; } @@ -437,24 +489,6 @@ static int _push_ipintercept_modify(net_buffer_t *nb, ipintercept_t *ipint) { } } - if (push_tlv(nb, OPENLI_PROTO_FIELD_INTERCEPT_START_TIME, - (uint8_t *)&(ipint->common.tostart_time), - sizeof(ipint->common.tostart_time)) == -1) { - goto pushmodfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_INTERCEPT_END_TIME, - (uint8_t *)&(ipint->common.toend_time), - sizeof(ipint->common.toend_time)) == -1) { - goto pushmodfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_TOMEDIATE, - (uint8_t *)&(ipint->common.tomediate), - sizeof(ipint->common.tomediate)) == -1) { - goto pushmodfail; - } - return (int)totallen; @@ -467,10 +501,7 @@ static int _push_ipintercept_modify(net_buffer_t *nb, ipintercept_t *ipint) { } #define EMAILINTERCEPT_MODIFY_BODY_LEN(em) \ - (em->common.liid_len + em->common.authcc_len + \ - em->common.delivcc_len + sizeof(em->common.toend_time) + \ - sizeof(em->common.tomediate) + \ - sizeof(em->common.tostart_time) + (6 * 4)) + (INTERCEPT_COMMON_LEN(em->common)) static int _push_emailintercept_modify(net_buffer_t *nb, emailintercept_t *em) { ii_header_t hdr; @@ -495,41 +526,10 @@ static int _push_emailintercept_modify(net_buffer_t *nb, emailintercept_t *em) { } /* Push on each intercept field */ - - if (push_tlv(nb, OPENLI_PROTO_FIELD_LIID, (uint8_t *)em->common.liid, - strlen(em->common.liid)) == -1) { - goto pushmodfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_AUTHCC, (uint8_t *)em->common.authcc, - strlen(em->common.authcc)) == -1) { - goto pushmodfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_DELIVCC, (uint8_t *)em->common.delivcc, - strlen(em->common.delivcc)) == -1) { - goto pushmodfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_INTERCEPT_START_TIME, - (uint8_t *)&(em->common.tostart_time), - sizeof(em->common.tostart_time)) == -1) { + if (_push_intercept_common_fields(nb, &(em->common)) == -1) { goto pushmodfail; } - if (push_tlv(nb, OPENLI_PROTO_FIELD_INTERCEPT_END_TIME, - (uint8_t *)&(em->common.toend_time), - sizeof(em->common.toend_time)) == -1) { - goto pushmodfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_TOMEDIATE, - (uint8_t *)&(em->common.tomediate), - sizeof(em->common.tomediate)) == -1) { - goto pushmodfail; - } - - return (int)totallen; pushmodfail: @@ -541,11 +541,8 @@ static int _push_emailintercept_modify(net_buffer_t *nb, emailintercept_t *em) { #define VOIPINTERCEPT_MODIFY_BODY_LEN(vint) \ - (vint->common.liid_len + vint->common.authcc_len + \ - vint->common.delivcc_len + \ - sizeof(vint->options) + sizeof(vint->common.toend_time) + \ - sizeof(vint->common.tomediate) + \ - sizeof(vint->common.tostart_time) + (7 * 4)) + (INTERCEPT_COMMON_LEN(vint->common) + \ + sizeof(vint->options) + (1 * 4)) static int _push_voipintercept_modify(net_buffer_t *nb, voipintercept_t *vint) { @@ -571,46 +568,15 @@ static int _push_voipintercept_modify(net_buffer_t *nb, voipintercept_t *vint) } /* Push on each intercept field */ - - if (push_tlv(nb, OPENLI_PROTO_FIELD_INTOPTIONS, - (uint8_t *)(&vint->options), sizeof(vint->options)) == -1) { - goto pushmodfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_LIID, (uint8_t *)vint->common.liid, - strlen(vint->common.liid)) == -1) { - goto pushmodfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_AUTHCC, (uint8_t *)vint->common.authcc, - strlen(vint->common.authcc)) == -1) { - goto pushmodfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_DELIVCC, (uint8_t *)vint->common.delivcc, - strlen(vint->common.delivcc)) == -1) { - goto pushmodfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_INTERCEPT_START_TIME, - (uint8_t *)&(vint->common.tostart_time), - sizeof(vint->common.tostart_time)) == -1) { - goto pushmodfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_INTERCEPT_END_TIME, - (uint8_t *)&(vint->common.toend_time), - sizeof(vint->common.toend_time)) == -1) { + if (_push_intercept_common_fields(nb, &(vint->common)) == -1) { goto pushmodfail; } - if (push_tlv(nb, OPENLI_PROTO_FIELD_TOMEDIATE, - (uint8_t *)&(vint->common.tomediate), - sizeof(vint->common.tomediate)) == -1) { + if (push_tlv(nb, OPENLI_PROTO_FIELD_INTOPTIONS, + (uint8_t *)(&vint->options), sizeof(vint->options)) == -1) { goto pushmodfail; } - return (int)totallen; pushmodfail: @@ -636,11 +602,7 @@ int push_intercept_modify_onto_net_buffer(net_buffer_t *nb, void *data, } #define EMAILINTERCEPT_BODY_LEN(em) \ - (em->common.liid_len + em->common.authcc_len + \ - em->common.delivcc_len + strlen(em->common.targetagency) + \ - sizeof(em->common.destid) + sizeof(em->common.tostart_time) + \ - sizeof(em->common.tomediate) + \ - sizeof(em->common.toend_time) + (8 * 4)) + (INTERCEPT_COMMON_LEN(em->common)) int push_emailintercept_onto_net_buffer(net_buffer_t *nb, void *data) { @@ -666,52 +628,7 @@ int push_emailintercept_onto_net_buffer(net_buffer_t *nb, void *data) { goto pushemailintfail; } - /* Push on each intercept field */ - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_LIID, - (uint8_t *)em->common.liid, - em->common.liid_len)) == -1) { - goto pushemailintfail; - } - - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_AUTHCC, - (uint8_t *)em->common.authcc, - em->common.authcc_len)) == -1) { - goto pushemailintfail; - } - - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_DELIVCC, - (uint8_t *)em->common.delivcc, - em->common.delivcc_len)) == -1) { - goto pushemailintfail; - } - - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_LEAID, - (uint8_t *)em->common.targetagency, - strlen(em->common.targetagency))) == -1) { - goto pushemailintfail; - } - - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_MEDIATORID, - (uint8_t *)&(em->common.destid), - sizeof(em->common.destid))) == -1) { - goto pushemailintfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_INTERCEPT_START_TIME, - (uint8_t *)&(em->common.tostart_time), - sizeof(em->common.tostart_time)) == -1) { - goto pushemailintfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_INTERCEPT_END_TIME, - (uint8_t *)&(em->common.toend_time), - sizeof(em->common.toend_time)) == -1) { - goto pushemailintfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_TOMEDIATE, - (uint8_t *)&(em->common.tomediate), - sizeof(em->common.tomediate)) == -1) { + if (_push_intercept_common_fields(nb, &(em->common)) == -1) { goto pushemailintfail; } @@ -725,12 +642,8 @@ int push_emailintercept_onto_net_buffer(net_buffer_t *nb, void *data) { } #define VOIPINTERCEPT_BODY_LEN(vint) \ - (vint->common.liid_len + vint->common.authcc_len + \ - vint->common.delivcc_len + strlen(vint->common.targetagency) + \ - sizeof(vint->common.destid) + sizeof(vint->options) \ - + sizeof(vint->common.tomediate) \ - + sizeof(vint->common.tostart_time) + sizeof(vint->common.toend_time) \ - + (9 * 4)) + (INTERCEPT_COMMON_LEN(vint->common) + sizeof(vint->options) + \ + (1 * 4)) #define INTERCEPT_WITHDRAW_BODY_LEN(liid, authcc) \ (strlen(liid) + strlen(authcc) + (2 * 4)) @@ -827,33 +740,7 @@ int push_voipintercept_onto_net_buffer(net_buffer_t *nb, void *data) { } /* Push on each intercept field */ - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_LIID, - (uint8_t *)vint->common.liid, - vint->common.liid_len)) == -1) { - goto pushvoipintfail; - } - - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_AUTHCC, - (uint8_t *)vint->common.authcc, - vint->common.authcc_len)) == -1) { - goto pushvoipintfail; - } - - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_DELIVCC, - (uint8_t *)vint->common.delivcc, - vint->common.delivcc_len)) == -1) { - goto pushvoipintfail; - } - - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_LEAID, - (uint8_t *)vint->common.targetagency, - strlen(vint->common.targetagency))) == -1) { - goto pushvoipintfail; - } - - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_MEDIATORID, - (uint8_t *)&(vint->common.destid), - sizeof(vint->common.destid))) == -1) { + if (_push_intercept_common_fields(nb, &(vint->common)) == -1) { goto pushvoipintfail; } @@ -862,24 +749,6 @@ int push_voipintercept_onto_net_buffer(net_buffer_t *nb, void *data) { goto pushvoipintfail; } - if (push_tlv(nb, OPENLI_PROTO_FIELD_INTERCEPT_START_TIME, - (uint8_t *)&(vint->common.tostart_time), - sizeof(vint->common.tostart_time)) == -1) { - goto pushvoipintfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_INTERCEPT_END_TIME, - (uint8_t *)&(vint->common.toend_time), - sizeof(vint->common.toend_time)) == -1) { - goto pushvoipintfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_TOMEDIATE, - (uint8_t *)&(vint->common.tomediate), - sizeof(vint->common.tomediate)) == -1) { - goto pushvoipintfail; - } - return (int)totallen; pushvoipintfail: @@ -1131,22 +1000,14 @@ int push_static_ipranges_onto_net_buffer(net_buffer_t *nb, } #define IPINTERCEPT_BODY_LEN(ipint) \ - (ipint->common.liid_len + ipint->common.authcc_len + \ - ipint->common.delivcc_len + \ - ipint->username_len + sizeof(ipint->common.destid) + \ - strlen(ipint->common.targetagency) + \ - sizeof(ipint->options) + sizeof(ipint->common.tomediate) + \ - sizeof(ipint->common.tostart_time) + sizeof(ipint->common.toend_time) \ - + sizeof(ipint->accesstype) + (11 * 4)) + (INTERCEPT_COMMON_LEN(ipint->common) + \ + ipint->username_len + sizeof(ipint->options) + \ + sizeof(ipint->accesstype) + (3 * 4)) #define VENDMIRROR_IPINTERCEPT_BODY_LEN(ipint) \ - (ipint->common.liid_len + ipint->common.authcc_len + \ - ipint->common.delivcc_len + ipint->username_len + \ - strlen(ipint->common.targetagency) + \ - sizeof(ipint->vendmirrorid) + sizeof(ipint->common.destid) + \ - sizeof(ipint->options) + sizeof(ipint->common.tomediate) + \ - sizeof(ipint->common.tostart_time) + sizeof(ipint->common.toend_time) \ - + sizeof(ipint->accesstype) + (12 * 4)) + (INTERCEPT_COMMON_LEN(ipint->common) + \ + ipint->username_len + sizeof(ipint->vendmirrorid) + \ + sizeof(ipint->options) + sizeof(ipint->accesstype) + (4 * 4)) int push_ipintercept_onto_net_buffer(net_buffer_t *nb, void *data) { @@ -1179,21 +1040,7 @@ int push_ipintercept_onto_net_buffer(net_buffer_t *nb, void *data) { } /* Push on each intercept field */ - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_LIID, - (uint8_t *)ipint->common.liid, - ipint->common.liid_len)) == -1) { - goto pushipintfail; - } - - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_AUTHCC, - (uint8_t *)ipint->common.authcc, - ipint->common.authcc_len)) == -1) { - goto pushipintfail; - } - - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_DELIVCC, - (uint8_t *)ipint->common.delivcc, - ipint->common.delivcc_len)) == -1) { + if (_push_intercept_common_fields(nb, &(ipint->common)) == -1) { goto pushipintfail; } @@ -1202,12 +1049,6 @@ int push_ipintercept_onto_net_buffer(net_buffer_t *nb, void *data) { goto pushipintfail; } - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_LEAID, - (uint8_t *)ipint->common.targetagency, - strlen(ipint->common.targetagency))) == -1) { - goto pushipintfail; - } - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_ACCESSTYPE, (uint8_t *)(&ipint->accesstype), sizeof(ipint->accesstype))) == -1) { @@ -1228,29 +1069,6 @@ int push_ipintercept_onto_net_buffer(net_buffer_t *nb, void *data) { } } - if ((ret = push_tlv(nb, OPENLI_PROTO_FIELD_MEDIATORID, - (uint8_t *)&(ipint->common.destid), - sizeof(ipint->common.destid))) == -1) { - goto pushipintfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_INTERCEPT_START_TIME, - (uint8_t *)&(ipint->common.tostart_time), - sizeof(ipint->common.tostart_time)) == -1) { - goto pushipintfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_INTERCEPT_END_TIME, - (uint8_t *)&(ipint->common.toend_time), - sizeof(ipint->common.toend_time)) == -1) { - goto pushipintfail; - } - - if (push_tlv(nb, OPENLI_PROTO_FIELD_TOMEDIATE, - (uint8_t *)&(ipint->common.tomediate), - sizeof(ipint->common.tomediate)) == -1) { - goto pushipintfail; - } HASH_ITER(hh, ipint->statics, ipr, tmpr) { if (push_static_ipranges_onto_net_buffer(nb, ipint, ipr) < 0) { return -1; @@ -1689,6 +1507,8 @@ int decode_emailintercept_start(uint8_t *msgbody, uint16_t len, mailint->common.tostart_time = 0; mailint->common.toend_time = 0; mailint->common.tomediate = 0; + mailint->common.encrypt = 0; + mailint->common.encryptkey = NULL; while (msgbody < msgend) { openli_proto_fieldtype_t f; @@ -1718,6 +1538,10 @@ int decode_emailintercept_start(uint8_t *msgbody, uint16_t len, mailint->common.toend_time = *((uint64_t *)valptr); } else if (f == OPENLI_PROTO_FIELD_TOMEDIATE) { mailint->common.tomediate = *((intercept_outputs_t *)valptr); + } else if (f == OPENLI_PROTO_FIELD_PAYLOAD_ENCRYPTION) { + mailint->common.encrypt = *((payload_encryption_method_t *)valptr); + } else if (f == OPENLI_PROTO_FIELD_ENCRYPTION_KEY) { + DECODE_STRING_FIELD(mailint->common.encryptkey, valptr, vallen); } else { dump_buffer_contents(msgbody, len); logger(LOG_INFO, @@ -1766,6 +1590,8 @@ int decode_voipintercept_start(uint8_t *msgbody, uint16_t len, vint->common.tostart_time = 0; vint->common.toend_time = 0; vint->common.tomediate = 0; + vint->common.encrypt = 0; + vint->common.encryptkey = NULL; while (msgbody < msgend) { openli_proto_fieldtype_t f; @@ -1799,6 +1625,10 @@ int decode_voipintercept_start(uint8_t *msgbody, uint16_t len, vint->common.toend_time = *((uint64_t *)valptr); } else if (f == OPENLI_PROTO_FIELD_TOMEDIATE) { vint->common.tomediate = *((intercept_outputs_t *)valptr); + } else if (f == OPENLI_PROTO_FIELD_PAYLOAD_ENCRYPTION) { + vint->common.encrypt = *((payload_encryption_method_t *)valptr); + } else if (f == OPENLI_PROTO_FIELD_ENCRYPTION_KEY) { + DECODE_STRING_FIELD(vint->common.encryptkey, valptr, vallen); } else { dump_buffer_contents(msgbody, len); logger(LOG_INFO, @@ -1854,6 +1684,8 @@ int decode_ipintercept_start(uint8_t *msgbody, uint16_t len, ipint->common.tostart_time = 0; ipint->common.toend_time = 0; ipint->common.tomediate = 0; + ipint->common.encrypt = 0; + ipint->common.encryptkey = NULL; ipint->username_len = 0; while (msgbody < msgend) { @@ -1891,6 +1723,10 @@ int decode_ipintercept_start(uint8_t *msgbody, uint16_t len, ipint->common.toend_time = *((uint64_t *)valptr); } else if (f == OPENLI_PROTO_FIELD_TOMEDIATE) { ipint->common.tomediate = *((intercept_outputs_t *)valptr); + } else if (f == OPENLI_PROTO_FIELD_PAYLOAD_ENCRYPTION) { + ipint->common.encrypt = *((payload_encryption_method_t *)valptr); + } else if (f == OPENLI_PROTO_FIELD_ENCRYPTION_KEY) { + DECODE_STRING_FIELD(ipint->common.encryptkey, valptr, vallen); } else if (f == OPENLI_PROTO_FIELD_USERNAME) { DECODE_STRING_FIELD(ipint->username, valptr, vallen); if (vallen == 0) { diff --git a/src/netcomms.h b/src/netcomms.h index 87891c45..5e882902 100644 --- a/src/netcomms.h +++ b/src/netcomms.h @@ -161,6 +161,8 @@ typedef enum { OPENLI_PROTO_FIELD_INTERCEPT_END_TIME, OPENLI_PROTO_FIELD_EMAIL_TARGET, OPENLI_PROTO_FIELD_TOMEDIATE, + OPENLI_PROTO_FIELD_PAYLOAD_ENCRYPTION, + OPENLI_PROTO_FIELD_ENCRYPTION_KEY, } openli_proto_fieldtype_t; net_buffer_t *create_net_buffer(net_buffer_type_t buftype, int fd, SSL *ssl); diff --git a/src/provisioner/configwriter.c b/src/provisioner/configwriter.c index e8facd97..494798ed 100644 --- a/src/provisioner/configwriter.c +++ b/src/provisioner/configwriter.c @@ -430,11 +430,43 @@ static int emit_intercept_common(intercept_common_t *intcom, YAML_PLAIN_SCALAR_STYLE); if (!yaml_emitter_emit(emitter, &event)) return -1; + + yaml_scalar_event_initialize(&event, NULL, (yaml_char_t *)YAML_STR_TAG, + (yaml_char_t *)"payloadencryption", strlen("payloadencryption"), + 1, 0, YAML_PLAIN_SCALAR_STYLE); + if (!yaml_emitter_emit(emitter, &event)) return -1; + + if (intcom->encrypt == OPENLI_PAYLOAD_ENCRYPTION_NONE) { + yaml_scalar_event_initialize(&event, NULL, (yaml_char_t *)YAML_STR_TAG, + (yaml_char_t *)"none", strlen("none"), 1, 0, + YAML_PLAIN_SCALAR_STYLE); + } else if (intcom->encrypt == OPENLI_PAYLOAD_ENCRYPTION_AES_192_CBC) { + yaml_scalar_event_initialize(&event, NULL, (yaml_char_t *)YAML_STR_TAG, + (yaml_char_t *)"aes-192-cbc", strlen("aes-192-cbc"), 1, 0, + YAML_PLAIN_SCALAR_STYLE); + } else { + yaml_scalar_event_initialize(&event, NULL, (yaml_char_t *)YAML_STR_TAG, + (yaml_char_t *)"none", strlen("none"), 1, 0, + YAML_PLAIN_SCALAR_STYLE); + } + if (!yaml_emitter_emit(emitter, &event)) return -1; + + if (intcom->encryptkey) { + yaml_scalar_event_initialize(&event, NULL, (yaml_char_t *)YAML_STR_TAG, + (yaml_char_t *)"encryptionkey", strlen("encryptionkey"), 1, 0, + YAML_PLAIN_SCALAR_STYLE); + if (!yaml_emitter_emit(emitter, &event)) return -1; + + yaml_scalar_event_initialize(&event, NULL, (yaml_char_t *)YAML_STR_TAG, + (yaml_char_t *)intcom->encryptkey, + strlen(intcom->encryptkey), 1, 0, YAML_PLAIN_SCALAR_STYLE); + if (!yaml_emitter_emit(emitter, &event)) return -1; + } + yaml_scalar_event_initialize(&event, NULL, (yaml_char_t *)YAML_STR_TAG, (yaml_char_t *)"outputhandovers", strlen("outputhandovers"), 1, 0, YAML_PLAIN_SCALAR_STYLE); if (!yaml_emitter_emit(emitter, &event)) return -1; - if (intcom->tomediate == OPENLI_INTERCEPT_OUTPUTS_IRIONLY) { yaml_scalar_event_initialize(&event, NULL, (yaml_char_t *)YAML_STR_TAG, (yaml_char_t *)"irionly", strlen("irionly"), 1, 0, diff --git a/src/provisioner/hup_reload.c b/src/provisioner/hup_reload.c index 42f08b29..eb0bf1f5 100644 --- a/src/provisioner/hup_reload.c +++ b/src/provisioner/hup_reload.c @@ -59,40 +59,65 @@ static inline int reload_staticips(provision_state_t *currstate, return changed; } -static inline int ip_intercept_equal(ipintercept_t *a, ipintercept_t *b) { - if (strcmp(a->common.liid, b->common.liid) != 0) { +static inline int common_intercept_equal(intercept_common_t *a, + intercept_common_t *b) { + + if (strcmp(a->liid, b->liid) != 0) { return 0; } - if (a->common.tostart_time != b->common.tostart_time) { + if (a->tostart_time != b->tostart_time) { return 0; } - if (a->common.toend_time != b->common.toend_time) { + if (a->toend_time != b->toend_time) { return 0; } - if (strcmp(a->common.authcc, b->common.authcc) != 0) { + if (strcmp(a->authcc, b->authcc) != 0) { return 0; } - if (strcmp(a->common.delivcc, b->common.delivcc) != 0) { + if (strcmp(a->delivcc, b->delivcc) != 0) { return 0; } - if (a->username && b->username && strcmp(a->username, b->username) != 0) { + if (a->encrypt != b->encrypt) { return 0; } - if (a->vendmirrorid != b->vendmirrorid) { + if (a->tomediate != b->tomediate) { + return 0; + } + + if (strcmp(a->targetagency, b->targetagency) != 0) { + return 0; + } + + if (a->encryptkey == NULL) { + if (b->encryptkey != NULL) { + return 0; + } + } else if (b->encryptkey == NULL) { + return 0; + } else if (strcmp(a->encryptkey, b->encryptkey) != 0) { + return 0; + } + + return 1; +} + +static inline int ip_intercept_equal(ipintercept_t *a, ipintercept_t *b) { + + if (common_intercept_equal(&(a->common), &(b->common)) == 0) { return 0; } - if (a->common.tomediate != b->common.tomediate) { + if (a->username && b->username && strcmp(a->username, b->username) != 0) { return 0; } - if (strcmp(a->common.targetagency, b->common.targetagency) != 0) { + if (a->vendmirrorid != b->vendmirrorid) { return 0; } @@ -103,6 +128,21 @@ static inline int ip_intercept_equal(ipintercept_t *a, ipintercept_t *b) { return 1; } +static inline int voip_intercept_equal(voipintercept_t *a, voipintercept_t *b) { + if (common_intercept_equal(&(a->common), &(b->common)) == 0) { + return 0; + } + if (a->options != b->options) { + return 0; + } + return 1; +} + +static inline int email_intercept_equal(emailintercept_t *a, + emailintercept_t *b) { + + return common_intercept_equal(&(a->common), &(b->common)); +} static int reload_intercept_config_filename(provision_state_t *currstate, provision_state_t *newstate) { diff --git a/src/provisioner/updateserver_jsoncreation.c b/src/provisioner/updateserver_jsoncreation.c index 776f47a9..11802c91 100644 --- a/src/provisioner/updateserver_jsoncreation.c +++ b/src/provisioner/updateserver_jsoncreation.c @@ -66,25 +66,34 @@ static json_object *convert_lea_to_json(prov_agency_t *lea) { return jobj; } -static json_object *convert_ipintercept_to_json(ipintercept_t *ipint) { - json_object *jobj; +static void convert_commonintercept_to_json(json_object *jobj, + intercept_common_t *common) { + + const char *encrypt_str; json_object *liid, *authcc, *delivcc, *agencyid, *mediator; - json_object *vendmirrorid, *user, *accesstype, *radiusident; - json_object *staticips, *starttime, *endtime, *tomediate; + json_object *encryptkey; + json_object *starttime, *endtime, *tomediate, *encryption; - jobj = json_object_new_object(); + if (common->encrypt == OPENLI_PAYLOAD_ENCRYPTION_AES_192_CBC) { + encrypt_str = "aes-192-cbc"; + } else { + encrypt_str = "none"; + } - liid = json_object_new_string(ipint->common.liid); - authcc = json_object_new_string(ipint->common.authcc); - delivcc = json_object_new_string(ipint->common.delivcc); - agencyid = json_object_new_string(ipint->common.targetagency); - mediator = json_object_new_int(ipint->common.destid); - tomediate = json_object_new_int(ipint->common.tomediate); - user = json_object_new_string(ipint->username); - accesstype = json_object_new_string( - get_access_type_string(ipint->accesstype)); - radiusident = json_object_new_string( - get_radius_ident_string(ipint->options)); + + liid = json_object_new_string(common->liid); + authcc = json_object_new_string(common->authcc); + delivcc = json_object_new_string(common->delivcc); + agencyid = json_object_new_string(common->targetagency); + mediator = json_object_new_int(common->destid); + tomediate = json_object_new_int(common->tomediate); + encryption = json_object_new_string(encrypt_str); + + if (common->encryptkey) { + encryptkey = json_object_new_string(common->encryptkey); + } else { + encryptkey = NULL; + } json_object_object_add(jobj, "liid", liid); json_object_object_add(jobj, "authcc", authcc); @@ -92,20 +101,41 @@ static json_object *convert_ipintercept_to_json(ipintercept_t *ipint) { json_object_object_add(jobj, "agencyid", agencyid); json_object_object_add(jobj, "mediator", mediator); json_object_object_add(jobj, "outputhandovers", tomediate); - json_object_object_add(jobj, "user", user); - json_object_object_add(jobj, "accesstype", accesstype); - json_object_object_add(jobj, "radiusident", radiusident); + json_object_object_add(jobj, "payloadencryption", encryption); + if (encryptkey) { + json_object_object_add(jobj, "encryptionkey", encryptkey); + } - if (ipint->common.tostart_time != 0) { - starttime = json_object_new_int(ipint->common.tostart_time); + if (common->tostart_time != 0) { + starttime = json_object_new_int(common->tostart_time); json_object_object_add(jobj, "starttime", starttime); } - if (ipint->common.toend_time != 0) { - endtime = json_object_new_int(ipint->common.toend_time); + if (common->toend_time != 0) { + endtime = json_object_new_int(common->toend_time); json_object_object_add(jobj, "endtime", endtime); } +} + +static json_object *convert_ipintercept_to_json(ipintercept_t *ipint) { + json_object *jobj; + json_object *vendmirrorid, *user, *accesstype, *radiusident; + json_object *staticips; + + jobj = json_object_new_object(); + convert_commonintercept_to_json(jobj, &(ipint->common)); + + user = json_object_new_string(ipint->username); + accesstype = json_object_new_string( + get_access_type_string(ipint->accesstype)); + radiusident = json_object_new_string( + get_radius_ident_string(ipint->options)); + + json_object_object_add(jobj, "user", user); + json_object_object_add(jobj, "accesstype", accesstype); + json_object_object_add(jobj, "radiusident", radiusident); + if (ipint->vendmirrorid != 0xFFFFFFFF) { vendmirrorid = json_object_new_int(ipint->vendmirrorid); json_object_object_add(jobj, "vendmirrorid", vendmirrorid); @@ -137,37 +167,14 @@ static json_object *convert_ipintercept_to_json(ipintercept_t *ipint) { static json_object *convert_emailintercept_to_json(emailintercept_t *mailint) { json_object *jobj; - json_object *liid, *authcc, *delivcc, *agencyid, *mediator; - json_object *targets, *starttime, *endtime, *tomediate; + json_object *targets; email_target_t *tgt, *tmp; jobj = json_object_new_object(); + convert_commonintercept_to_json(jobj, &(mailint->common)); - liid = json_object_new_string(mailint->common.liid); - authcc = json_object_new_string(mailint->common.authcc); - delivcc = json_object_new_string(mailint->common.delivcc); - agencyid = json_object_new_string(mailint->common.targetagency); - mediator = json_object_new_int(mailint->common.destid); - tomediate = json_object_new_int(mailint->common.tomediate); targets = json_object_new_array(); - json_object_object_add(jobj, "liid", liid); - json_object_object_add(jobj, "authcc", authcc); - json_object_object_add(jobj, "delivcc", delivcc); - json_object_object_add(jobj, "agencyid", agencyid); - json_object_object_add(jobj, "mediator", mediator); - json_object_object_add(jobj, "outputhandovers", tomediate); - - if (mailint->common.tostart_time != 0) { - starttime = json_object_new_int(mailint->common.tostart_time); - json_object_object_add(jobj, "starttime", starttime); - } - - if (mailint->common.toend_time != 0) { - endtime = json_object_new_int(mailint->common.toend_time); - json_object_object_add(jobj, "endtime", endtime); - } - HASH_ITER(hh, mailint->targets, tgt, tmp) { json_object *jsontgt, *address; @@ -184,36 +191,14 @@ static json_object *convert_emailintercept_to_json(emailintercept_t *mailint) { static json_object *convert_voipintercept_to_json(voipintercept_t *vint) { json_object *jobj; - json_object *liid, *authcc, *delivcc, *agencyid, *mediator; - json_object *siptargets, *starttime, *endtime, *tomediate; - libtrace_list_node_t *n; + json_object *siptargets; - jobj = json_object_new_object(); + libtrace_list_node_t *n; - liid = json_object_new_string(vint->common.liid); - authcc = json_object_new_string(vint->common.authcc); - delivcc = json_object_new_string(vint->common.delivcc); - agencyid = json_object_new_string(vint->common.targetagency); - mediator = json_object_new_int(vint->common.destid); - tomediate = json_object_new_int(vint->common.tomediate); siptargets = json_object_new_array(); + jobj = json_object_new_object(); - json_object_object_add(jobj, "liid", liid); - json_object_object_add(jobj, "authcc", authcc); - json_object_object_add(jobj, "delivcc", delivcc); - json_object_object_add(jobj, "agencyid", agencyid); - json_object_object_add(jobj, "mediator", mediator); - json_object_object_add(jobj, "outputhandovers", tomediate); - - if (vint->common.tostart_time != 0) { - starttime = json_object_new_int(vint->common.tostart_time); - json_object_object_add(jobj, "starttime", starttime); - } - - if (vint->common.toend_time != 0) { - endtime = json_object_new_int(vint->common.toend_time); - json_object_object_add(jobj, "endtime", endtime); - } + convert_commonintercept_to_json(jobj, &(vint->common)); n = vint->targets->head; while (n) { diff --git a/src/provisioner/updateserver_jsonparsing.c b/src/provisioner/updateserver_jsonparsing.c index 8e9eebf8..31a97018 100644 --- a/src/provisioner/updateserver_jsonparsing.c +++ b/src/provisioner/updateserver_jsonparsing.c @@ -59,6 +59,8 @@ struct json_intercept { struct json_object *siptargets; struct json_object *emailtargets; struct json_object *tomediate; + struct json_object *encryption; + struct json_object *encryptkey; }; #define EXTRACT_JSON_INT_PARAM(name, uptype, jsonobj, dest, errflag, force) \ @@ -93,16 +95,26 @@ struct json_intercept { *errflag = 1; \ } \ } else { \ - dest = strdup(objstr); \ + if (strlen(objstr) == 0) { \ + dest = NULL; \ + } else { \ + dest = strdup(objstr); \ + } \ } \ } #define MODIFY_STRING_MEMBER(newmem, oldmem, changeflag) \ - if (newmem != NULL && strcmp(newmem, oldmem) != 0) { \ + if (newmem != NULL && oldmem != NULL && strcmp(newmem, oldmem) != 0) { \ free(oldmem); oldmem = newmem; *changeflag = 1; \ newmem = NULL; \ } else if (newmem) { \ - free(newmem); newmem = NULL; \ + if (oldmem == NULL) { \ + oldmem = newmem; newmem = NULL; *changeflag = 1; \ + } else { \ + free(newmem); newmem = NULL; \ + } \ + } else if (oldmem && newmem == NULL) { \ + free(oldmem); oldmem = NULL; *changeflag = 1; \ } #define INIT_JSON_INTERCEPT_PARSING \ @@ -184,6 +196,8 @@ static inline void extract_intercept_json_objects( json_object_object_get_ex(parsed, "starttime", &(ipjson->starttime)); json_object_object_get_ex(parsed, "endtime", &(ipjson->endtime)); json_object_object_get_ex(parsed, "outputhandovers", &(ipjson->tomediate)); + json_object_object_get_ex(parsed, "payloadencryption", &(ipjson->encryption)); + json_object_object_get_ex(parsed, "encryptionkey", &(ipjson->encryptkey)); json_object_object_get_ex(parsed, "vendmirrorid", &(ipjson->vendmirrorid)); json_object_object_get_ex(parsed, "staticips", &(ipjson->staticips)); json_object_object_get_ex(parsed, "siptargets", &(ipjson->siptargets)); @@ -219,6 +233,135 @@ static inline int compare_intercept_times(intercept_common_t *latest, return changed; } +static inline void new_intercept_liidmapping(provision_state_t *state, + char *targetagency, char *liid) { + + int liidmapped = 0; + prov_agency_t *lea = NULL; + + if (targetagency == NULL) { + return; + } + + if (strcmp(targetagency, "pcapdisk") != 0) { + HASH_FIND_STR(state->interceptconf.leas, targetagency, lea); + if (lea) { + liidmapped = 1; + } + } else { + liidmapped = 1; + } + + if (liidmapped) { + liid_hash_t *h = add_liid_mapping(&(state->interceptconf), + liid, targetagency); + if (announce_liidmapping_to_mediators(state, h) < 0) { + logger(LOG_INFO, + "OpenLI provisioner: unable to announce new IP intercept %s to mediators.", + liid); + } + } +} + +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) { + + int parseerr = 0; + char *encryptmethodstring = NULL; + + if (is_new) { + common->tostart_time = 0; + common->toend_time = 0; + common->encrypt = OPENLI_PAYLOAD_ENCRYPTION_NONE; + } else { + common->tostart_time = (uint64_t)-1; + common->toend_time = (uint64_t)-1; + common->encrypt = OPENLI_PAYLOAD_ENCRYPTION_NOT_SPECIFIED; + } + + if (common->liid == NULL) { + EXTRACT_JSON_STRING_PARAM("liid", cepttype, jsonp->liid, + common->liid, &parseerr, true); + } + + EXTRACT_JSON_STRING_PARAM("authcc", cepttype, jsonp->authcc, + common->authcc, &parseerr, is_new); + EXTRACT_JSON_STRING_PARAM("delivcc", cepttype, jsonp->delivcc, + common->delivcc, &parseerr, is_new); + EXTRACT_JSON_STRING_PARAM("agencyid", cepttype, jsonp->agencyid, + common->targetagency, &parseerr, is_new); + EXTRACT_JSON_INT_PARAM("outputhandovers", cepttype, + jsonp->tomediate, common->tomediate, &parseerr, false); + EXTRACT_JSON_INT_PARAM("mediator", cepttype, jsonp->mediator, + common->destid, &parseerr, is_new); + EXTRACT_JSON_INT_PARAM("starttime", cepttype, jsonp->starttime, + common->tostart_time, &parseerr, false); + EXTRACT_JSON_INT_PARAM("endtime", cepttype, jsonp->endtime, + common->toend_time, &parseerr, false); + EXTRACT_JSON_STRING_PARAM("payloadencryption", cepttype, + jsonp->encryption, encryptmethodstring, &parseerr, false); + EXTRACT_JSON_STRING_PARAM("encryptionkey", cepttype, + jsonp->encryptkey, common->encryptkey, &parseerr, false); + + if (encryptmethodstring) { + common->encrypt = map_encrypt_method_string(encryptmethodstring); + free(encryptmethodstring); + } + + if (common->authcc) { + common->authcc_len = strlen(common->authcc); + } + if (common->delivcc) { + common->delivcc_len = strlen(common->delivcc); + } + if (common->liid) { + common->liid_len = strlen(common->liid); + } + + if (parseerr) { + return -1; + } + return 0; +} + +static int update_intercept_common(intercept_common_t *parsed, + intercept_common_t *existing, int *changed, int *agencychanged, + provision_state_t *state) { + + MODIFY_STRING_MEMBER(parsed->authcc, existing->authcc, changed); + existing->authcc_len = strlen(existing->authcc); + MODIFY_STRING_MEMBER(parsed->delivcc, existing->delivcc, changed); + existing->delivcc_len = strlen(existing->delivcc); + + if (parsed->tomediate != existing->tomediate) { + existing->tomediate = parsed->tomediate; + *changed = 1; + } + + MODIFY_STRING_MEMBER(parsed->targetagency, existing->targetagency, + agencychanged); + + if (*agencychanged) { + new_intercept_liidmapping(state, existing->targetagency, + existing->liid); + } + + MODIFY_STRING_MEMBER(parsed->encryptkey, existing->encryptkey, changed); + + if (parsed->encrypt != existing->encrypt && + parsed->encrypt != OPENLI_PAYLOAD_ENCRYPTION_NOT_SPECIFIED) { + *changed = 1; + existing->encrypt = parsed->encrypt; + } + + if (compare_intercept_times(parsed, existing) == 1) { + *changed = 1; + } + + return 0; +} + int remove_voip_intercept(update_con_info_t *cinfo, provision_state_t *state, const char *idstr) { @@ -805,43 +948,13 @@ int parse_ipintercept_staticips(provision_state_t *state, } -static inline void new_intercept_liidmapping(provision_state_t *state, - char *targetagency, char *liid) { - - int liidmapped = 0; - prov_agency_t *lea = NULL; - - if (targetagency == NULL) { - return; - } - - if (strcmp(targetagency, "pcapdisk") != 0) { - HASH_FIND_STR(state->interceptconf.leas, targetagency, lea); - if (lea) { - liidmapped = 1; - } - } else { - liidmapped = 1; - } - - if (liidmapped) { - liid_hash_t *h = add_liid_mapping(&(state->interceptconf), - liid, targetagency); - if (announce_liidmapping_to_mediators(state, h) < 0) { - logger(LOG_INFO, - "OpenLI provisioner: unable to announce new IP intercept %s to mediators.", - liid); - } - } -} - int add_new_emailintercept(update_con_info_t *cinfo, provision_state_t *state) { struct json_intercept emailjson; struct json_tokener *tknr; struct json_object *parsed = NULL; emailintercept_t *found = NULL; emailintercept_t *mailint = NULL; - int parseerr = 0, r; + int r; char *target_info; INIT_JSON_INTERCEPT_PARSING @@ -851,28 +964,9 @@ int add_new_emailintercept(update_con_info_t *cinfo, provision_state_t *state) { /* XXX does internalid still matter? if not, let's remove it */ mailint->awaitingconfirm = 1; mailint->targets = NULL; - mailint->common.tostart_time = 0; - mailint->common.toend_time = 0; - EXTRACT_JSON_STRING_PARAM("liid", "Email intercept", emailjson.liid, - mailint->common.liid, &parseerr, true); - EXTRACT_JSON_STRING_PARAM("authcc", "Email intercept", emailjson.authcc, - mailint->common.authcc, &parseerr, true); - EXTRACT_JSON_STRING_PARAM("delivcc", "Email intercept", emailjson.delivcc, - mailint->common.delivcc, &parseerr, true); - EXTRACT_JSON_STRING_PARAM("agencyid", "Email intercept", emailjson.agencyid, - mailint->common.targetagency, &parseerr, true); - EXTRACT_JSON_INT_PARAM("outputhandovers", "Email intercept", - emailjson.tomediate, - mailint->common.tomediate, &parseerr, false); - EXTRACT_JSON_INT_PARAM("mediator", "Email intercept", emailjson.mediator, - mailint->common.destid, &parseerr, true); - EXTRACT_JSON_INT_PARAM("starttime", "Email intercept", emailjson.starttime, - mailint->common.tostart_time, &parseerr, false); - EXTRACT_JSON_INT_PARAM("endtime", "Email intercept", emailjson.endtime, - mailint->common.toend_time, &parseerr, false); - - if (parseerr) { + if (parse_intercept_common_json(&emailjson, &(mailint->common), + "Email intercept", cinfo, true) < 0) { goto cepterr; } @@ -892,10 +986,6 @@ int add_new_emailintercept(update_con_info_t *cinfo, provision_state_t *state) { goto cepterr; } - mailint->common.liid_len = strlen(mailint->common.liid); - mailint->common.authcc_len = strlen(mailint->common.authcc); - mailint->common.delivcc_len = strlen(mailint->common.delivcc); - HASH_FIND(hh_liid, state->interceptconf.emailintercepts, mailint->common.liid, mailint->common.liid_len, found); @@ -966,7 +1056,7 @@ int add_new_voipintercept(update_con_info_t *cinfo, provision_state_t *state) { struct json_object *parsed = NULL; voipintercept_t *found = NULL; voipintercept_t *vint = NULL; - int parseerr = 0, r; + int r; char *target_info; INIT_JSON_INTERCEPT_PARSING @@ -977,8 +1067,6 @@ int add_new_voipintercept(update_con_info_t *cinfo, provision_state_t *state) { vint->awaitingconfirm = 1; vint->active = 1; vint->targets = libtrace_list_init(sizeof(openli_sip_identity_t *)); - vint->common.tostart_time = 0; - vint->common.toend_time = 0; /* XXX potential data race here if we're reloading core provisioner * config at the same time, consider adding a mutex */ @@ -986,25 +1074,8 @@ int add_new_voipintercept(update_con_info_t *cinfo, provision_state_t *state) { vint->options |= (1UL << OPENLI_VOIPINT_OPTION_IGNORE_COMFORT); } - EXTRACT_JSON_STRING_PARAM("liid", "VOIP intercept", voipjson.liid, - vint->common.liid, &parseerr, true); - EXTRACT_JSON_STRING_PARAM("authcc", "VOIP intercept", voipjson.authcc, - vint->common.authcc, &parseerr, true); - EXTRACT_JSON_STRING_PARAM("delivcc", "VOIP intercept", voipjson.delivcc, - vint->common.delivcc, &parseerr, true); - EXTRACT_JSON_STRING_PARAM("agencyid", "VOIP intercept", voipjson.agencyid, - vint->common.targetagency, &parseerr, true); - EXTRACT_JSON_INT_PARAM("outputhandovers", "VOIP intercept", - voipjson.tomediate, - vint->common.tomediate, &parseerr, false); - EXTRACT_JSON_INT_PARAM("mediator", "VOIP intercept", voipjson.mediator, - vint->common.destid, &parseerr, true); - EXTRACT_JSON_INT_PARAM("starttime", "VOIP intercept", voipjson.starttime, - vint->common.tostart_time, &parseerr, false); - EXTRACT_JSON_INT_PARAM("endtime", "VOIP intercept", voipjson.endtime, - vint->common.toend_time, &parseerr, false); - - if (parseerr) { + if (parse_intercept_common_json(&voipjson, &(vint->common), + "VOIP intercept", cinfo, true) < 0) { goto cepterr; } @@ -1024,10 +1095,6 @@ int add_new_voipintercept(update_con_info_t *cinfo, provision_state_t *state) { goto cepterr; } - vint->common.liid_len = strlen(vint->common.liid); - vint->common.authcc_len = strlen(vint->common.authcc); - vint->common.delivcc_len = strlen(vint->common.delivcc); - HASH_FIND(hh_liid, state->interceptconf.voipintercepts, vint->common.liid, vint->common.liid_len, found); @@ -1097,11 +1164,10 @@ int add_new_ipintercept(update_con_info_t *cinfo, provision_state_t *state) { struct json_tokener *tknr; struct json_object *parsed = NULL; ipintercept_t *found = NULL; - + int parseerr = 0; char *accessstring = NULL; char *radiusidentstring = NULL; ipintercept_t *ipint = NULL; - int parseerr = 0; INIT_JSON_INTERCEPT_PARSING extract_intercept_json_objects(&ipjson, parsed); @@ -1110,23 +1176,12 @@ int add_new_ipintercept(update_con_info_t *cinfo, provision_state_t *state) { ipint->awaitingconfirm = 1; ipint->vendmirrorid = OPENLI_VENDOR_MIRROR_NONE; ipint->accesstype = INTERNET_ACCESS_TYPE_UNDEFINED; - ipint->common.tostart_time = 0; - ipint->common.toend_time = 0; ipint->options = 0; - EXTRACT_JSON_STRING_PARAM("liid", "IP intercept", ipjson.liid, - ipint->common.liid, &parseerr, true); - EXTRACT_JSON_STRING_PARAM("authcc", "IP intercept", ipjson.authcc, - ipint->common.authcc, &parseerr, true); - EXTRACT_JSON_STRING_PARAM("delivcc", "IP intercept", ipjson.delivcc, - ipint->common.delivcc, &parseerr, true); - EXTRACT_JSON_STRING_PARAM("agencyid", "IP intercept", ipjson.agencyid, - ipint->common.targetagency, &parseerr, true); - EXTRACT_JSON_INT_PARAM("outputhandovers", "IP intercept", - ipjson.tomediate, - ipint->common.tomediate, &parseerr, false); - EXTRACT_JSON_INT_PARAM("mediator", "IP intercept", ipjson.mediator, - ipint->common.destid, &parseerr, true); + if (parse_intercept_common_json(&ipjson, &(ipint->common), + "IP intercept", cinfo, true) < 0) { + goto cepterr; + } EXTRACT_JSON_INT_PARAM("vendmirrorid", "IP intercept", ipjson.vendmirrorid, ipint->vendmirrorid, &parseerr, false); EXTRACT_JSON_STRING_PARAM("user", "IP intercept", ipjson.user, @@ -1135,10 +1190,6 @@ int add_new_ipintercept(update_con_info_t *cinfo, provision_state_t *state) { accessstring, &parseerr, false); EXTRACT_JSON_STRING_PARAM("radiusident", "IP intercept", ipjson.radiusident, radiusidentstring, &parseerr, false); - EXTRACT_JSON_INT_PARAM("starttime", "IP intercept", ipjson.starttime, - ipint->common.tostart_time, &parseerr, false); - EXTRACT_JSON_INT_PARAM("endtime", "IP intercept", ipjson.endtime, - ipint->common.toend_time, &parseerr, false); if (parseerr) { goto cepterr; @@ -1243,7 +1294,7 @@ int modify_emailintercept(update_con_info_t *cinfo, provision_state_t *state) { char *target_info; char *liidstr = NULL; - int parseerr = 0, changed = 0, agencychanged = 0, timechanged = 0; + int parseerr = 0, changed = 0, agencychanged = 0; INIT_JSON_INTERCEPT_PARSING extract_intercept_json_objects(&emailjson, parsed); @@ -1271,26 +1322,9 @@ int modify_emailintercept(update_con_info_t *cinfo, provision_state_t *state) { mailint->awaitingconfirm = 1; mailint->common.liid = liidstr; mailint->targets = NULL; - mailint->common.tostart_time = (uint64_t)-1; - mailint->common.toend_time = (uint64_t)-1; - - EXTRACT_JSON_STRING_PARAM("authcc", "Email intercept", emailjson.authcc, - mailint->common.authcc, &parseerr, false); - EXTRACT_JSON_STRING_PARAM("delivcc", "Email intercept", emailjson.delivcc, - mailint->common.delivcc, &parseerr, false); - EXTRACT_JSON_STRING_PARAM("agencyid", "Email intercept", emailjson.agencyid, - mailint->common.targetagency, &parseerr, false); - EXTRACT_JSON_INT_PARAM("outputhandovers", "Email intercept", - emailjson.tomediate, - mailint->common.tomediate, &parseerr, false); - EXTRACT_JSON_INT_PARAM("mediator", "Email intercept", emailjson.mediator, - mailint->common.destid, &parseerr, false); - EXTRACT_JSON_INT_PARAM("starttime", "Email intercept", emailjson.starttime, - mailint->common.tostart_time, &parseerr, false); - EXTRACT_JSON_INT_PARAM("endtime", "Email intercept", emailjson.endtime, - mailint->common.toend_time, &parseerr, false); - if (parseerr) { + if (parse_intercept_common_json(&emailjson, &(mailint->common), + "Email intercept", cinfo, false) < 0) { goto cepterr; } @@ -1318,28 +1352,12 @@ int modify_emailintercept(update_con_info_t *cinfo, provision_state_t *state) { * */ - MODIFY_STRING_MEMBER(mailint->common.authcc, found->common.authcc, &changed); - found->common.authcc_len = strlen(found->common.authcc); - - MODIFY_STRING_MEMBER(mailint->common.delivcc, found->common.delivcc, &changed); - found->common.delivcc_len = strlen(found->common.delivcc); - - MODIFY_STRING_MEMBER(mailint->common.targetagency, found->common.targetagency, - &agencychanged); - - timechanged = compare_intercept_times(&(mailint->common), &(found->common)); - - if (mailint->common.tomediate != found->common.tomediate) { - changed = 1; - found->common.tomediate = mailint->common.tomediate; - } - - if (agencychanged) { - new_intercept_liidmapping(state, found->common.targetagency, - found->common.liid); + if (update_intercept_common(&(mailint->common), &(found->common), + &changed, &agencychanged, state) < 0) { + goto cepterr; } - if (changed || timechanged) { + if (changed) { modify_existing_intercept_options(state, (void *)found, OPENLI_PROTO_MODIFY_EMAILINTERCEPT); } @@ -1353,7 +1371,6 @@ int modify_emailintercept(update_con_info_t *cinfo, provision_state_t *state) { } } - mailint->common.hi1_seqno = found->common.hi1_seqno; logger(LOG_INFO, "OpenLI provisioner: updated Email intercept %s via update socket.", found->common.liid); @@ -1389,7 +1406,7 @@ int modify_voipintercept(update_con_info_t *cinfo, provision_state_t *state) { libtrace_list_t *tmp; char *liidstr = NULL, *target_info; - int parseerr = 0, changed = 0, agencychanged = 0, timechanged = 0; + int changed = 0, agencychanged = 0, parseerr = 0; INIT_JSON_INTERCEPT_PARSING extract_intercept_json_objects(&voipjson, parsed); @@ -1417,26 +1434,9 @@ int modify_voipintercept(update_con_info_t *cinfo, provision_state_t *state) { vint->awaitingconfirm = 1; vint->common.liid = liidstr; vint->targets = libtrace_list_init(sizeof(openli_sip_identity_t *)); - vint->common.tostart_time = (uint64_t)-1; - vint->common.toend_time = (uint64_t)-1; - - EXTRACT_JSON_STRING_PARAM("authcc", "VOIP intercept", voipjson.authcc, - vint->common.authcc, &parseerr, false); - EXTRACT_JSON_STRING_PARAM("delivcc", "VOIP intercept", voipjson.delivcc, - vint->common.delivcc, &parseerr, false); - EXTRACT_JSON_STRING_PARAM("agencyid", "VOIP intercept", voipjson.agencyid, - vint->common.targetagency, &parseerr, false); - EXTRACT_JSON_INT_PARAM("outputhandovers", "VOIP intercept", - voipjson.tomediate, - vint->common.tomediate, &parseerr, false); - EXTRACT_JSON_INT_PARAM("mediator", "VOIP intercept", voipjson.mediator, - vint->common.destid, &parseerr, false); - EXTRACT_JSON_INT_PARAM("starttime", "VOIP intercept", voipjson.starttime, - vint->common.tostart_time, &parseerr, false); - EXTRACT_JSON_INT_PARAM("endtime", "VOIP intercept", voipjson.endtime, - vint->common.toend_time, &parseerr, false); - if (parseerr) { + if (parse_intercept_common_json(&voipjson, &(vint->common), + "VOIP intercept", cinfo, false) < 0) { goto cepterr; } @@ -1463,28 +1463,12 @@ int modify_voipintercept(update_con_info_t *cinfo, provision_state_t *state) { * */ - MODIFY_STRING_MEMBER(vint->common.authcc, found->common.authcc, &changed); - found->common.authcc_len = strlen(found->common.authcc); - - MODIFY_STRING_MEMBER(vint->common.delivcc, found->common.delivcc, &changed); - found->common.delivcc_len = strlen(found->common.delivcc); - - MODIFY_STRING_MEMBER(vint->common.targetagency, found->common.targetagency, - &agencychanged); - - if (vint->common.tomediate != found->common.tomediate) { - changed = 1; - found->common.tomediate = vint->common.tomediate; - } - - timechanged = compare_intercept_times(&(vint->common), &(found->common)); - - if (agencychanged) { - new_intercept_liidmapping(state, found->common.targetagency, - found->common.liid); + if (update_intercept_common(&(vint->common), &(found->common), + &changed, &agencychanged, state) < 0) { + goto cepterr; } - if (changed || timechanged) { + if (changed) { modify_existing_intercept_options(state, (void *)found, OPENLI_PROTO_MODIFY_VOIPINTERCEPT); } @@ -1498,7 +1482,6 @@ int modify_voipintercept(update_con_info_t *cinfo, provision_state_t *state) { } } - vint->common.hi1_seqno = found->common.hi1_seqno; logger(LOG_INFO, "OpenLI provisioner: updated VOIP intercept %s via update socket.", found->common.liid); @@ -1563,32 +1546,20 @@ int modify_ipintercept(update_con_info_t *cinfo, provision_state_t *state) { ipint->vendmirrorid = OPENLI_VENDOR_MIRROR_NONE; ipint->accesstype = INTERNET_ACCESS_TYPE_UNDEFINED; ipint->common.liid = liidstr; - ipint->common.tostart_time = (uint64_t)-1; - ipint->common.toend_time = (uint64_t)-1; - - EXTRACT_JSON_STRING_PARAM("authcc", "IP intercept", ipjson.authcc, - ipint->common.authcc, &parseerr, false); - EXTRACT_JSON_STRING_PARAM("delivcc", "IP intercept", ipjson.delivcc, - ipint->common.delivcc, &parseerr, false); - EXTRACT_JSON_STRING_PARAM("agencyid", "IP intercept", ipjson.agencyid, - ipint->common.targetagency, &parseerr, false); - EXTRACT_JSON_INT_PARAM("outputhandovers", "IP intercept", - ipjson.tomediate, - ipint->common.tomediate, &parseerr, false); - EXTRACT_JSON_INT_PARAM("mediator", "IP intercept", ipjson.mediator, - ipint->common.destid, &parseerr, false); - EXTRACT_JSON_INT_PARAM("vendmirrorid", "IP intercept", ipjson.vendmirrorid, - ipint->vendmirrorid, &parseerr, false); - EXTRACT_JSON_INT_PARAM("starttime", "IP intercept", ipjson.starttime, - ipint->common.tostart_time, &parseerr, false); - EXTRACT_JSON_INT_PARAM("endtime", "IP intercept", ipjson.endtime, - ipint->common.toend_time, &parseerr, false); + + if (parse_intercept_common_json(&ipjson, &(ipint->common), + "IP intercept", cinfo, false) < 0) { + goto cepterr; + } + EXTRACT_JSON_STRING_PARAM("user", "IP intercept", ipjson.user, ipint->username, &parseerr, false); EXTRACT_JSON_STRING_PARAM("accesstype", "IP intercept", ipjson.accesstype, accessstring, &parseerr, false); EXTRACT_JSON_STRING_PARAM("radiusident", "IP intercept", ipjson.radiusident, radiusidentstring, &parseerr, false); + EXTRACT_JSON_INT_PARAM("vendmirrorid", "IP intercept", ipjson.vendmirrorid, + ipint->vendmirrorid, &parseerr, false); if (parseerr) { goto cepterr; @@ -1652,29 +1623,14 @@ int modify_ipintercept(update_con_info_t *cinfo, provision_state_t *state) { * changing (e.g. mediator) ? * */ - - MODIFY_STRING_MEMBER(ipint->common.authcc, found->common.authcc, &changed); - found->common.authcc_len = strlen(found->common.authcc); - MODIFY_STRING_MEMBER(ipint->common.delivcc, found->common.delivcc, - &changed); - found->common.delivcc_len = strlen(found->common.delivcc); - - if (ipint->common.tomediate != found->common.tomediate) { - found->common.tomediate = ipint->common.tomediate; - changed = 1; + if (update_intercept_common(&(ipint->common), &(found->common), + &changed, &agencychanged, state) < 0) { + goto cepterr; } MODIFY_STRING_MEMBER(ipint->username, found->username, &changed); found->username_len = strlen(found->username); - MODIFY_STRING_MEMBER(ipint->common.targetagency, found->common.targetagency, - &agencychanged); - - if (agencychanged) { - new_intercept_liidmapping(state, found->common.targetagency, - found->common.liid); - } - if (accessstring && ipint->accesstype != found->accesstype) { changed = 1; found->accesstype = ipint->accesstype; @@ -1685,15 +1641,6 @@ int modify_ipintercept(update_con_info_t *cinfo, provision_state_t *state) { found->options = ipint->options; } - if (accessstring) { - free(accessstring); - } - if (radiusidentstring) { - free(radiusidentstring); - } - radiusidentstring = NULL; - accessstring = NULL; - if (ipint->vendmirrorid != found->vendmirrorid) { changed = 1; found->vendmirrorid = ipint->vendmirrorid; @@ -1704,10 +1651,6 @@ int modify_ipintercept(update_con_info_t *cinfo, provision_state_t *state) { found->username, HI1_LI_ACTIVATED); } - if (compare_intercept_times(&(ipint->common), &(found->common)) == 1) { - changed = 1; - } - if (changed) { modify_existing_intercept_options(state, (void *)found, OPENLI_PROTO_MODIFY_IPINTERCEPT); @@ -1717,11 +1660,17 @@ int modify_ipintercept(update_con_info_t *cinfo, provision_state_t *state) { } } - ipint->common.hi1_seqno = found->common.hi1_seqno; logger(LOG_INFO, "OpenLI provisioner: updated IP intercept %s via update socket.", found->common.liid); + if (accessstring) { + free(accessstring); + } + if (radiusidentstring) { + free(radiusidentstring); + } + if (ipint) { free_single_ipintercept(ipint); }