예제 #1
0
void readAslRow(aslmsg row, Row& r) {
  pt::ptree extras;

  // Fetch each column individually, adding it to the result map
  size_t i = 0;
  for (const char* key = asl_key(row, i); key != nullptr;
       key = asl_key(row, ++i)) {
    const char* val = asl_get(row, key);

    // Rarely, asl_fetch_key_val_op will return a NULL pointer for
    // key/value, so we defend against that case by using the empty string
    std::string key_s = key != nullptr ? std::string(key) : "";
    std::string val_s = val != nullptr ? std::string(val) : "";

    if (kAslKeyToColumnMap.count(key_s) > 0) {
      // This key is a default column
      r[kAslKeyToColumnMap.at(key_s)] = val_s;
    } else {
      // This key is not a default column, add it to extras
      extras.push_back(pt::ptree::value_type(key_s, pt::ptree(val_s)));
    }
  }

  // Join up the extras and add them to the Extra column
  std::stringstream ss;
  pt::write_json(ss, extras, false);
  r[kExtraColumnKey] = ss.str();
}
예제 #2
0
/* qsort compare function for sorting by message ID */
static int
sort_compare(const void *a, const void *b)
{
	const char *va, *vb;
	uint64_t na, nb;

	va = asl_get(*(aslmsg *)a, ASL_KEY_MSG_ID);
	vb = asl_get(*(aslmsg *)b, ASL_KEY_MSG_ID);

	if (va == NULL) return -1;
	if (vb == NULL) return 1;

	na = atoll(va);
	nb = atoll(vb);

	if (na < nb) return -1;
	if (na > nb) return 1;
	return 0;
}
예제 #3
0
static int
_bsd_send(aslmsg msg, struct config_rule *r, char **out, char **fwd, time_t now)
{
	char *sf, *outmsg;
	const char *vlevel, *vfacility;
	size_t outlen;
	int pf, fc, status, is_dup, do_write;
	uint32_t msg_hash, n;

	if (out == NULL) return -1;
	if (fwd == NULL) return -1;
	if (r == NULL) return -1;

	_syslog_dst_open(r);

	if (r->type == DST_TYPE_NOTE)
	{
		notify_post(r->dst+1);
		return 0;
	}

	msg_hash = 0;
	outmsg = NULL;

	/* Build output string if it hasn't been built by a previous rule-match */
	if (*out == NULL)
	{
		*out = asl_format_message((asl_msg_t *)msg, ASL_MSG_FMT_BSD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE, &n);
		if (*out == NULL) return -1;
	}

	/* check if message is a duplicate of the last message, and inside the dup time window */
	is_dup = 0;
	if ((global.bsd_max_dup_time > 0) && (*out != NULL) && (r->last_msg != NULL))
	{
		msg_hash = asl_core_string_hash(*out + 16, strlen(*out + 16));
		if ((r->last_hash == msg_hash) && (!strcmp(r->last_msg, *out + 16)))
		{
			if ((now - r->last_time) < global.bsd_max_dup_time) is_dup = 1;
		}
	}

	if ((*fwd == NULL) && (r->type == DST_TYPE_SOCK))
	{
		pf = 7;
		vlevel = asl_get(msg, ASL_KEY_LEVEL);
		if (vlevel != NULL) pf = atoi(vlevel);

		fc = asl_syslog_faciliy_name_to_num(asl_get(msg, ASL_KEY_FACILITY));
		if (fc > 0) pf |= fc;

		sf = NULL;
		asprintf(&sf, "<%d>%s", pf, *out);
		if (sf == NULL) return -1;

		*fwd = sf;
	}

	if (r->type == DST_TYPE_SOCK) outlen = strlen(*fwd);
	else outlen = strlen(*out);

	if ((r->type == DST_TYPE_FILE) || (r->type == DST_TYPE_CONS))
	{
		/*
		 * If current message is NOT a duplicate and r->last_count > 0
		 * we need to write a "last message was repeated N times" log entry
		 */
		if ((r->type == DST_TYPE_FILE) && (is_dup == 0) && (r->last_count > 0)) _bsd_send_repeat_msg(r);

		do_write = 1;

		/*
		 * Special case for kernel messages.
		 * Don't write kernel messages to /dev/console.
		 * The kernel printf routine already sends them to /dev/console
		 * so writing them here would cause duplicates.
		 */
		vfacility = asl_get(msg, ASL_KEY_FACILITY);
		if ((vfacility != NULL) && (!strcmp(vfacility, FACILITY_KERNEL)) && (r->type == DST_TYPE_CONS)) do_write = 0;
		if ((do_write == 1) && (r->type == DST_TYPE_FILE) && (is_dup == 1))
		{
			do_write = 0;

			if (r->dup_timer == NULL)
			{
				/* create a timer to flush dups on this file */
				r->dup_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, bsd_out_queue);
				dispatch_source_set_event_handler(r->dup_timer, ^{ _bsd_send_repeat_msg(r); });
			}
예제 #4
0
/* save a message to an appropriately named BB file */
static uint32_t 
save_bb_msg(aslmsg msg)
{
	const char *val;
	uid_t u, ruid;
	gid_t g, rgid;
	struct tm ctm;
	time_t msg_time, bb;
	char *path, *tstring;
	asl_file_t *out;
	uint64_t mid;
	mode_t m;
	uint32_t status;

	if (msg == NULL) return ASL_STATUS_OK;

	val = asl_get(msg, ASL_KEY_EXPIRE_TIME);
	if (val == NULL)  return ASL_STATUS_INVALID_ARG;
	msg_time = asl_parse_time(val);

	val = asl_get(msg, ASL_KEY_READ_UID);
	ruid = -1;
	if (val != NULL) ruid = atoi(val);

	val = asl_get(msg, ASL_KEY_READ_GID);
	rgid = -1;
	if (val != NULL) rgid = atoi(val);

	if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED;

	/*
	 * This supports 12 monthy "Best Before" buckets.
	 * We advance the actual expiry time to day zero of the following month.
	 * mktime() is clever enough to know that you actually mean the last day
	 * of the previous month.  What we get back from localtime is the last
	 * day of the month in which the message expires, which we use in the name.
	 */
	ctm.tm_sec = 0;
	ctm.tm_min = 0;
	ctm.tm_hour = 0;
	ctm.tm_mday = 0;
	ctm.tm_mon += 1;

	bb = mktime(&ctm);

	u = 0;
	g = 0;
	if (ruid != -1) u = ruid;
	if (rgid != -1) g = rgid;

	out = NULL;

	if (cache_file != NULL)
	{
		if ((cache_uid == u) && (cache_gid == g) && (cache_bb == bb))
		{
			out = cache_file;
		}
		else
		{
			asl_file_close(cache_file);
			cache_file = NULL;
			cache_uid = -1;
			cache_gid = -1;
			cache_bb = 0;
		}
	}

	if (out == NULL)
	{
		if (localtime_r((const time_t *)&bb, &ctm) == NULL) return ASL_STATUS_FAILED;

		tstring = NULL;
		asprintf(&tstring, "%s/BB.%d.%02d.%02d", store_path, ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
		if (tstring == NULL) return ASL_STATUS_NO_MEMORY;

		path = NULL;
		m = 0644;

		if (ruid == -1)
		{
			if (rgid == -1)
			{
				asprintf(&path, "%s.asl", tstring);
			}
			else
			{
				m = 0640;
				asprintf(&path, "%s.G%d.asl", tstring, g);
			}
		}
		else
		{
			if (rgid == -1)
			{
				m = 0600;
				asprintf(&path, "%s.U%d.asl", tstring, u);
			}
			else
			{
				m = 0640;
				asprintf(&path, "%s.U%d.G%u.asl", tstring, u, g);
			}
		}

		if (path == NULL) return ASL_STATUS_NO_MEMORY;

		status = asl_file_open_write(path, m, u, g, &out);
		free(path);
		if (status != ASL_STATUS_OK) return status;
		if (out == NULL) return ASL_STATUS_FAILED;

		out->flags = ASL_FILE_FLAG_PRESERVE_MSG_ID;

		cache_file = out;
		cache_uid = u;
		cache_gid = g;
		cache_bb = bb;
	}

	status = asl_file_save(out, msg, &mid);

	return status;
}
예제 #5
0
/* remove all messages that have an ASLExpireTime key */
static uint32_t
do_ASLExpireTime_filter(const char *name)
{
	aslmsg msg;
	asl_file_t *in, *out;
	uint32_t status;
	uint64_t mid;
	char *inpath, *outpath;
	struct stat sb;

	if (name == NULL) return ASL_STATUS_INVALID_ARG;

	in = NULL;
	inpath = NULL;
	asprintf(&inpath, "%s/%s", store_path, name);
	if (inpath == NULL) return ASL_STATUS_NO_MEMORY;

	memset(&sb, 0, sizeof(struct stat));
	if (stat(inpath, &sb) < 0)
	{
		free(inpath);
		return ASL_STATUS_INVALID_STORE;
	}

	status = asl_file_open_read(inpath, &in);
	if (status != ASL_STATUS_OK) 
	{
		free(inpath);
		return ASL_STATUS_OK;
	}

	out = NULL;
	outpath = NULL;
	asprintf(&outpath, "%s/%s", store_path, TEMP_NAME);
	if (outpath == NULL)
	{
		asl_file_close(in);
		free(inpath);
		return ASL_STATUS_NO_MEMORY;
	}

	status = asl_file_open_write(outpath, sb.st_mode, sb.st_uid, sb.st_gid, &out);
	if (status != ASL_STATUS_OK)
	{
		asl_file_close(in);
		free(inpath);
		free(outpath);
		return status;
	}

	out->flags = ASL_FILE_FLAG_PRESERVE_MSG_ID;

	msg = NULL;
	while (asl_file_fetch_next(in, &msg) == ASL_STATUS_OK)
	{
		if (msg == NULL) break;

		mid = 0;

		if (asl_get(msg, ASL_KEY_EXPIRE_TIME) == NULL) status = asl_file_save(out, msg, &mid);

		asl_free(msg);
		msg = NULL;

		if (status != ASL_STATUS_OK) break;
	}

	asl_file_close(in);
	asl_file_close(out);

	unlink(inpath);
	rename(outpath, inpath);

	free(inpath);
	free(outpath);

	return status;
}
예제 #6
0
uint32_t
asl_store_open_aux(asl_store_t *s, aslmsg msg, int *out_fd, char **url)
{
	struct tm ctm;
	time_t msg_time, bb;
	char *path, *dir, *tstring;
	const char *val;
	uid_t ruid, u;
	gid_t rgid, g;
	mode_t m;
	uint32_t status;
	uint64_t fid;
	int fd;

	if (s == NULL) return ASL_STATUS_INVALID_STORE;
	if (msg == NULL) return ASL_STATUS_INVALID_ARG;
	if (out_fd == NULL) return ASL_STATUS_INVALID_ARG;
	if (url == NULL) return ASL_STATUS_INVALID_ARG;

	msg_time = time(NULL);

	val = asl_get(msg, ASL_KEY_READ_UID);
	ruid = -1;
	if (val != NULL) ruid = atoi(val);

	val = asl_get(msg, ASL_KEY_READ_GID);
	rgid = -1;
	if (val != NULL) rgid = atoi(val);

	bb = 0;
	val = asl_get(msg, ASL_KEY_EXPIRE_TIME);
	if (val != NULL)
	{
		bb = 1;
		msg_time = asl_parse_time(val);
	}

	if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED;

	dir = NULL;
	if (bb == 1)
	{
		/*
		 * This supports 12 monthly "Best Before" buckets.
		 * We advance the actual expiry time to day zero of the following month.
		 * mktime() is clever enough to know that you actually mean the last day
		 * of the previous month.  What we get back from localtime is the last
		 * day of the month in which the message expires, which we use in the name.
		 */
		ctm.tm_sec = 0;
		ctm.tm_min = 0;
		ctm.tm_hour = 0;
		ctm.tm_mday = 0;
		ctm.tm_mon += 1;

		bb = mktime(&ctm);

		if (localtime_r((const time_t *)&bb, &ctm) == NULL) return ASL_STATUS_FAILED;
		asprintf(&dir, "BB.AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
	}
	else
	{
		asprintf(&dir, "AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
	}

	if (dir == NULL) return ASL_STATUS_NO_MEMORY;

	status = asl_store_mkdir(s, dir, 0755);
	if (status != ASL_STATUS_OK)
	{
		free(dir);
		return status;
	}

	fid = s->next_id;
	s->next_id++;
	tstring = NULL;

	asprintf(&tstring, "%s/%llu", dir, fid);
	free(dir);
	if (tstring == NULL) return ASL_STATUS_NO_MEMORY;

	u = 0;
	g = 0;
	m = 0644;
	path = asl_store_make_ug_path(s->base_dir, tstring, NULL, ruid, rgid, &u, &g, &m);
	free(tstring);
	if (path == NULL) return ASL_STATUS_NO_MEMORY;

	fd = asl_file_create(path, u, g, m);
	if (fd < 0)
	{
		free(path);
		*out_fd = -1;
		return ASL_STATUS_WRITE_FAILED;
	}

	/* URL is file://<path> */
	*url = NULL;
	asprintf(url, "file://%s", path);
	free(path);

	*out_fd = fd;

	return status;
}
예제 #7
0
uint32_t
asl_store_save(asl_store_t *s, aslmsg msg)
{
	struct tm ctm;
	time_t msg_time, now, bb;
	char *path, *tmp_path, *tstring, *scratch;
	const char *val;
	uid_t ruid;
	gid_t rgid;
	asl_file_t *f;
	uint32_t status, check_cache, trigger_aslmanager, len;
	uint64_t xid, ftime;
	size_t fsize;

	if (s == NULL) return ASL_STATUS_INVALID_STORE;
	if (msg == NULL) return ASL_STATUS_INVALID_ARG;

	now = time(NULL);

	check_cache = 0;
	if ((s->last_write + FILE_CACHE_TTL) <= now) check_cache = 1;

	trigger_aslmanager = 0;

	msg_time = 0;
	val = asl_get(msg, ASL_KEY_TIME);
	if (val == NULL) msg_time = now;
	else msg_time = asl_parse_time(val);

	if (msg_time >= s->start_tomorrow)
	{
		if (now >= s->start_tomorrow)
		{
			/* new day begins */
			check_cache = 0;
			asl_store_file_closeall(s);

			/*
			 * _asl_start_today should never fail, but if it does,
			 * just push forward one day.  That will probably be correct, and if
			 * it isn't, the next message that gets saved will push it ahead again
			 * until we get to the right date.
			 */
			s->start_today = _asl_start_today();
			if (s->start_today == 0) s->start_today = s->start_tomorrow;

			s->start_tomorrow = s->start_today + SECONDS_PER_DAY;
		}
	}

	val = asl_get(msg, ASL_KEY_READ_UID);
	ruid = -1;
	if (val != NULL) ruid = atoi(val);

	val = asl_get(msg, ASL_KEY_READ_GID);
	rgid = -1;
	if (val != NULL) rgid = atoi(val);

	bb = 0;
	val = asl_get(msg, ASL_KEY_EXPIRE_TIME);
	if (val != NULL)
	{
		bb = 1;
		msg_time = asl_parse_time(val);
	}

	if (fseeko(s->storedata, 0, SEEK_SET) != 0) return ASL_STATUS_WRITE_FAILED;

	xid = asl_core_htonq(s->next_id);
	if (fwrite(&xid, sizeof(uint64_t), 1, s->storedata) != 1) return ASL_STATUS_WRITE_FAILED;

	/* flush data */
	fflush(s->storedata);

	xid = s->next_id;
	s->next_id++;

	s->last_write = now;

	if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED;

	tstring = NULL;
	if (bb == 1)
	{
		/*
		 * This supports 12 monthly "Best Before" buckets.
		 * We advance the actual expiry time to day zero of the following month.
		 * mktime() is clever enough to know that you actually mean the last day
		 * of the previous month.  What we get back from localtime is the last
		 * day of the month in which the message expires, which we use in the name.
		 */
		ctm.tm_sec = 0;
		ctm.tm_min = 0;
		ctm.tm_hour = 0;
		ctm.tm_mday = 0;
		ctm.tm_mon += 1;

		bb = mktime(&ctm);

		if (localtime_r((const time_t *)&bb, &ctm) == NULL) return ASL_STATUS_FAILED;
		asprintf(&tstring, "BB.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
	}
	else
	{
		asprintf(&tstring, "%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
	}

	if (tstring == NULL) return ASL_STATUS_NO_MEMORY;

	status = asl_store_file_open_write(s, tstring, ruid, rgid, bb, &f, now, check_cache);
	free(tstring);
	tstring = NULL;

	if (status != ASL_STATUS_OK) return status;

	status = asl_file_save(f, msg, &xid);
	if (status != ASL_STATUS_OK) return status;

	fsize = asl_file_size(f);
	ftime = asl_file_ctime(f);

	/* if file is larger than max_file_size, rename it and trigger aslmanager */
	if ((s->max_file_size != 0) && (fsize > s->max_file_size))
	{
		trigger_aslmanager = 1;
		status = ASL_STATUS_OK;

		path = asl_store_file_path(s, f);

		asl_store_file_close(s, f);

		if (path != NULL)
		{
			tmp_path = NULL;

			len = strlen(path);
			if ((len >= 4) && (!strcmp(path + len - 4, ".asl")))
			{
				/* rename xxxxxxx.asl to xxxxxxx.timestamp.asl */
				scratch = strdup(path);
				if (scratch != NULL)
				{
					scratch[len - 4] = '\0';
					asprintf(&tmp_path, "%s.%llu.asl", scratch, ftime);
					free(scratch);

				}
			}
			else
			{
				/* append timestamp */
				asprintf(&tmp_path, "%s.%llu", path, ftime);
			}

			if (tmp_path == NULL)
			{
				status = ASL_STATUS_NO_MEMORY;
			}
			else
			{
				if (rename(path, tmp_path) != 0) status = ASL_STATUS_FAILED;
				free(tmp_path);
			}

			free(path);
		}
	}

	if (trigger_aslmanager != 0) asl_trigger_aslmanager();

	return status;
}