#include <sys/utsname.h>
#include <unistd.h>
#include <strings.h>
#include <libmlrpc/libmlrpc.h>
#include <smbsrv/libsmb.h>
#include <smbsrv/nmpipes.h>
#include <smbsrv/libmlsvc.h>
#include <smbsrv/ndl/eventlog.ndl>
#define LOGR_FWD +1
#define LOGR_REW -1
#define LOGR_RECORD_SIGNATURE 0x654C664C
#define LOGR_PRI(p) ((p) & LOG_PRIMASK)
#define LOGR_WNSTRLEN(S) ((strlen((S)) + 1) * sizeof (smb_wchar_t))
#define LOGR_MSG_DWORD_OFFSET 12
#define LOGR_MSG_WORD_OFFSET 4
#define EVENTLOG_SEQUENTIAL_READ 0x0001
#define EVENTLOG_SEEK_READ 0x0002
#define EVENTLOG_FORWARDS_READ 0x0004
#define EVENTLOG_BACKWARDS_READ 0x0008
#define EVENTLOG_SUCCESS 0x0000
#define EVENTLOG_ERROR_TYPE 0x0001
#define EVENTLOG_WARNING_TYPE 0x0002
#define EVENTLOG_INFORMATION_TYPE 0x0004
#define EVENTLOG_AUDIT_SUCCESS 0x0008
#define EVENTLOG_AUDIT_FAILURE 0x0010
#define EVENTID_SEVERITY_SUCCESS 0x00000000
#define EVENTID_SEVERITY_INFO 0x40000000
#define EVENTID_SEVERITY_WARNING 0x80000000
#define EVENTID_SEVERITY_ERROR 0xC0000000
#define EVENTID_SYSTEM_CODE 0x00000000
#define EVENTID_CUSTOMER_CODE 0x20000000
static int logr_s_EventLogClose(void *, ndr_xa_t *);
static int logr_s_EventLogQueryCount(void *, ndr_xa_t *);
static int logr_s_EventLogGetOldestRec(void *, ndr_xa_t *);
static int logr_s_EventLogOpen(void *, ndr_xa_t *);
static int logr_s_EventLogRead(void *, ndr_xa_t *);
static ndr_stub_table_t logr_stub_table[] = {
{ logr_s_EventLogClose, LOGR_OPNUM_EventLogClose },
{ logr_s_EventLogQueryCount, LOGR_OPNUM_EventLogQueryCount },
{ logr_s_EventLogGetOldestRec, LOGR_OPNUM_EventLogGetOldestRec },
{ logr_s_EventLogOpen, LOGR_OPNUM_EventLogOpen },
{ logr_s_EventLogRead, LOGR_OPNUM_EventLogRead },
{0}
};
static ndr_service_t logr_service = {
"LOGR",
"Event Log Service",
"\\eventlog",
PIPE_NTSVCS,
"82273fdc-e32a-18c3-3f78-827929dc23ea", 0,
NDR_TRANSFER_SYNTAX_UUID, 2,
0,
0,
0,
0,
&TYPEINFO(logr_interface),
logr_stub_table
};
void
logr_initialize(void)
{
(void) ndr_svc_register(&logr_service);
logr_init();
}
void
logr_finalize(void)
{
logr_fini();
}
static ndr_handle_t *
logr_hdlookup(ndr_xa_t *mxa, ndr_hdid_t *id)
{
ndr_handle_t *hd;
logr_context_t *ctx;
if ((hd = ndr_hdlookup(mxa, id)) == NULL)
return (NULL);
if ((ctx = (logr_context_t *)hd->nh_data) == NULL)
return (NULL);
if (ctx->lc_source_name == NULL)
return (NULL);
return (hd);
}
static void
logr_context_data_free(void *ctxp)
{
logr_context_t *ctx = (logr_context_t *)ctxp;
if (ctx == NULL)
return;
free(ctx->lc_source_name);
free(ctx->lc_cached_read_data->rd_log);
free(ctx->lc_cached_read_data);
free(ctx);
ctx = NULL;
}
static ndr_hdid_t *
logr_hdalloc(ndr_xa_t *mxa, char *logname)
{
logr_context_t *ctx;
if ((ctx = malloc(sizeof (logr_context_t))) == NULL)
return (NULL);
bzero(ctx, sizeof (logr_context_t));
ctx->lc_source_name = strdup(logname);
if (ctx->lc_source_name == NULL) {
free(ctx);
return (NULL);
}
if (logr_get_snapshot(ctx) != 0) {
free(ctx->lc_source_name);
free(ctx);
return (NULL);
}
return (ndr_hdalloc(mxa, ctx));
}
static int
logr_s_EventLogClose(void *arg, ndr_xa_t *mxa)
{
struct logr_EventLogClose *param = arg;
ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
ndr_handle_t *hd;
if ((hd = ndr_hdlookup(mxa, id)) == NULL) {
bzero(¶m->result_handle, sizeof (logr_handle_t));
param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
return (NDR_DRC_OK);
}
logr_context_data_free(hd->nh_data);
ndr_hdfree(mxa, id);
bzero(¶m->result_handle, sizeof (logr_handle_t));
param->status = NT_STATUS_SUCCESS;
return (NDR_DRC_OK);
}
static int
logr_s_EventLogOpen(void *arg, ndr_xa_t *mxa)
{
struct logr_EventLogOpen *param = arg;
ndr_hdid_t *id = NULL;
ndr_handle_t *hd;
char *log_name = NULL;
if (!ndr_is_admin(mxa)) {
bzero(¶m->handle, sizeof (logr_handle_t));
param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
return (NDR_DRC_OK);
}
if (param->log_name.length != 0)
log_name = (char *)param->log_name.str;
if (!logr_is_supported(log_name)) {
bzero(¶m->handle, sizeof (logr_handle_t));
param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
return (NDR_DRC_OK);
}
id = logr_hdalloc(mxa, log_name);
if (id && ((hd = logr_hdlookup(mxa, id)) != NULL)) {
hd->nh_data_free = logr_context_data_free;
bcopy(id, ¶m->handle, sizeof (logr_handle_t));
param->status = NT_STATUS_SUCCESS;
} else {
bzero(¶m->handle, sizeof (logr_handle_t));
param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
}
return (NDR_DRC_OK);
}
static int
logr_s_EventLogQueryCount(void *arg, ndr_xa_t *mxa)
{
struct logr_EventLogQueryCount *param = arg;
ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
ndr_handle_t *hd;
logr_context_t *ctx;
logr_read_data_t *data;
if ((hd = logr_hdlookup(mxa, id)) == NULL) {
param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
return (NDR_DRC_OK);
}
ctx = (logr_context_t *)hd->nh_data;
data = ctx->lc_cached_read_data;
param->rec_num = data->rd_tot_recnum;
param->status = NT_STATUS_SUCCESS;
return (NDR_DRC_OK);
}
static int
logr_s_EventLogGetOldestRec(void *arg, ndr_xa_t *mxa)
{
struct logr_EventLogGetOldestRec *param = arg;
ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
ndr_handle_t *hd;
logr_context_t *ctx;
logr_read_data_t *data;
if ((hd = logr_hdlookup(mxa, id)) == NULL) {
param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
return (NDR_DRC_OK);
}
ctx = (logr_context_t *)hd->nh_data;
data = ctx->lc_cached_read_data;
param->oldest_rec = data->rd_log->li_idx - data->rd_tot_recnum + 1;
param->status = NT_STATUS_SUCCESS;
return (NDR_DRC_OK);
}
void
logr_set_event_typeid(int le_pri, WORD *etype, DWORD *eid)
{
switch (LOGR_PRI(le_pri)) {
case LOG_EMERG:
case LOG_ALERT:
case LOG_CRIT:
case LOG_ERR:
*eid = EVENTID_SEVERITY_ERROR;
*etype = EVENTLOG_ERROR_TYPE;
break;
case LOG_WARNING:
*eid = EVENTID_SEVERITY_WARNING;
*etype = EVENTLOG_WARNING_TYPE;
break;
case LOG_NOTICE:
case LOG_INFO:
case LOG_DEBUG:
*eid = EVENTID_SEVERITY_INFO;
*etype = EVENTLOG_INFORMATION_TYPE;
break;
default:
*eid = EVENTID_SEVERITY_SUCCESS;
*etype = EVENTLOG_SUCCESS;
}
}
static logr_entry_t *
logr_get_entry(logr_info_t *linfo, int entno)
{
return (&linfo->li_entry[entno]);
}
static void
logr_set_logrecord(char *src_name, logr_entry_t *le,
DWORD recno, logr_record_t *rec)
{
int srcname_len = 0, hostname_len = 0, len;
int str_offs, sh_len;
smb_wchar_t wcs_hostname[MAXHOSTNAMELEN];
smb_wchar_t wcs_srcname[SYS_NMLN * 2];
(void) smb_mbstowcs(wcs_srcname, src_name,
strlen(src_name) + 1);
srcname_len = LOGR_WNSTRLEN(src_name);
(void) smb_mbstowcs(wcs_hostname, le->le_hostname,
strlen(le->le_hostname) + 1);
hostname_len = LOGR_WNSTRLEN(le->le_hostname);
sh_len = srcname_len + hostname_len;
str_offs = LOGR_MSG_DWORD_OFFSET * sizeof (DWORD) +
LOGR_MSG_WORD_OFFSET * sizeof (WORD) + sh_len;
rec->Length1 = sizeof (logr_record_t);
rec->Reserved = LOGR_RECORD_SIGNATURE;
rec->RecordNumber = recno;
rec->TimeGenerated = le->le_timestamp.tv_sec;
rec->TimeWritten = le->le_timestamp.tv_sec;
logr_set_event_typeid(le->le_pri, &rec->EventType, &rec->EventID);
rec->NumStrings = 1;
rec->EventCategory = 0;
rec->ReservedFlags = 0;
rec->ClosingRecordNumber = 0;
rec->StringOffset = str_offs;
rec->UserSidLength = 0;
rec->UserSidOffset = 0;
rec->DataLength = 0;
rec->DataOffset = 0;
bzero(rec->info, LOGR_MAXENTRYLEN);
(void) memcpy(rec->info, wcs_srcname, srcname_len);
(void) memcpy(rec->info + srcname_len, wcs_hostname, hostname_len);
len = strlen(le->le_msg) + 1;
if (len > 0)
(void) smb_mbstowcs((smb_wchar_t *)(rec->info + sh_len),
le->le_msg, len);
rec->Length2 = sizeof (logr_record_t);
}
static int
logr_s_EventLogRead(void *arg, ndr_xa_t *mxa)
{
struct logr_EventLogRead *param = arg;
ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
ndr_handle_t *hd;
logr_read_data_t *rdata;
logr_entry_t *le;
DWORD ent_no, ent_num, ent_remain;
logr_record_t *rec;
BYTE *buf;
int dir, ent_per_req, iter;
logr_context_t *ctx;
if ((hd = logr_hdlookup(mxa, id)) == NULL) {
param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
return (NDR_DRC_OK);
}
ctx = (logr_context_t *)hd->nh_data;
rdata = ctx->lc_cached_read_data;
if (rdata == NULL) {
param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
return (NDR_DRC_OK);
}
dir = (param->read_flags & EVENTLOG_FORWARDS_READ) ?
LOGR_FWD : LOGR_REW;
if (param->read_flags & EVENTLOG_SEEK_READ)
rdata->rd_last_sentrec = param->rec_offset;
else if (rdata->rd_first_read)
rdata->rd_last_sentrec = (dir == LOGR_FWD)
? (rdata->rd_log->li_idx - rdata->rd_tot_recnum)
: rdata->rd_log->li_idx;
ent_remain = (dir == LOGR_FWD)
? (rdata->rd_tot_recnum - rdata->rd_last_sentrec)
: rdata->rd_last_sentrec;
ent_per_req = param->nbytes_to_read / sizeof (logr_record_t);
if (ent_remain > ent_per_req)
ent_remain = ent_per_req;
if (ent_remain == 0) {
param->buf = NDR_STRDUP(mxa, "");
param->sent_size = 0;
param->status = NT_SC_ERROR(NT_STATUS_END_OF_FILE);
return (NDR_DRC_OK);
}
param->buf = NDR_MALLOC(mxa, param->nbytes_to_read);
buf = (BYTE *)param->buf;
for (ent_num = 0, ent_no = rdata->rd_last_sentrec;
ent_num < ent_remain; ent_num++, ent_no += dir) {
iter = ent_no & LOGR_NMSGMASK;
if (dir == LOGR_REW)
iter = (ent_no - 1) & LOGR_NMSGMASK;
le = logr_get_entry(rdata->rd_log, iter);
rec = (logr_record_t *)buf;
logr_set_logrecord(ctx->lc_source_name, le, ent_no, rec);
buf += sizeof (logr_record_t);
}
rdata->rd_last_sentrec = ent_no;
rdata->rd_first_read = 0;
param->sent_size = sizeof (logr_record_t) * ent_remain;
param->status = NT_STATUS_SUCCESS;
return (NDR_DRC_OK);
}