int output_log_txt_init(struct output *o) { struct output_log_txt_priv *priv = malloc(sizeof(struct output_log_txt_priv)); if (!priv) { pom_oom(sizeof(struct output_log_txt_priv)); return POM_ERR; } memset(priv, 0, sizeof(struct output_log_txt_priv)); output_set_priv(o, priv); priv->p_prefix = ptype_alloc("string"); priv->p_template = ptype_alloc("string"); if (!priv->p_prefix || !priv->p_template) goto err; struct registry_param *p = registry_new_param("prefix", "/tmp/", priv->p_prefix, "Log files prefix", 0); if (output_instance_add_param(o, p) != POM_OK) goto err; p = registry_new_param("template", "", priv->p_template, "Log template to use", 0); if (output_instance_add_param(o, p) != POM_OK) goto err; return POM_OK; err: output_log_txt_cleanup(priv); return POM_ERR; }
int output_file_init(struct output *o) { struct output_file_priv *priv = malloc(sizeof(struct output_file_priv)); if (!priv) { pom_oom(sizeof(struct output_file_priv)); return POM_ERR; } memset(priv, 0, sizeof(struct output_file_priv)); output_set_priv(o, priv); priv->p_listen_pload_evt = ptype_alloc("bool"); priv->p_path = ptype_alloc("string"); if (!priv->p_path || !priv->p_listen_pload_evt) goto err; struct registry_param *p = registry_new_param("listen_pload_events", "no", priv->p_listen_pload_evt, "Listen to all events that generate payloads", 0); if (output_instance_add_param(o, p) != POM_OK) goto err; p = registry_new_param("path", "/tmp/", priv->p_path, "Path where to store the files", 0); if (output_instance_add_param(o, p) != POM_OK) goto err; priv->output_reg.open = output_file_pload_open; priv->output_reg.write = output_file_pload_write; priv->output_reg.close = output_file_pload_close; return POM_OK; err: output_file_cleanup(priv); return POM_ERR; }
static int input_kismet_drone_init(struct input *i) { struct input_kismet_drone_priv *priv; priv = malloc(sizeof(struct input_kismet_drone_priv)); if (!priv) { pom_oom(sizeof(struct input_kismet_drone_priv)); return POM_ERR; } memset(priv, 0, sizeof(struct input_kismet_drone_priv)); priv->fd = -1; struct registry_param *p = NULL; priv->datalink_80211 = proto_get("80211"); priv->datalink_radiotap = proto_get("radiotap"); if (!priv->datalink_80211 || !priv->datalink_radiotap) { pomlog(POMLOG_ERR "Could not find datalink 80211 or radiotap"); goto err; } priv->p_host = ptype_alloc("string"); priv->p_port = ptype_alloc("uint16"); if (!priv->p_host || !priv->p_port) goto err; p = registry_new_param("host", "localhost", priv->p_host, "Kismet drone host", 0); if (input_add_param(i, p) != POM_OK) goto err; p = registry_new_param("port", "2502", priv->p_port, "Kismet drone port", 0); if (input_add_param(i, p) != POM_OK) goto err; i->priv = priv; return POM_OK; err: if (p) registry_cleanup_param(p); if (priv->p_host) ptype_cleanup(priv->p_host); if (priv->p_port) ptype_cleanup(priv->p_port); free(priv); return POM_ERR; }
int output_file_init(struct output *o) { struct output_file_priv *priv = malloc(sizeof(struct output_file_priv)); if (!priv) { pom_oom(sizeof(struct output_file_priv)); return POM_ERR; } memset(priv, 0, sizeof(struct output_file_priv)); output_set_priv(o, priv); priv->p_listen_pload_evt = ptype_alloc("bool"); priv->p_path = ptype_alloc("string"); priv->p_filter = ptype_alloc("string"); if (!priv->p_path || !priv->p_listen_pload_evt || !priv->p_filter) goto err; struct registry_instance *inst = output_get_reg_instance(o); priv->perf_files_closed = registry_instance_add_perf(inst, "files_closed", registry_perf_type_counter, "Number of files fully written and closed", "files"); priv->perf_files_open = registry_instance_add_perf(inst, "files_open", registry_perf_type_gauge, "Number of files currently open", "files"); priv->perf_bytes_written = registry_instance_add_perf(inst, "bytes_written", registry_perf_type_counter, "Number of bytes written", "bytes"); if (!priv->perf_files_closed || !priv->perf_files_open || !priv->perf_bytes_written) goto err; struct registry_param *p = registry_new_param("listen_pload_events", "no", priv->p_listen_pload_evt, "Listen to all events that generate payloads", 0); if (output_add_param(o, p) != POM_OK) goto err; p = registry_new_param("path", "/tmp/", priv->p_path, "Path where to store the files", 0); if (output_add_param(o, p) != POM_OK) goto err; p = registry_new_param("filter", "", priv->p_filter, "Payload filter", 0); if (output_add_param(o, p) != POM_OK) goto err; return POM_OK; err: if (p) registry_cleanup_param(p); output_file_cleanup(priv); return POM_ERR; }
int output_log_xml_init(struct output *o) { struct output_log_xml_priv *priv = log_xml_init(); if (!priv) return POM_ERR; priv->p_source = ptype_alloc("string"); if (!priv->p_source) goto err; output_set_priv(o, priv); struct registry_instance *inst = output_get_reg_instance(o); priv->perf_events = registry_instance_add_perf(inst, "events", registry_perf_type_counter, "Number of events process", "events"); if (!priv->perf_events) goto err; struct registry_param *p = registry_new_param("filename", "log.xml", priv->p_filename, "XML log file", 0); if (output_add_param(o, p) != POM_OK) goto err; p = registry_new_param("source", "", priv->p_source, "Define the type of event being logged", 0); if (output_add_param(o, p) != POM_OK) goto err; return POM_OK; err: output_log_xml_cleanup(priv); return POM_ERR; }
static int input_pcap_file_init(struct input *i) { if (input_pcap_common_init(i) != POM_OK) return POM_ERR; struct input_pcap_priv *priv = i->priv; struct registry_param *p = NULL; priv->tpriv.file.p_file = ptype_alloc("string"); if (!priv->tpriv.file.p_file) goto err; p = registry_new_param("filename", "dump.cap", priv->tpriv.file.p_file, "File in PCAP format", 0); if (input_add_param(i, p) != POM_OK) goto err; priv->type = input_pcap_type_file; return POM_OK; err: if (priv->tpriv.file.p_file) ptype_cleanup(priv->tpriv.file.p_file); if (p) registry_cleanup_param(p); free(priv); return POM_ERR; }
static int input_pcap_common_init(struct input *i) { struct input_pcap_priv *priv; priv = malloc(sizeof(struct input_pcap_priv)); if (!priv) { pom_oom(sizeof(struct input_pcap_priv)); return POM_ERR; } memset(priv, 0, sizeof(struct input_pcap_priv)); struct registry_param *p = NULL; priv->p_filter = ptype_alloc("string"); if (!priv->p_filter) goto err; p = registry_new_param("bpf_filter", "", priv->p_filter, "BPF filter to use", 0); if (input_add_param(i, p) != POM_OK) goto err; i->priv = priv; return POM_OK; err: if (p) registry_cleanup_param(p); if (priv->p_filter) ptype_cleanup(priv->p_filter); free(priv); return POM_ERR; }
static int output_inject_init(struct output *o) { struct output_inject_priv *priv = malloc(sizeof(struct output_inject_priv)); if (!priv) { pom_oom(sizeof(struct output_inject_priv)); return POM_ERR; } memset(priv, 0, sizeof(struct output_inject_priv)); output_set_priv(o, priv); priv->p_interface = ptype_alloc("string"); priv->p_filter = ptype_alloc("string"); if (!priv->p_interface || !priv->p_filter) goto err; struct registry_instance *inst = output_get_reg_instance(o); priv->perf_pkts_out = registry_instance_add_perf(inst, "pkts_out", registry_perf_type_counter, "Number of packets injected", "pkts"); priv->perf_bytes_out = registry_instance_add_perf(inst, "bytes_out", registry_perf_type_counter, "Number of packet bytes injected", "bytes"); char err[PCAP_ERRBUF_SIZE] = { 0 }; char *dev = pcap_lookupdev(err); if (!dev) { pomlog(POMLOG_WARN, "Warning, could not find a suitable interface to inject packets to : %s", err); dev = "none"; } struct registry_param *p = registry_new_param("interface", dev, priv->p_interface, "Output interface", 0); if (output_add_param(o, p) != POM_OK) goto err; p = registry_new_param("filter", "", priv->p_filter, "Filter", REGISTRY_PARAM_FLAG_NOT_LOCKED_WHILE_RUNNING); if (output_add_param(o, p) != POM_OK) goto err; registry_param_set_callbacks(p, priv, output_inject_filter_parse, output_inject_filter_update); return POM_OK; err: output_inject_cleanup(priv); return POM_ERR; }
static struct output_tap_priv *tap_init() { struct output_tap_priv *priv = malloc(sizeof(struct output_tap_priv)); if (!priv) { pom_oom(sizeof(struct output_tap_priv)); return NULL; } memset(priv, 0, sizeof(struct output_tap_priv)); priv->fd = -1; priv->p_ifname = ptype_alloc("string"); priv->p_persistent = ptype_alloc("bool"); priv->p_filter = ptype_alloc("string"); if (!priv->p_ifname || !priv->p_persistent) { output_tap_cleanup(priv); return NULL; } return priv; }
static int input_pcap_dir_init(struct input *i) { if (input_pcap_common_init(i) != POM_OK) return POM_ERR; struct input_pcap_priv *priv = i->priv; struct registry_param *p = NULL; priv->tpriv.dir.p_dir = ptype_alloc("string"); priv->tpriv.dir.p_match = ptype_alloc("string"); if (!priv->tpriv.dir.p_dir || !priv->tpriv.dir.p_match) goto err; p = registry_new_param("directory", "/tmp", priv->tpriv.dir.p_dir, "Directory containing pcap files", 0); if (input_add_param(i, p) != POM_OK) goto err; p = registry_new_param("match", "\\.p\\?cap[0-9]*$", priv->tpriv.dir.p_match, "Match files with the specific pattern (regex)", 0); if (input_add_param(i, p) != POM_OK) goto err; priv->type = input_pcap_type_dir; return POM_OK; err: if (priv->tpriv.dir.p_dir) ptype_cleanup(priv->tpriv.dir.p_dir); if (p) registry_cleanup_param(p); free(priv); return POM_ERR; }
static struct output_log_xml_priv *log_xml_init() { struct output_log_xml_priv *priv = malloc(sizeof(struct output_log_xml_priv)); if (!priv) { pom_oom(sizeof(struct output_log_xml_priv)); return NULL; } memset(priv, 0, sizeof(struct output_log_xml_priv)); priv->fd = -1; priv->p_filename = ptype_alloc("string"); if (!priv->p_filename) { output_log_xml_cleanup(priv); return NULL; } return priv; }
static int registry_uid_add(struct registry_instance *instance, uint32_t uid) { // Add the uid to the instance struct ptype *uid_ptype = ptype_alloc("uint32"); if (!uid_ptype) return POM_ERR; PTYPE_UINT32_SETVAL(uid_ptype, uid); struct registry_param* uid_param = registry_new_param("uid", NULL, uid_ptype, "Unique ID", REGISTRY_PARAM_FLAG_CLEANUP_VAL | REGISTRY_PARAM_FLAG_IMMUTABLE); if (!uid_param) { ptype_cleanup(uid_ptype); return POM_ERR; } // Add the new uid to the table registry_uid_table_size++; uint32_t *new_uid_table = realloc(registry_uid_table, sizeof(uint32_t) * registry_uid_table_size); if (!new_uid_table) { pom_oom(sizeof(uint32_t) * registry_uid_table_size); ptype_cleanup(uid_ptype); return POM_ERR; } registry_uid_table = new_uid_table; registry_uid_table[registry_uid_table_size - 1] = uid; if (registry_instance_add_param(instance, uid_param) != POM_OK) { registry_cleanup_param(uid_param); ptype_cleanup(uid_ptype); registry_uid_table_size--; return POM_ERR; } return POM_OK; }
static int analyzer_smtp_event_process_begin(struct event *evt, void *obj, struct proto_process_stack *stack, unsigned int stack_index) { struct analyzer *analyzer = obj; struct analyzer_smtp_priv *apriv = analyzer->priv; struct proto_process_stack *s = &stack[stack_index]; if (!s->ce) return POM_ERR; // Only process stuff if we have the DATA event or if we already have an event struct event_reg *evt_reg = event_get_reg(evt); struct data *evt_data = event_get_data(evt); struct analyzer_smtp_ce_priv *cpriv = conntrack_get_priv(s->ce, analyzer); // It's expected that an SMTP connection will always contain at least one message // So we always create the cpriv and event, no matter what if (!cpriv) { cpriv = malloc(sizeof(struct analyzer_smtp_ce_priv)); if (!cpriv) { pom_oom(sizeof(struct analyzer_smtp_ce_priv)); return POM_ERR; } memset(cpriv, 0, sizeof(struct analyzer_smtp_ce_priv)); if (conntrack_add_priv(s->ce, analyzer, cpriv, analyzer_smtp_ce_priv_cleanup) != POM_OK) { free(cpriv); return POM_ERR; } } if (!cpriv->evt_msg) { cpriv->evt_msg = event_alloc(apriv->evt_msg); if (!cpriv->evt_msg) return POM_ERR; } struct data *msg_data = event_get_data(cpriv->evt_msg); if (evt_reg == apriv->evt_cmd) { if (!cpriv->common_data_fetched) analyzer_smtp_event_fetch_common_data(cpriv, stack, stack_index, POM_DIR_REVERSE(s->direction)); // Process commands // A message was being transmitted and we recevied a new command if (event_is_started(cpriv->evt_msg)) { event_process_end(cpriv->evt_msg); cpriv->evt_msg = NULL; } char *cmd = PTYPE_STRING_GETVAL(evt_data[proto_smtp_cmd_name].value); if (!cmd) return POM_OK; char *arg = PTYPE_STRING_GETVAL(evt_data[proto_smtp_cmd_arg].value); if (arg) { while (*arg == ' ') arg++; } if (!strcasecmp(cmd, "MAIL")) { if (strncasecmp(arg, "FROM:", strlen("FROM:"))) { pomlog(POMLOG_DEBUG "Unparseable MAIL command"); return POM_OK; } arg += strlen("FROM:"); while (*arg == ' ') arg++; if (*arg == '<') arg++; size_t len; char *end = strchr(arg, '>'); if (end) len = end - arg; else len = strlen(arg); PTYPE_STRING_SETVAL_N(msg_data[analyzer_smtp_msg_from].value, arg, len); data_set(msg_data[analyzer_smtp_msg_from]); cpriv->last_cmd = analyzer_smtp_last_cmd_mail_from; } else if (!strcasecmp(cmd, "RCPT")) { if (strncasecmp(arg, "TO:", strlen("TO:"))) { pomlog(POMLOG_DEBUG "Unparseable RCPT command"); return POM_OK; } arg += strlen("TO:"); while (*arg == ' ') arg++; if (*arg == '<') arg++; size_t len; char *end = strchr(arg, '>'); if (end) len = end - arg; else len = strlen(arg); struct ptype *to = ptype_alloc("string"); if (!to) return POM_ERR; PTYPE_STRING_SETVAL_N(to, arg, len); if (data_item_add_ptype(msg_data, analyzer_smtp_msg_to, strdup("to"), to) != POM_OK) { ptype_cleanup(to); return POM_ERR; } cpriv->last_cmd = analyzer_smtp_last_cmd_rcpt_to; } else if (!strcasecmp(cmd, "DATA")) { cpriv->last_cmd = analyzer_smtp_last_cmd_data; if (!event_is_started(cpriv->evt_msg)) { analyzer_smtp_event_fill_common_data(cpriv, msg_data); event_process_begin(cpriv->evt_msg, stack, stack_index, event_get_timestamp(evt)); } else { pomlog(POMLOG_DEBUG "Message event already started !"); } } else if (!strcasecmp(cmd, "RSET")) { // Cleanup the event event_cleanup(cpriv->evt_msg); cpriv->evt_msg = NULL; cpriv->last_cmd = analyzer_smtp_last_cmd_other; } else if (!strcasecmp(cmd, "HELO") || !strcasecmp(cmd, "EHLO")) { if (cpriv->client_hello) { pomlog(POMLOG_DEBUG "We already have a client hello !"); free(cpriv->client_hello); } cpriv->client_hello = strdup(arg); if (!cpriv->client_hello) { pom_oom(strlen(arg) + 1); return POM_ERR; } cpriv->last_cmd = analyzer_smtp_last_cmd_other; } else if (!strcasecmp(cmd, "AUTH")) { if (!strncasecmp(arg, "PLAIN", strlen("PLAIN"))) { arg += strlen("PLAIN"); while (*arg == ' ') arg++; if (cpriv->evt_auth) { event_process_end(cpriv->evt_auth); cpriv->evt_auth = NULL; } if (strlen(arg)) { if (analyzer_smtp_parse_auth_plain(apriv, cpriv, arg) == POM_OK) { event_process_begin(cpriv->evt_auth, stack, stack_index, event_get_timestamp(evt)); cpriv->last_cmd = analyzer_smtp_last_cmd_auth_plain_creds; } } else { cpriv->last_cmd = analyzer_smtp_last_cmd_auth_plain; } } else if (!strncasecmp(arg, "LOGIN", strlen("LOGIN"))) { arg += strlen("LOGIN"); while (*arg == ' ') arg++; if (cpriv->evt_auth) { event_process_end(cpriv->evt_auth); cpriv->evt_auth = NULL; } cpriv->evt_auth = event_alloc(apriv->evt_auth); if (!cpriv->evt_auth) return POM_ERR; struct data *auth_data = event_get_data(cpriv->evt_auth); analyzer_smtp_event_fill_common_data(cpriv, auth_data); // Set the authentication type PTYPE_STRING_SETVAL(auth_data[analyzer_smtp_auth_type].value, "LOGIN"); data_set(auth_data[analyzer_smtp_auth_type]); if (strlen(arg)) { char *username = NULL; size_t out_len = 0; struct ptype *username_pt = NULL; if (decoder_decode_simple("base64", arg, strlen(arg), &username, &out_len) == POM_OK) { username_pt = ptype_alloc("string"); if (username_pt) { PTYPE_STRING_SETVAL_P(username_pt, username); if (data_item_add_ptype(auth_data, analyzer_smtp_auth_params, strdup("username"), username_pt) != POM_OK) { ptype_cleanup(username_pt); event_cleanup(cpriv->evt_auth); cpriv->evt_auth = NULL; username_pt = NULL; } } else { free(username); } } if (!username_pt) { cpriv->last_cmd = analyzer_smtp_last_cmd_other; event_process_begin(cpriv->evt_auth, stack, stack_index, event_get_timestamp(evt)); } } else { cpriv->last_cmd = analyzer_smtp_last_cmd_auth_login; } } } else if (cpriv->last_cmd == analyzer_smtp_last_cmd_auth_plain) { // We are expecting the credentials right now if (analyzer_smtp_parse_auth_plain(apriv, cpriv, cmd) == POM_OK) { event_process_begin(cpriv->evt_auth, stack, stack_index, event_get_timestamp(evt)); cpriv->last_cmd = analyzer_smtp_last_cmd_auth_plain_creds; } else { cpriv->last_cmd = analyzer_smtp_last_cmd_other; } } else if (cpriv->last_cmd == analyzer_smtp_last_cmd_auth_login) { char *username = NULL; size_t out_len = 0; struct ptype *username_pt = NULL; if (decoder_decode_simple("base64", cmd, strlen(cmd), &username, &out_len) == POM_OK) { username_pt = ptype_alloc("string"); if (username_pt) { PTYPE_STRING_SETVAL_P(username_pt, username); struct data *auth_data = event_get_data(cpriv->evt_auth); if (data_item_add_ptype(auth_data, analyzer_smtp_auth_params, strdup("username"), username_pt) != POM_OK) { ptype_cleanup(username_pt); event_process_end(cpriv->evt_auth); cpriv->evt_auth = NULL; username_pt = NULL; } } else { free(username); } } if (!username_pt) { cpriv->last_cmd = analyzer_smtp_last_cmd_other; } else { event_process_begin(cpriv->evt_auth, stack, stack_index, event_get_timestamp(evt)); cpriv->last_cmd = analyzer_smtp_last_cmd_auth_login_user; } } else if (cpriv->last_cmd == analyzer_smtp_last_cmd_auth_login_user) { char *password = NULL; size_t out_len = 0; struct ptype *password_pt = NULL; if (decoder_decode_simple("base64", cmd, strlen(cmd), &password, &out_len) == POM_OK) { password_pt = ptype_alloc("string"); if (password_pt) { PTYPE_STRING_SETVAL_P(password_pt, password); struct data *auth_data = event_get_data(cpriv->evt_auth); if (data_item_add_ptype(auth_data, analyzer_smtp_auth_params, strdup("password"), password_pt) != POM_OK) { ptype_cleanup(password_pt); event_process_end(cpriv->evt_auth); cpriv->evt_auth = NULL; password_pt = NULL; } } else { free(password); } } if (!password_pt) { cpriv->last_cmd = analyzer_smtp_last_cmd_other; } else { cpriv->last_cmd = analyzer_smtp_last_cmd_auth_login_pass; } } else { cpriv->last_cmd = analyzer_smtp_last_cmd_other; } } else if (evt_reg == apriv->evt_reply) { if (!cpriv->common_data_fetched) analyzer_smtp_event_fetch_common_data(cpriv, stack, stack_index, s->direction); // Process replies uint16_t code = *PTYPE_UINT16_GETVAL(evt_data[proto_smtp_reply_code].value); switch (cpriv->last_cmd) { default: case analyzer_smtp_last_cmd_other: if (code == 220 && evt_data[proto_smtp_reply_text].items && evt_data[proto_smtp_reply_text].items->value) { // STARTTLS returns 220 as well so ignore extra code 220 if (!cpriv->server_hello) { char *helo = PTYPE_STRING_GETVAL(evt_data[proto_smtp_reply_text].items->value); cpriv->server_hello = strdup(helo); if (!cpriv->server_hello) { pom_oom(strlen(helo) + 1); return POM_ERR; } } } break; case analyzer_smtp_last_cmd_mail_from: if (code != 250) { // FROM is invalid data_unset(msg_data[analyzer_smtp_msg_from]); } break; case analyzer_smtp_last_cmd_rcpt_to: // For now just don't do anything // It's best to keep a destination in there even if it's invalid or denied break; case analyzer_smtp_last_cmd_data: if (code == 354) { // The message is starting, keep last_cmd intact return POM_OK; } // Message is over (if ever transmited) if (event_is_started(cpriv->evt_msg)) { struct data *msg_data = event_get_data(cpriv->evt_msg); PTYPE_UINT16_SETVAL(msg_data[analyzer_smtp_msg_result].value, code); data_set(msg_data[analyzer_smtp_msg_result]); event_process_end(cpriv->evt_msg); cpriv->evt_msg = NULL; } break; case analyzer_smtp_last_cmd_auth_plain: case analyzer_smtp_last_cmd_auth_login: case analyzer_smtp_last_cmd_auth_login_user: // Check if authentication phase can continue if (code == 334) { // Don't reset cpriv->last_cmd return POM_OK; } else { struct data *evt_data = event_get_data(cpriv->evt_auth); PTYPE_BOOL_SETVAL(evt_data[analyzer_smtp_auth_success].value, 0); data_set(evt_data[analyzer_smtp_auth_success]); event_process_end(cpriv->evt_auth); cpriv->evt_auth = NULL; } break; case analyzer_smtp_last_cmd_auth_plain_creds: case analyzer_smtp_last_cmd_auth_login_pass: { // We just processed the credentials struct data *auth_data = event_get_data(cpriv->evt_auth); char success = 0; if (code == 235) success = 1; PTYPE_BOOL_SETVAL(auth_data[analyzer_smtp_auth_success].value, success); data_set(auth_data[analyzer_smtp_auth_success]); event_process_end(cpriv->evt_auth); cpriv->evt_auth = NULL; break; } } cpriv->last_cmd = analyzer_smtp_last_cmd_other; } return POM_OK; }
static int analyzer_smtp_parse_auth_plain(struct analyzer_smtp_priv *apriv, struct analyzer_smtp_ce_priv *cpriv, char *auth_plain) { // Parse SASL AUTH PLAIN as described in RFC 4616 // The decoded arg must be at least 3 bytes if (strlen(auth_plain) < 4 || memchr(auth_plain, '=', 4)) { pomlog(POMLOG_DEBUG "AUTH PLAIN argument too short"); return POM_OK; } // Allocate the event cpriv->evt_auth = event_alloc(apriv->evt_auth); if (!cpriv->evt_auth) return POM_ERR; struct data *evt_data = event_get_data(cpriv->evt_auth); analyzer_smtp_event_fill_common_data(cpriv, evt_data); // Set the authentication type PTYPE_STRING_SETVAL(evt_data[analyzer_smtp_auth_type].value, "PLAIN"); data_set(evt_data[analyzer_smtp_auth_type]); // Parse the authentication stuff char *creds_str = NULL; size_t out_len = 0; if (decoder_decode_simple("base64", auth_plain, strlen(auth_plain), &creds_str, &out_len) != POM_OK) { pomlog(POMLOG_DEBUG "Unable to decode AUTH PLAIN message"); return POM_OK; } if (out_len < 3) { pomlog(POMLOG_DEBUG "Invalid decoded AUTH PLAIN data"); return POM_OK; } char *tmp = creds_str; // Add the identity if (strlen(tmp)) { // SASL AUTH PLAIN specifies struct ptype *identity = ptype_alloc("string"); if (!identity) goto err; PTYPE_STRING_SETVAL(identity, tmp); if (data_item_add_ptype(evt_data, analyzer_smtp_auth_params, strdup("identity"), identity) != POM_OK) { ptype_cleanup(identity); goto err; } } tmp += strlen(tmp) + 1; // Add the username struct ptype *username = ptype_alloc("string"); if (!username) goto err; PTYPE_STRING_SETVAL(username, tmp); if (data_item_add_ptype(evt_data, analyzer_smtp_auth_params, strdup("username"), username) != POM_OK) { ptype_cleanup(username); goto err; } tmp += strlen(tmp) + 1; // Add the password struct ptype *password = ptype_alloc("string"); if (!password) goto err; PTYPE_STRING_SETVAL(password, tmp); if (data_item_add_ptype(evt_data, analyzer_smtp_auth_params, strdup("password"), password) != POM_OK) { ptype_cleanup(password); goto err; } free(creds_str); return POM_OK; err: event_cleanup(cpriv->evt_auth); cpriv->evt_auth = NULL; free(creds_str); return POM_ERR; }
int core_init(unsigned int num_threads) { core_registry_class = registry_add_class(CORE_REGISTRY); if (!core_registry_class) return POM_ERR; perf_pkt_queue = registry_class_add_perf(core_registry_class, "pkt_queue", registry_perf_type_gauge, "Number of packets in the queue waiting to be processed", "pkts"); perf_thread_active = registry_class_add_perf(core_registry_class, "active_thread", registry_perf_type_gauge, "Number of active threads", "threads"); if (!perf_pkt_queue || !perf_thread_active) return POM_OK; core_param_dump_pkt = ptype_alloc("bool"); if (!core_param_dump_pkt) return POM_ERR; core_param_offline_dns = ptype_alloc("bool"); if (!core_param_offline_dns) { ptype_cleanup(core_param_dump_pkt); core_param_dump_pkt = NULL; return POM_ERR; } core_param_reset_perf_on_restart = ptype_alloc("bool"); if (!core_param_reset_perf_on_restart) { ptype_cleanup(core_param_dump_pkt); core_param_dump_pkt = NULL; ptype_cleanup(core_param_offline_dns); core_param_offline_dns = NULL; return POM_ERR; } struct registry_param *param = registry_new_param("dump_pkt", "no", core_param_dump_pkt, "Dump packets to logs", REGISTRY_PARAM_FLAG_CLEANUP_VAL); if (registry_class_add_param(core_registry_class, param) != POM_OK) goto err; param = registry_new_param("offline_dns", "yes", core_param_offline_dns, "Enable offline DNS resolver", REGISTRY_PARAM_FLAG_CLEANUP_VAL); if (registry_class_add_param(core_registry_class, param) != POM_OK) goto err; param = registry_new_param("reset_perf_on_restart", "no", core_param_reset_perf_on_restart, "Reset performances when core restarts", REGISTRY_PARAM_FLAG_CLEANUP_VAL); if (registry_class_add_param(core_registry_class, param) != POM_OK) goto err; param = NULL; // Start the processing threads unsigned int num_cpu = sysconf(_SC_NPROCESSORS_ONLN) - 1; if (num_cpu < 1) { pomlog(POMLOG_WARN "Could not find the number of CPU, assuming %u", CORE_PROCESS_THREAD_DEFAULT); num_cpu = CORE_PROCESS_THREAD_DEFAULT; } if (num_threads < 1) num_threads = num_cpu; if (num_threads > num_cpu) pomlog(POMLOG_WARN "WARNING : Running more processing threads than available CPU is discouraged as it will cause issues by creating higher latencies and eventually dropping packets !!! You have been warned !"); if (num_threads > CORE_PROCESS_THREAD_MAX) num_threads = CORE_PROCESS_THREAD_MAX; core_num_threads = num_threads; pomlog(POMLOG_INFO "Starting %u processing thread(s)", core_num_threads); core_run = 1; memset(core_processing_threads, 0, sizeof(struct core_processing_thread*) * CORE_PROCESS_THREAD_MAX); unsigned int i; for (i = 0; i < core_num_threads; i++) { struct core_processing_thread *tmp = malloc(sizeof(struct core_processing_thread)); if (!tmp) { pom_oom(sizeof(struct core_processing_thread)); goto err; } memset(tmp, 0, sizeof(struct core_processing_thread)); tmp->thread_id = i; int res = pthread_mutex_init(&tmp->pkt_queue_lock, NULL); if (res) { pomlog(POMLOG_ERR "Error while initializing a thread pkt_queue lock : %s", pom_strerror(res)); free(tmp); goto err; } res = pthread_cond_init(&tmp->pkt_queue_cond, NULL); if (res) { pomlog(POMLOG_ERR "Error while initializing a thread pkt_queue condition : %s", pom_strerror(res)); pthread_mutex_destroy(&tmp->pkt_queue_lock); free(tmp); goto err; } if (pthread_create(&tmp->thread, NULL, core_processing_thread_func, tmp)) { pomlog(POMLOG_ERR "Error while creating a new processing thread : %s", pom_strerror(errno)); pthread_mutex_destroy(&tmp->pkt_queue_lock); pthread_cond_destroy(&tmp->pkt_queue_cond); free(tmp); goto err; } core_processing_threads[i] = tmp; } return POM_OK; err: if (param) registry_cleanup_param(param); core_cleanup(0); return POM_ERR; }
int addon_output_init(struct output *o) { struct addon *addon = o->info->reg_info->mod->priv; lua_State *L = addon_create_state(addon->filename); // Stack : empty if (!L) { pomlog(POMLOG_ERR "Error while creating new lua state for output %s", o->info->reg_info->name); return POM_ERR; } // Get the output from the outputs table lua_getfield(L, LUA_REGISTRYINDEX, ADDON_OUTPUTS_TABLE); // Stack : outputs lua_getfield(L, -1, o->info->reg_info->name); // Stack : outputs, output // Get rid of the outputs table lua_remove(L, -2); // Stack : output lua_pushnil(L); // Stack : output, nil lua_setfield(L, LUA_REGISTRYINDEX, ADDON_OUTPUTS_TABLE); // Stack : output // Add the output to the registry lua_pushvalue(L, -1); // Stack : output, output lua_setfield(L, LUA_REGISTRYINDEX, ADDON_INSTANCE); // Stack : output // Create the private data // TODO make __priv read-only struct addon_instance_priv *p = lua_newuserdata(L, sizeof(struct addon_instance_priv)); // Stack : output, priv if (!p) { pom_oom(sizeof(struct addon_instance_priv)); return POM_ERR; } memset(p, 0, sizeof(struct addon_instance_priv)); o->priv = p; p->instance = o; p->L = L; if (pthread_mutex_init(&p->lock, NULL)) { pomlog(POMLOG_ERR "Error while initializing mutex : %s", pom_strerror(errno)); abort(); return POM_ERR; } // Assign the output_priv metatable luaL_getmetatable(L, ADDON_OUTPUT_PRIV_METATABLE); // Stack : output, priv, metatable lua_setmetatable(L, -2); // Stack : output, priv // Add it to __priv lua_setfield(L, -2, "__priv"); // Stack : output // Fetch the parameters table lua_getfield(L, -1, "__params"); // Stack : output, params // Parse each param from the class lua_pushnil(L); // Stack : output, params, nil while (lua_next(L, -2) != 0) { // Stack : output, params, key, param if (!lua_istable(L, -1)) { pomlog(POMLOG_ERR "Parameters should be described in tables"); goto err; } // Fetch the name lua_pushinteger(L, 1); // Stack : output, params, key, param, 1 lua_gettable(L, -2); // Stack : output, params, key, param, name if (!lua_isstring(L, -1)) { pomlog(POMLOG_ERR "Parameter name is not a string"); goto err; } const char *name = luaL_checkstring(L, -1); lua_pop(L, 1); // Stack : output, params, key, param // Fetch the ptype type lua_pushinteger(L, 2); // Stack : output, params, key, param, 2 lua_gettable(L, -2); // Stack : output, params, key, param, type if (!lua_isstring(L, -1)) { pomlog(POMLOG_ERR "Parameter type is not a string"); goto err; } const char *type = lua_tostring(L, -1); lua_pop(L, 1); // Stack : output, params, key, param // Fetch the default value lua_pushinteger(L, 3); // Stack : output, params, key, param, 3 lua_gettable(L, -2); // Stack : output, params, key, param, defval if (!lua_isstring(L, -1)) { pomlog(POMLOG_ERR "Parameter default value is not a string"); goto err; } const char *defval = lua_tostring(L, -1); lua_pop(L, 1); // Stack : output, params, key, param // Fetch the description lua_pushinteger(L, 4); // Stack : output, params, key, param, 4 lua_gettable(L, -2); // Stack : output, params, key, param, descr if (!lua_isstring(L, -1)) { pomlog(POMLOG_ERR "Parameter description is not a string"); goto err; } const char *descr = lua_tostring(L, -1); lua_pop(L, 1); // Stack : output, params, key, param // Allocate it struct addon_param *param = malloc(sizeof(struct addon_param)); if (!param) { pom_oom(sizeof(struct addon_param)); goto err; } param->name = strdup(name); if (!param->name) { free(param); pom_oom(strlen(name) + 1); goto err; } param->value = ptype_alloc(type); if (!param->value) { free(param->name); free(param); goto err; } struct registry_param *reg_param = registry_new_param((char*)name, (char*)defval, param->value, (char*)descr, 0); if (output_add_param(o, reg_param) != POM_OK) { pomlog(POMLOG_ERR "Error while adding parameter to the output instance"); if (reg_param) registry_cleanup_param(reg_param); free(param->name); ptype_cleanup(param->value); free(param); goto err; } param->next = p->params; p->params = param; // Pop the value (the param table) lua_pop(L, 1); // Stack : output, params, key } // At this point the stack is : output, params lua_pop(L, 2); // Stack : empty pomlog(POMLOG_DEBUG "Output %s created", o->name); return POM_OK; err: lua_close(L); p->L = NULL; return POM_ERR; }
int output_instance_add(char *type, char *name) { struct output_reg *reg; for (reg = output_reg_head; reg && strcmp(reg->reg_info->name, type); reg = reg->next); if (!reg) { pomlog(POMLOG_ERR "Output type %s does not exists", type); return POM_ERR; } struct output *res = malloc(sizeof(struct output)); if (!res) { pom_oom(sizeof(struct output)); return POM_ERR; } memset(res, 0, sizeof(struct output)); res->info = reg; res->name = strdup(name); if (!res->name) { pom_oom(strlen(name) + 1); goto err; } res->reg_instance = registry_add_instance(output_registry_class, name); if (!res->reg_instance) goto err; res->reg_instance->priv = res; res->perf_runtime = registry_instance_add_perf(res->reg_instance, "runtime", registry_perf_type_timeticks, "Runtime", NULL); if (!res->perf_runtime) goto err; struct ptype *param_running_val = ptype_alloc("bool"); if (!param_running_val) goto err; struct registry_param *param_running = registry_new_param("running", "no", param_running_val, "Running state of the output", REGISTRY_PARAM_FLAG_CLEANUP_VAL); if (!param_running) { ptype_cleanup(param_running_val); goto err; } if (registry_param_set_callbacks(param_running, res, NULL, output_instance_start_stop_handler) != POM_OK) { registry_cleanup_param(param_running); ptype_cleanup(param_running_val); goto err; } if (registry_instance_add_param(res->reg_instance, param_running) != POM_OK) { registry_cleanup_param(param_running); ptype_cleanup(param_running_val); goto err; } struct ptype *output_type = ptype_alloc("string"); if (!output_type) goto err; struct registry_param *type_param = registry_new_param("type", type, output_type, "Type of the output", REGISTRY_PARAM_FLAG_CLEANUP_VAL | REGISTRY_PARAM_FLAG_IMMUTABLE); if (!type_param) { ptype_cleanup(output_type); goto err; } if (registry_instance_add_param(res->reg_instance, type_param) != POM_OK) { registry_cleanup_param(type_param); ptype_cleanup(output_type); goto err; } if (registry_uid_create(res->reg_instance) != POM_OK) goto err; if (reg->reg_info->init) { if (reg->reg_info->init(res) != POM_OK) { pomlog(POMLOG_ERR "Error while initializing the output %s", name); goto err; } } res->next = output_head; if (res->next) res->next->prev = res; output_head = res; return POM_OK; err: if (res->reg_instance) { registry_remove_instance(res->reg_instance); } else { if (res->name) free(res->name); free(res); } return POM_ERR; }
static int input_pcap_interface_init(struct input *i) { if (input_pcap_common_init(i) != POM_OK) return POM_ERR; struct input_pcap_priv *priv = i->priv; struct registry_param *p = NULL; priv->tpriv.iface.p_interface = ptype_alloc("string"); priv->tpriv.iface.p_promisc = ptype_alloc("bool"); priv->tpriv.iface.p_buff_size = ptype_alloc_unit("uint32", "bytes"); if (!priv->tpriv.iface.p_interface || !priv->tpriv.iface.p_promisc || !priv->tpriv.iface.p_buff_size) goto err; priv->tpriv.iface.perf_dropped = registry_instance_add_perf(i->reg_instance, "dropped_pkt", registry_perf_type_counter, "Dropped packets", "pkts"); if (!priv->tpriv.iface.perf_dropped) goto err; registry_perf_set_update_hook(priv->tpriv.iface.perf_dropped, input_pcap_interface_perf_dropped, priv); char err[PCAP_ERRBUF_SIZE] = { 0 }; char *dev = "<none>"; pcap_if_t *alldevsp = NULL; if (pcap_findalldevs(&alldevsp, err)) { pomlog(POMLOG_WARN "Warning, could not find a suitable interface to sniff packets from : %s", err); alldevsp = NULL; } else { dev = alldevsp->name; } p = registry_new_param("interface", dev, priv->tpriv.iface.p_interface, "Interface to capture packets from", 0); if (alldevsp) { pcap_if_t *tmp; for (tmp = alldevsp; tmp; tmp = tmp->next) { if (registry_param_info_add_value(p, tmp->name) != POM_OK) { pcap_freealldevs(alldevsp); goto err; } } pcap_freealldevs(alldevsp); } if (input_add_param(i, p) != POM_OK) goto err; p = registry_new_param("promisc", "no", priv->tpriv.iface.p_promisc, "Promiscious mode", 0); if (input_add_param(i, p) != POM_OK) goto err; p = registry_new_param("buff_size", "16777216", priv->tpriv.iface.p_buff_size, "PCAP ring buffer size", 0); if (input_add_param(i, p) != POM_OK) goto err; priv->type = input_pcap_type_interface; return POM_OK; err: if (priv->tpriv.iface.p_interface) ptype_cleanup(priv->tpriv.iface.p_interface); if (priv->tpriv.iface.p_promisc) ptype_cleanup(priv->tpriv.iface.p_promisc); if (priv->tpriv.iface.p_buff_size) ptype_cleanup(priv->tpriv.iface.p_buff_size); if (p) registry_cleanup_param(p); free(priv); return POM_ERR; }
static int proto_smtp_process(void *proto_priv, struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) { struct proto_process_stack *s = &stack[stack_index]; struct proto_process_stack *s_next = &stack[stack_index + 1]; if (conntrack_get_unique_from_parent(stack, stack_index) != POM_OK) { pomlog(POMLOG_ERR "Could not get conntrack entry"); return PROTO_ERR; } // There should no need to keep the lock here since we are in the packet_stream lock from proto_tcp conntrack_unlock(s->ce); struct proto_smtp_priv *ppriv = proto_priv; struct proto_smtp_conntrack_priv *priv = s->ce->priv; if (!priv) { priv = malloc(sizeof(struct proto_smtp_conntrack_priv)); if (!priv) { pom_oom(sizeof(struct proto_smtp_conntrack_priv)); return PROTO_ERR; } memset(priv, 0, sizeof(struct proto_smtp_conntrack_priv)); priv->parser[POM_DIR_FWD] = packet_stream_parser_alloc(SMTP_MAX_LINE, PACKET_STREAM_PARSER_FLAG_TRIM); if (!priv->parser[POM_DIR_FWD]) { free(priv); return PROTO_ERR; } priv->parser[POM_DIR_REV] = packet_stream_parser_alloc(SMTP_MAX_LINE, PACKET_STREAM_PARSER_FLAG_TRIM); if (!priv->parser[POM_DIR_REV]) { packet_stream_parser_cleanup(priv->parser[POM_DIR_FWD]); free(priv); return PROTO_ERR; } priv->server_direction = POM_DIR_UNK; s->ce->priv = priv; } if (priv->flags & PROTO_SMTP_FLAG_INVALID) return PROTO_OK; struct packet_stream_parser *parser = priv->parser[s->direction]; if (packet_stream_parser_add_payload(parser, s->pload, s->plen) != POM_OK) return PROTO_ERR; char *line = NULL; size_t len = 0; while (1) { // Some check to do prior to parse the payload if (s->direction == POM_DIR_REVERSE(priv->server_direction)) { if (priv->flags & PROTO_SMTP_FLAG_STARTTLS) { // Last command was a STARTTLS command, this is the TLS negociation // Since we can't parse this, mark it as invalid priv->flags |= PROTO_SMTP_FLAG_INVALID; return PROTO_OK; } else if (priv->flags & PROTO_SMTP_FLAG_CLIENT_DATA) { // We are receiving payload data, check where the end is void *pload; size_t plen; packet_stream_parser_get_remaining(parser, &pload, &plen); if (!plen) return PROTO_OK; // Look for the "<CR><LF>.<CR><LF>" sequence if (priv->data_end_pos > 0) { // The previous packet ended with something that might be the final sequence // Check if we have the rest int i, found = 1; for (i = 0; i < PROTO_SMTP_DATA_END_LEN - priv->data_end_pos && i <= plen; i++) { if (*(char*)(pload + i) != PROTO_SMTP_DATA_END[priv->data_end_pos + i]) { found = 0; break; } } if (found) { // If we have already processed the dot after <CR><LF> there is no way to remove it // Thus we mark this connection as invalid. Most MTA will send at worst the last // 3 bytes of the end sequence in a sequence packet if (i != plen || (priv->data_end_pos >= 2 && plen < 3)) { pomlog(POMLOG_DEBUG "The final line was not at the of a packet as expected !"); priv->flags |= PROTO_SMTP_FLAG_INVALID; event_process_end(priv->data_evt); priv->data_evt = NULL; return PROTO_OK; } s_next->pload = pload; s_next->plen = plen - PROTO_SMTP_DATA_END_LEN + 2; // The last line return is part of the payload priv->flags |= PROTO_SMTP_FLAG_CLIENT_DATA_END; priv->flags &= ~PROTO_SMTP_FLAG_CLIENT_DATA; priv->data_end_pos = 0; return PROTO_OK; } priv->data_end_pos = 0; } char *dotline = pom_strnstr(pload, PROTO_SMTP_DATA_END, plen); if (dotline) { if (pload + plen - PROTO_SMTP_DATA_END_LEN != dotline) { pomlog(POMLOG_DEBUG "The final line was not at the of a packet as expected !"); priv->flags |= PROTO_SMTP_FLAG_INVALID; event_process_end(priv->data_evt); priv->data_evt = NULL; return PROTO_OK; } s_next->pload = pload; s_next->plen = plen - PROTO_SMTP_DATA_END_LEN + 2; // The last line return is part of the payload priv->flags |= PROTO_SMTP_FLAG_CLIENT_DATA_END; priv->flags &= ~PROTO_SMTP_FLAG_CLIENT_DATA; } else { // Check if the end of the payload contains part of the "<CR><LF>.<CR><LF>" sequence int i, found = 0; for (i = 1 ; (i < PROTO_SMTP_DATA_END_LEN) && (i <= plen); i++) { if (!memcmp(pload + plen - i, PROTO_SMTP_DATA_END, i)) { found = 1; break; } } if (found) priv->data_end_pos = i; s_next->pload = pload; s_next->plen = plen; } return PROTO_OK; } } // Process commands if (packet_stream_parser_get_line(parser, &line, &len) != POM_OK) return PROTO_ERR; if (!line) return PROTO_OK; if (!len) // Probably a missed packet return PROTO_OK; // Try to find the server direction if (priv->server_direction == POM_DIR_UNK) { unsigned int code = atoi(line); if (code > 0) { priv->server_direction = s->direction; } else { priv->server_direction = POM_DIR_REVERSE(s->direction); } } if (s->direction == priv->server_direction) { // Parse the response code and generate the event if ((len < 5) || // Server response is 3 digit error code, a space or hyphen and then at least one letter of text (line[3] != ' ' && line[3] != '-')) { pomlog(POMLOG_DEBUG "Too short or invalid response from server"); priv->flags |= PROTO_SMTP_FLAG_INVALID; return POM_OK; } int code = atoi(line); if (code == 0) { pomlog(POMLOG_DEBUG "Invalid response from server"); priv->flags |= PROTO_SMTP_FLAG_INVALID; return POM_OK; } if (event_has_listener(ppriv->evt_reply)) { struct data *evt_data = NULL; if (priv->reply_evt) { evt_data = event_get_data(priv->reply_evt); uint16_t cur_code = *PTYPE_UINT16_GETVAL(evt_data[proto_smtp_reply_code].value); if (cur_code != code) { pomlog(POMLOG_WARN "Multiline code not the same as previous line : %hu -> %hu", cur_code, code); event_process_end(priv->reply_evt); priv->reply_evt = NULL; } } if (!priv->reply_evt) { priv->reply_evt = event_alloc(ppriv->evt_reply); if (!priv->reply_evt) return PROTO_ERR; evt_data = event_get_data(priv->reply_evt); PTYPE_UINT16_SETVAL(evt_data[proto_smtp_reply_code].value, code); data_set(evt_data[proto_smtp_reply_code]); } if (len > 4) { struct ptype *txt = ptype_alloc("string"); if (!txt) return PROTO_ERR; PTYPE_STRING_SETVAL_N(txt, line + 4, len - 4); if (data_item_add_ptype(evt_data, proto_smtp_reply_text, strdup("text"), txt) != POM_OK) return PROTO_ERR; } if (!event_is_started(priv->reply_evt)) event_process_begin(priv->reply_evt, stack, stack_index, p->ts); } if (line[3] != '-') { // Last line in the response if (priv->reply_evt) { event_process_end(priv->reply_evt); priv->reply_evt = NULL; } } if (priv->flags & PROTO_SMTP_FLAG_STARTTLS) { // The last command was STARTTLS priv->flags &= ~PROTO_SMTP_FLAG_STARTTLS; if (code == 220) { // TLS has the go, we can't parse from now so mark as invalid priv->flags |= PROTO_SMTP_FLAG_INVALID; return POM_OK; } } } else { // Client command if (len < 4) { // Client commands are at least 4 bytes long pomlog(POMLOG_DEBUG "Too short or invalid query from client"); priv->flags |= PROTO_SMTP_FLAG_INVALID; return POM_OK; } // Make sure it's a command by checking it's at least a four letter word int i; for (i = 0; i < 4; i++) { // In some case it can also be a base64 encoded word if (! ((line[i] >= 'A' && line[i] <= 'Z') || (line[i] >= 'a' && line[i] <= 'z') || (line[i] >= '0' && line [i] <= '9') || line[i] == '=')) break; } if ((i < 4)) { pomlog(POMLOG_DEBUG "Recieved invalid client command"); priv->flags |= PROTO_SMTP_FLAG_INVALID; return POM_OK; } if (!strncasecmp(line, "DATA", strlen("DATA")) && len == strlen("DATA")) { priv->flags |= PROTO_SMTP_FLAG_CLIENT_DATA; } else if (!strncasecmp(line, "STARTTLS", strlen("STARTTLS")) && len == strlen("STARTTLS")) { priv->flags |= PROTO_SMTP_FLAG_STARTTLS; } if (event_has_listener(ppriv->evt_cmd)) { struct event *evt = event_alloc(ppriv->evt_cmd); if (!evt) return PROTO_ERR; size_t cmdlen = len; char *space = memchr(line, ' ', len); if (space) cmdlen = space - line; struct data *evt_data = event_get_data(evt); PTYPE_STRING_SETVAL_N(evt_data[proto_smtp_cmd_name].value, line, cmdlen); data_set(evt_data[proto_smtp_cmd_name]); if (space) { PTYPE_STRING_SETVAL_N(evt_data[proto_smtp_cmd_arg].value, space + 1, len - 1 - cmdlen); data_set(evt_data[proto_smtp_cmd_arg]); } if (priv->flags & PROTO_SMTP_FLAG_CLIENT_DATA) { // The event ends at the end of the message priv->data_evt = evt; return event_process_begin(evt, stack, stack_index, p->ts); } else { return event_process(evt, stack, stack_index, p->ts); } } } } return PROTO_OK; }
static void analyzer_jpeg_exif_entry_analyze(ExifEntry *entry, void *pload) { ExifIfd ifd = exif_content_get_ifd(entry->parent); const char *tag_name = exif_tag_get_name_in_ifd(entry->tag, ifd); if (!tag_name) // Unknown tag return; struct ptype *value = NULL; // First parse ascii values if (entry->format == EXIF_FORMAT_ASCII) { char *str = malloc(entry->size); if (!str) { pom_oom(entry->size); return; } memcpy(str, entry->data, entry->size); // Make sure it's NULL terminated str[entry->size - 1] = 0; value = ptype_alloc("string"); if (!value) { free(str); return; } PTYPE_STRING_SETVAL_P(value, str); } else if (entry->components == 1) { ExifByteOrder byte_order = exif_data_get_byte_order(entry->parent->parent); if (entry->format == EXIF_FORMAT_BYTE) { value = ptype_alloc("uint8"); if (!value) return; PTYPE_UINT8_SETVAL(value, *entry->data); } else if (entry->format == EXIF_FORMAT_SHORT) { value = ptype_alloc("uint16"); if (!value) return; PTYPE_UINT16_SETVAL(value, exif_get_short(entry->data, byte_order)); } else if (entry->format == EXIF_FORMAT_LONG) { value = ptype_alloc("uint32"); if (!value) return; PTYPE_UINT32_SETVAL(value, exif_get_long(entry->data, byte_order)); } } if (!value) { // Fallback for types not parsed by us yet // FIXME this is subject to the locale char buff[256]; buff[sizeof(buff) - 1] = 0; exif_entry_get_value(entry, buff, sizeof(buff) - 1); value = ptype_alloc("string"); if (!value) return; PTYPE_STRING_SETVAL(value, buff); } char *key = strdup(tag_name); if (!key) { pom_oom(strlen(tag_name) + 1); return; } struct data *data = analyzer_pload_buffer_get_data(pload); data_item_add_ptype(data, analyzer_jpeg_pload_exif, key, value); }