#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <pthread.h>
#include <notify.h>
#include <asl_core.h>
#include "asl_memory.h"
#include "daemon.h"
#define forever for(;;)
#define MY_ID "remote"
#define MAXLINE 4096
#define LOCKDOWN_PATH "/var/run/lockdown"
#define SYSLOG_SOCK_PATH "/var/run/lockdown/syslog.sock"
#define ASL_REMOTE_PORT 203
#define PRINT_STD 0
#define PRINT_RAW 1
#define WATCH_OFF 0
#define WATCH_LOCKDOWN_START 1
#define WATCH_RUN 2
#define SESSION_FLAGS_LOCKDOWN 0x00000001
#define MAXSOCK 1
static int rfd4 = -1;
static int rfd6 = -1;
static int rfdl = -1;
#ifdef NSS32
typedef uint32_t notify_state_t;
extern int notify_set_state(int, notify_state_t);
#else
typedef uint64_t notify_state_t;
#endif
extern char *asl_list_to_string(asl_search_result_t *list, uint32_t *outlen);
extern size_t asl_memory_size(asl_memory_t *s);
extern uint32_t db_query(aslresponse query, aslresponse *res, uint64_t startid, int count, int flags, uint64_t *lastid, int32_t ruid, int32_t rgid);
#define SESSION_WRITE(f,x) if (write(f, x, strlen(x)) < 0) goto exit_session
typedef struct
{
int sock;
uint32_t flags;
} session_args_t;
uint32_t
remote_db_size(uint32_t sel)
{
if (sel == DB_TYPE_FILE) return global.db_file_max;
if (sel == DB_TYPE_MEMORY) return global.db_memory_max;
if (sel == DB_TYPE_MINI) return global.db_mini_max;
return 0;
}
uint32_t
remote_db_set_size(uint32_t sel, uint32_t size)
{
if (sel == DB_TYPE_FILE) global.db_file_max = size;
if (sel == DB_TYPE_MEMORY) global.db_memory_max = size;
if (sel == DB_TYPE_MINI) global.db_mini_max = size;
return 0;
}
aslmsg
remote_db_stats(uint32_t sel)
{
aslmsg m;
m = NULL;
if (sel == DB_TYPE_FILE) asl_store_statistics(global.file_db, &m);
if (sel == DB_TYPE_MEMORY) asl_memory_statistics(global.memory_db, &m);
if (sel == DB_TYPE_MINI) asl_mini_memory_statistics(global.mini_db, &m);
return m;
}
void
session(void *x)
{
int i, s, wfd, status, pfmt, watch, wtoken, nfd, do_prompt, filter;
aslresponse res;
asl_search_result_t ql;
uint32_t outlen;
aslmsg stats;
asl_msg_t *query;
asl_msg_t *qlq[1];
char str[1024], *p, *qs, *out;
ssize_t len;
fd_set readfds;
uint64_t low_id, high_id;
notify_state_t nstate;
uint32_t dbselect, flags;
session_args_t *sp;
if (x == NULL) pthread_exit(NULL);
sp = (session_args_t *)x;
s = sp->sock;
flags = sp->flags;
free(x);
watch = WATCH_OFF;
wfd = -1;
wtoken = -1;
dbselect = 0;
if (global.dbtype & DB_TYPE_MEMORY) dbselect = DB_TYPE_MEMORY;
else if (global.dbtype & DB_TYPE_MINI) dbselect = DB_TYPE_MINI;
else if (global.dbtype & DB_TYPE_FILE) dbselect = DB_TYPE_FILE;
low_id = 0;
high_id = 0;
pfmt = PRINT_STD;
query = NULL;
memset(&ql, 0, sizeof(asl_search_result_t));
snprintf(str, sizeof(str) - 1, "\n========================\nASL is here to serve you\n");
if (write(s, str, strlen(str)) < 0)
{
close(s);
pthread_exit(NULL);
return;
}
do_prompt = 1;
forever
{
if (do_prompt > 0)
{
snprintf(str, sizeof(str) - 1, "> ");
SESSION_WRITE(s, str);
}
do_prompt = 1;
memset(str, 0, sizeof(str));
FD_ZERO(&readfds);
FD_SET(s, &readfds);
nfd = s;
if (wfd != -1)
{
FD_SET(wfd, &readfds);
if (wfd > nfd) nfd = wfd;
}
status = select(nfd + 1, &readfds, NULL, NULL, NULL);
if ((wfd != -1) && (FD_ISSET(wfd, &readfds)))
{
len = read(wfd, &i, sizeof(int));
}
if (FD_ISSET(s, &readfds))
{
len = read(s, str, sizeof(str) - 1);
if (len <= 0) goto exit_session;
while ((len > 1) && ((str[len - 1] == '\n') || (str[len - 1] == '\r')))
{
str[len - 1] = '\0';
len--;
}
if ((!strcmp(str, "q")) || (!strcmp(str, "quit")) || (!strcmp(str, "exit")))
{
snprintf(str, sizeof(str) - 1, "Goodbye\n");
write(s, str, strlen(str));
close(s);
s = -1;
break;
}
if ((!strcmp(str, "?")) || (!strcmp(str, "help")))
{
snprintf(str, sizeof(str) - 1, "Commands\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " quit exit session\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " select [val] get [set] current database\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " val must be \"file\", \"mem\", or \"mini\"\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " file [on/off] enable / disable file store\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " memory [on/off] enable / disable memory store\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " mini [on/off] enable / disable mini memory store\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " stats database statistics\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " flush flush database\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " dbsize [val] get [set] database size (# of records)\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " filter [val] get [set] current database filter\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " [p]anic (emergency) [a]lert [c]ritical [e]rror\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " [w]arning [n]otice [i]nfo [d]ebug\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " watch print new messages as they arrive\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " stop stop watching for new messages\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " raw use raw format for printing messages\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " std use standard format for printing messages\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " * show all log messages\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " * key val equality search for messages (single key/value pair)\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " * op key val search for matching messages (single key/value pair)\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " * [op key val] ... search for matching messages (multiple key/value pairs)\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " operators: = < > ! (not equal) T (key exists) R (regex)\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " modifiers (must follow operator):\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, " C=casefold N=numeric S=substring A=prefix Z=suffix\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, "\n");
SESSION_WRITE(s, str);
continue;
}
else if (!strcmp(str, "stats"))
{
stats = remote_db_stats(dbselect);
out = asl_format_message((asl_msg_t *)stats, ASL_MSG_FMT_RAW, ASL_TIME_FMT_SEC, ASL_ENCODE_NONE, &outlen);
write(s, out, outlen);
free(out);
asl_free(stats);
continue;
}
else if (!strcmp(str, "flush"))
{}
else if (!strncmp(str, "select", 6))
{
p = str + 6;
while ((*p == ' ') || (*p == '\t')) p++;
if (*p == '\0')
{
if (dbselect == 0) snprintf(str, sizeof(str) - 1, "no store\n");
else if (dbselect == DB_TYPE_FILE) snprintf(str, sizeof(str) - 1, "file store\n");
else if (dbselect == DB_TYPE_MEMORY) snprintf(str, sizeof(str) - 1, "memory store\n");
else if (dbselect == DB_TYPE_MINI) snprintf(str, sizeof(str) - 1, "mini memory store\n");
SESSION_WRITE(s, str);
continue;
}
if (!strncmp(p, "file", 4))
{
if ((global.dbtype & DB_TYPE_FILE) == 0)
{
snprintf(str, sizeof(str) - 1, "file database is not enabled\n");
SESSION_WRITE(s, str);
continue;
}
dbselect = DB_TYPE_FILE;
}
else if (!strncmp(p, "mem", 3))
{
if ((global.dbtype & DB_TYPE_MEMORY) == 0)
{
snprintf(str, sizeof(str) - 1, "memory database is not enabled\n");
SESSION_WRITE(s, str);
continue;
}
dbselect = DB_TYPE_MEMORY;
}
else if (!strncmp(p, "mini", 4))
{
if ((global.dbtype & DB_TYPE_MINI) == 0)
{
if (global.mini_db != NULL)
{
snprintf(str, sizeof(str) - 1, "mini memory database is enabled for disaster messages\n");
SESSION_WRITE(s, str);
}
else
{
snprintf(str, sizeof(str) - 1, "mini memory database is not enabled\n");
SESSION_WRITE(s, str);
continue;
}
}
dbselect = DB_TYPE_MINI;
}
else
{
snprintf(str, sizeof(str) - 1, "unknown database type\n");
SESSION_WRITE(s, str);
continue;
}
snprintf(str, sizeof(str) - 1, "OK\n");
SESSION_WRITE(s, str);
continue;
}
else if (!strncmp(str, "file", 4))
{
p = str + 4;
while ((*p == ' ') || (*p == '\t')) p++;
if (*p == '\0')
{
snprintf(str, sizeof(str) - 1, "file database is %senabled\n", (global.dbtype & DB_TYPE_FILE) ? "" : "not ");
SESSION_WRITE(s, str);
if ((global.dbtype & DB_TYPE_FILE) != 0) dbselect = DB_TYPE_FILE;
continue;
}
if (!strcmp(p, "on")) global.dbtype |= DB_TYPE_FILE;
else if (!strcmp(p, "off")) global.dbtype &= ~ DB_TYPE_FILE;
snprintf(str, sizeof(str) - 1, "OK\n");
SESSION_WRITE(s, str);
continue;
}
else if (!strncmp(str, "memory", 6))
{
p = str + 6;
while ((*p == ' ') || (*p == '\t')) p++;
if (*p == '\0')
{
snprintf(str, sizeof(str) - 1, "memory database is %senabled\n", (global.dbtype & DB_TYPE_MEMORY) ? "" : "not ");
SESSION_WRITE(s, str);
if ((global.dbtype & DB_TYPE_MEMORY) != 0) dbselect = DB_TYPE_MEMORY;
continue;
}
if (!strcmp(p, "on")) global.dbtype |= DB_TYPE_MEMORY;
else if (!strcmp(p, "off")) global.dbtype &= ~ DB_TYPE_MEMORY;
snprintf(str, sizeof(str) - 1, "OK\n");
SESSION_WRITE(s, str);
continue;
}
else if (!strncmp(str, "mini", 4))
{
p = str + 4;
while ((*p == ' ') || (*p == '\t')) p++;
if (*p == '\0')
{
snprintf(str, sizeof(str) - 1, "mini database is %senabled\n", (global.dbtype & DB_TYPE_MINI) ? "" : "not ");
SESSION_WRITE(s, str);
if ((global.dbtype & DB_TYPE_MINI) != 0) dbselect = DB_TYPE_MINI;
continue;
}
if (!strcmp(p, "on")) global.dbtype |= DB_TYPE_MINI;
else if (!strcmp(p, "off")) global.dbtype &= ~ DB_TYPE_MINI;
snprintf(str, sizeof(str) - 1, "OK\n");
SESSION_WRITE(s, str);
continue;
}
else if (!strncmp(str, "dbsize", 6))
{
if (dbselect == 0)
{
snprintf(str, sizeof(str) - 1, "no store\n");
SESSION_WRITE(s, str);
continue;
}
p = str + 6;
while ((*p == ' ') || (*p == '\t')) p++;
if (*p == '\0')
{
snprintf(str, sizeof(str) - 1, "DB size %u\n", remote_db_size(dbselect));
SESSION_WRITE(s, str);
continue;
}
i = atoi(p);
remote_db_set_size(dbselect, i);
snprintf(str, sizeof(str) - 1, "OK\n");
SESSION_WRITE(s, str);
continue;
}
else if (!strncmp(str, "filter", 6))
{
p = str + 6;
while ((*p == ' ') || (*p == '\t')) p++;
if (*p == '\0')
{
snprintf(str, sizeof(str) - 1, "%s%s%s%s%s%s%s%s\n",
(global.asl_log_filter & ASL_FILTER_MASK_EMERG) ? "p" : "",
(global.asl_log_filter & ASL_FILTER_MASK_ALERT) ? "a" : "",
(global.asl_log_filter & ASL_FILTER_MASK_CRIT) ? "c" : "",
(global.asl_log_filter & ASL_FILTER_MASK_ERR) ? "e" : "",
(global.asl_log_filter & ASL_FILTER_MASK_WARNING) ? "w" : "",
(global.asl_log_filter & ASL_FILTER_MASK_NOTICE) ? "n" : "",
(global.asl_log_filter & ASL_FILTER_MASK_INFO) ? "i" : "",
(global.asl_log_filter & ASL_FILTER_MASK_DEBUG) ? "d" : "");
SESSION_WRITE(s, str);
continue;
}
filter = 0;
if ((*p >= '0') && (*p <= '7'))
{
i = atoi(p);
filter = ASL_FILTER_MASK_UPTO(i);
}
else
{
while (*p != '\0')
{
if ((*p == 'p') || (*p == 'P')) filter |= ASL_FILTER_MASK_EMERG;
else if ((*p == 'a') || (*p == 'A')) filter |= ASL_FILTER_MASK_ALERT;
else if ((*p == 'c') || (*p == 'C')) filter |= ASL_FILTER_MASK_CRIT;
else if ((*p == 'e') || (*p == 'E')) filter |= ASL_FILTER_MASK_ERR;
else if ((*p == 'w') || (*p == 'W')) filter |= ASL_FILTER_MASK_WARNING;
else if ((*p == 'n') || (*p == 'N')) filter |= ASL_FILTER_MASK_NOTICE;
else if ((*p == 'i') || (*p == 'I')) filter |= ASL_FILTER_MASK_INFO;
else if ((*p == 'd') || (*p == 'D')) filter |= ASL_FILTER_MASK_DEBUG;
p++;
}
}
status = notify_register_check(NOTIFY_SYSTEM_ASL_FILTER, &i);
if (status != NOTIFY_STATUS_OK)
{
snprintf(str, sizeof(str) - 1, "FAILED %d\n", status);
SESSION_WRITE(s, str);
}
else
{
nstate = filter;
status = notify_set_state(i, nstate);
if (status != NOTIFY_STATUS_OK)
{
snprintf(str, sizeof(str) - 1, "FAILED %d\n", status);
SESSION_WRITE(s, str);
continue;
}
status = notify_post(NOTIFY_SYSTEM_ASL_FILTER);
notify_cancel(i);
global.asl_log_filter = filter;
snprintf(str, sizeof(str) - 1, "OK\n");
SESSION_WRITE(s, str);
}
continue;
}
else if (!strcmp(str, "stop"))
{
if (watch != WATCH_OFF)
{
watch = WATCH_OFF;
notify_cancel(wtoken);
wfd = -1;
wtoken = -1;
low_id = 0;
high_id = 0;
if (query != NULL) free(query);
query = NULL;
snprintf(str, sizeof(str) - 1, "OK\n");
SESSION_WRITE(s, str);
continue;
}
snprintf(str, sizeof(str) - 1, "not watching!\n");
SESSION_WRITE(s, str);
continue;
}
else if (!strcmp(str, "raw"))
{
pfmt = PRINT_RAW;
continue;
}
else if (!strcmp(str, "std"))
{
pfmt = PRINT_STD;
continue;
}
else if (!strcmp(str, "watch"))
{
if (watch != WATCH_OFF)
{
snprintf(str, sizeof(str) - 1, "already watching!\n");
SESSION_WRITE(s, str);
continue;
}
if (flags & SESSION_FLAGS_LOCKDOWN)
{
watch = WATCH_LOCKDOWN_START;
}
else
{
status = notify_register_file_descriptor(ASL_DB_NOTIFICATION, &wfd, 0, &wtoken);
if (status != 0)
{
snprintf(str, sizeof(str) - 1, "notify_register_file_descriptor failed: %d\n", status);
SESSION_WRITE(s, str);
continue;
}
watch = WATCH_RUN;
}
snprintf(str, sizeof(str) - 1, "OK\n");
SESSION_WRITE(s, str);
do_prompt = 2;
}
else if ((str[0] == '*') || (str[0] == 'T') || (str[0] == '=') || (str[0] == '!') || (str[0] == '<') || (str[0] == '>'))
{
memset(&ql, 0, sizeof(asl_search_result_t));
if (query != NULL) free(query);
query = NULL;
p = str;
if (*p == '*') p++;
while ((*p == ' ') || (*p == '\t')) p++;
if (*p == '\0')
{
}
else if (*p == '[')
{
qs = NULL;
asprintf(&qs, "Q %s", p);
query = asl_msg_from_string(qs);
free(qs);
}
else if ((*p == 'T') || (*p == '=') || (*p == '!') || (*p == '<') || (*p == '>') || (*p == 'R'))
{
qs = NULL;
asprintf(&qs, "Q [%s]", p);
query = asl_msg_from_string(qs);
free(qs);
}
else
{
qs = NULL;
asprintf(&qs, "Q [= %s]", p);
query = asl_msg_from_string(qs);
free(qs);
}
}
else
{
snprintf(str, sizeof(str) - 1, "unrecognized command\n");
SESSION_WRITE(s, str);
snprintf(str, sizeof(str) - 1, "enter \"help\" for help\n");
SESSION_WRITE(s, str);
continue;
}
}
if ((flags & SESSION_FLAGS_LOCKDOWN) && (watch == WATCH_RUN)) continue;
if (watch == WATCH_LOCKDOWN_START)
{
pthread_mutex_lock(global.work_queue_lock);
}
if (query != NULL)
{
ql.count = 1;
qlq[0] = query;
ql.msg = qlq;
}
if (watch == WATCH_OFF) low_id = 0;
memset(&res, 0, sizeof(aslresponse));
high_id = 0;
status = db_query(&ql, (aslresponse *)&res, low_id, 0, 0, &high_id, 0, 0);
if ((watch == WATCH_RUN) && (high_id >= low_id)) low_id = high_id + 1;
if (res == NULL)
{
if (watch == WATCH_OFF)
{
snprintf(str, sizeof(str) - 1, "-nil-\n");
SESSION_WRITE(s, str);
}
else
{
if (do_prompt != 2) do_prompt = 0;
}
}
else if (pfmt == PRINT_RAW)
{
if (watch == WATCH_RUN)
{
snprintf(str, sizeof(str) - 1, "\n");
SESSION_WRITE(s, str);
}
outlen = 0;
out = asl_list_to_string((asl_search_result_t *)res, &outlen);
write(s, out, outlen);
free(out);
snprintf(str, sizeof(str) - 1, "\n");
SESSION_WRITE(s, str);
}
else
{
if (watch == WATCH_RUN)
{
snprintf(str, sizeof(str) - 1, "\n");
SESSION_WRITE(s, str);
}
for (i = 0; i < res->count; i++)
{
out = asl_format_message(res->msg[i], ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE, &outlen);
write(s, out, outlen);
free(out);
}
}
aslresponse_free(res);
if (watch == WATCH_LOCKDOWN_START)
{
global.lockdown_session_fd = s;
global.watchers_active++;
watch = WATCH_RUN;
pthread_mutex_unlock(global.work_queue_lock);
}
}
exit_session:
if (s >= 0)
{
if (s == global.lockdown_session_fd) global.lockdown_session_fd = -1;
if (global.watchers_active > 0) global.watchers_active--;
close(s);
s = -1;
}
if (watch != WATCH_OFF) notify_cancel(wtoken);
if (query != NULL) asl_msg_release(query);
pthread_exit(NULL);
}
aslmsg
remote_acceptmsg(int fd, int tcp)
{
socklen_t fromlen;
int s, status, flags, v;
pthread_attr_t attr;
pthread_t t;
struct sockaddr_storage from;
session_args_t *sp;
fromlen = sizeof(struct sockaddr_un);
if (tcp == 1) fromlen = sizeof(struct sockaddr_storage);
memset(&from, 0, sizeof(from));
s = accept(fd, (struct sockaddr *)&from, &fromlen);
if (s == -1)
{
asldebug("%s: accept: %s\n", MY_ID, strerror(errno));
return NULL;
}
flags = fcntl(s, F_GETFL, 0);
flags &= ~ O_NONBLOCK;
status = fcntl(s, F_SETFL, flags);
if (status < 0)
{
asldebug("%s: fcntl: %s\n", MY_ID, strerror(errno));
close(s);
return NULL;
}
v = 1;
setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &v, sizeof(v));
if (tcp == 1)
{
flags = 1;
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(int));
}
sp = (session_args_t *)calloc(1, sizeof(session_args_t));
if (sp == NULL)
{
asldebug("%s: malloc: %s\n", MY_ID, strerror(errno));
close(s);
return NULL;
}
sp->sock = s;
if ((tcp == 0) && (global.lockdown_session_fd < 0))
{
sp->flags |= SESSION_FLAGS_LOCKDOWN;
}
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&t, &attr, (void *(*)(void *))session, (void *)sp);
pthread_attr_destroy(&attr);
return NULL;
}
aslmsg
remote_acceptmsg_local(int fd)
{
return remote_acceptmsg(fd, 0);
}
aslmsg
remote_acceptmsg_tcp(int fd)
{
return remote_acceptmsg(fd, 1);
}
int
remote_init_lockdown(void)
{
int status, reuse, fd;
struct sockaddr_un local;
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0)
{
asldebug("%s: socket: %s\n", MY_ID, strerror(errno));
return -1;
}
reuse = 1;
status = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(int));
if (status < 0)
{
asldebug("%s: setsockopt: %s\n", MY_ID, strerror(errno));
close(fd);
return -1;
}
mkdir(LOCKDOWN_PATH, 0777);
memset(&local, 0, sizeof(local));
local.sun_family = AF_UNIX;
strlcpy(local.sun_path, SYSLOG_SOCK_PATH, sizeof(local.sun_path));
unlink(local.sun_path);
status = bind(fd, (struct sockaddr *)&local, sizeof(local.sun_family) + sizeof(local.sun_path));
if (status < 0)
{
asldebug("%s: bind: %s\n", MY_ID, strerror(errno));
close(fd);
return -1;
}
status = fcntl(fd, F_SETFL, O_NONBLOCK);
if (status < 0)
{
asldebug("%s: fcntl: %s\n", MY_ID, strerror(errno));
close(fd);
return -1;
}
status = listen(fd, 5);
if (status < 0)
{
asldebug("%s: listen: %s\n", MY_ID, strerror(errno));
close(fd);
return -1;
}
chmod(SYSLOG_SOCK_PATH, 0666);
aslevent_addfd(SOURCE_SESSION, fd, 0, remote_acceptmsg_local, NULL, NULL);
return fd;
}
int
remote_init_tcp(int family)
{
int status, reuse, fd;
struct sockaddr_in a4;
struct sockaddr_in6 a6;
struct sockaddr *s;
socklen_t len;
fd = socket(family, SOCK_STREAM, 0);
if (fd < 0)
{
asldebug("%s: socket: %s\n", MY_ID, strerror(errno));
return -1;
}
reuse = 1;
status = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(int));
if (status < 0)
{
asldebug("%s: setsockopt: %s\n", MY_ID, strerror(errno));
close(fd);
return -1;
}
memset(&(a4.sin_addr), 0, sizeof(struct in_addr));
a4.sin_family = AF_INET;
a4.sin_port = htons(ASL_REMOTE_PORT);
memset(&(a6.sin6_addr), 0, sizeof(struct in6_addr));
a6.sin6_family = AF_INET6;
a6.sin6_port = htons(ASL_REMOTE_PORT);
s = (struct sockaddr *)&a4;
len = sizeof(struct sockaddr_in);
if (family == AF_INET6)
{
s = (struct sockaddr *)&a6;
len = sizeof(struct sockaddr_in6);
}
status = bind(fd, s, len);
if (status < 0)
{
asldebug("%s: bind: %s\n", MY_ID, strerror(errno));
close(fd);
return -1;
}
status = fcntl(fd, F_SETFL, O_NONBLOCK);
if (status < 0)
{
asldebug("%s: fcntl: %s\n", MY_ID, strerror(errno));
close(fd);
return -1;
}
status = listen(fd, 5);
if (status < 0)
{
asldebug("%s: listen: %s\n", MY_ID, strerror(errno));
close(fd);
return -1;
}
aslevent_addfd(SOURCE_SESSION, fd, 0, remote_acceptmsg_tcp, NULL, NULL);
return fd;
}
int
remote_init(void)
{
asldebug("%s: init\n", MY_ID);
#ifdef LOCKDOWN
rfdl = remote_init_lockdown();
#endif
#ifdef REMOTE_IPV4
rfd4 = remote_init_tcp(AF_INET);
#endif
#ifdef REMOTE_IPV6
rfd6 = remote_init_tcp(AF_INET6);
#endif
return 0;
}
int
remote_close(void)
{
if (rfdl >= 0)
{
aslevent_removefd(rfdl);
close(rfdl);
}
rfdl = -1;
if (rfd4 >= 0)
{
aslevent_removefd(rfd4);
close(rfd4);
}
rfd4 = -1;
if (rfd6 >= 0)
{
aslevent_removefd(rfd6);
close(rfd6);
}
rfd6 = -1;
return 0;
}
int
remote_reset(void)
{
remote_close();
return remote_init();
}