|
|
@ -4498,7 +4498,7 @@ static const char *cause_str(enum event_cause cause) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// return EVENT_OK or timeout seconds
|
|
|
|
// return EVENT_OK or -timeout seconds
|
|
|
|
int check_events(EVENTS *events) |
|
|
|
int check_events(EVENTS *events) |
|
|
|
{ |
|
|
|
{ |
|
|
|
bool alert = false, user1, user2; |
|
|
|
bool alert = false, user1, user2; |
|
|
@ -4539,220 +4539,222 @@ int check_events(EVENTS *events) |
|
|
|
// Check hash - same hash passfail on more than one valid User
|
|
|
|
// Check hash - same hash passfail on more than one valid User
|
|
|
|
if (events->id == EVENTID_PASSFAIL && *(events->hash)) { |
|
|
|
if (events->id == EVENTID_PASSFAIL && *(events->hash)) { |
|
|
|
e_item = last_events_hash(events->id, events->hash, ctx); |
|
|
|
e_item = last_events_hash(events->id, events->hash, ctx); |
|
|
|
if (e_item) { |
|
|
|
DATA_EVENTS_NULL(e, e_item); |
|
|
|
DATA_EVENTS(e, e_item); |
|
|
|
user1 = false; |
|
|
|
user1 = false; |
|
|
|
|
|
|
|
while (e_item && e->id == events->id && |
|
|
|
|
|
|
|
strcmp(e->hash, events->hash) == 0 && |
|
|
|
|
|
|
|
CURRENT(&(e->expirydate))) { |
|
|
|
|
|
|
|
// rounded down seconds
|
|
|
|
|
|
|
|
secs = (int)tvdiff(&now, &(e->createdate)); |
|
|
|
|
|
|
|
// Is this event too old?
|
|
|
|
|
|
|
|
if (secs >= event_limits_hash_lifetime) { |
|
|
|
|
|
|
|
tmp_item = e_item; |
|
|
|
|
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
|
|
|
|
// Discard the old event - e is still tmp_item
|
|
|
|
|
|
|
|
remove_from_ktree(events_hash_root, tmp_item); |
|
|
|
|
|
|
|
if (--(e->trees) < 1) { |
|
|
|
|
|
|
|
// No longer in any of the event trees
|
|
|
|
|
|
|
|
k_unlink_item(events_store, tmp_item); |
|
|
|
|
|
|
|
k_add_head(events_free, tmp_item); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!alert) { |
|
|
|
|
|
|
|
if (!user1) { |
|
|
|
|
|
|
|
K_RLOCK(users_free); |
|
|
|
|
|
|
|
u_item = find_users(e->createby); |
|
|
|
|
|
|
|
K_RUNLOCK(users_free); |
|
|
|
|
|
|
|
if (u_item) { |
|
|
|
|
|
|
|
// Remember the username
|
|
|
|
|
|
|
|
STRNCPY(createby, e->createby); |
|
|
|
|
|
|
|
user1 = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// Don't check username case mistyping errors
|
|
|
|
|
|
|
|
if (strcasecmp(createby, e->createby) != 0) { |
|
|
|
|
|
|
|
K_RLOCK(users_free); |
|
|
|
|
|
|
|
u_item = find_users(e->createby); |
|
|
|
|
|
|
|
K_RUNLOCK(users_free); |
|
|
|
|
|
|
|
if (u_item) { |
|
|
|
|
|
|
|
alert = true; |
|
|
|
|
|
|
|
cause = CAUSE_HASH; |
|
|
|
|
|
|
|
tyme = 0; |
|
|
|
|
|
|
|
limit = 1; |
|
|
|
|
|
|
|
lifetime = event_limits_hash_lifetime; |
|
|
|
|
|
|
|
STRNCPY(name, "HASH"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Check User
|
|
|
|
|
|
|
|
e_item = last_events_user(events->id, events->createby, ctx); |
|
|
|
|
|
|
|
if (e_item) { |
|
|
|
|
|
|
|
DATA_EVENTS(e, e_item); |
|
|
|
|
|
|
|
count = 0; |
|
|
|
|
|
|
|
while (e_item && e->id == events->id && |
|
|
|
while (e_item && e->id == events->id && |
|
|
|
strcmp(e->createby, events->createby) == 0 && |
|
|
|
strcmp(e->hash, events->hash) == 0 && |
|
|
|
CURRENT(&(e->expirydate))) { |
|
|
|
CURRENT(&(e->expirydate))) { |
|
|
|
count++; |
|
|
|
|
|
|
|
// rounded down seconds
|
|
|
|
// rounded down seconds
|
|
|
|
secs = (int)tvdiff(&now, &(e->createdate)); |
|
|
|
secs = (int)tvdiff(&now, &(e->createdate)); |
|
|
|
// Is this event too old?
|
|
|
|
// Is this event too old?
|
|
|
|
if (secs >= e_limits[events->id].lifetime) { |
|
|
|
if (secs >= event_limits_hash_lifetime) { |
|
|
|
tmp_item = e_item; |
|
|
|
tmp_item = e_item; |
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
// Discard the old event - e is still tmp_item
|
|
|
|
// Discard the old event - e is still old
|
|
|
|
remove_from_ktree(events_user_root, tmp_item); |
|
|
|
remove_from_ktree(events_hash_root, tmp_item); |
|
|
|
if (--e->trees < 1) { |
|
|
|
if (--(e->trees) < 1) { |
|
|
|
// No longer in any of the event trees
|
|
|
|
// No longer in any of the event trees
|
|
|
|
k_unlink_item(events_store, tmp_item); |
|
|
|
k_unlink_item(events_store, tmp_item); |
|
|
|
k_add_head(events_free, tmp_item); |
|
|
|
k_add_head(events_free, tmp_item); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
DATA_EVENTS_NULL(e, e_item); |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
if (alert == false && |
|
|
|
if (!alert) { |
|
|
|
secs <= e_limits[events->id].user_low_time && |
|
|
|
if (!user1) { |
|
|
|
count > e_limits[events->id].user_low_time_limit) { |
|
|
|
K_RLOCK(users_free); |
|
|
|
alert = true; |
|
|
|
u_item = find_users(e->createby); |
|
|
|
cause = CAUSE_USER_LO; |
|
|
|
K_RUNLOCK(users_free); |
|
|
|
tyme = e_limits[events->id].user_low_time; |
|
|
|
if (u_item) { |
|
|
|
limit = e_limits[events->id].user_low_time_limit; |
|
|
|
// Remember the username
|
|
|
|
lifetime = e_limits[events->id].lifetime; |
|
|
|
STRNCPY(createby, e->createby); |
|
|
|
STRNCPY(name, e_limits[events->id].name); |
|
|
|
user1 = true; |
|
|
|
} |
|
|
|
} |
|
|
|
if (alert == false && |
|
|
|
} else { |
|
|
|
secs <= e_limits[events->id].user_hi_time && |
|
|
|
// Don't check username case mistyping errors
|
|
|
|
count > e_limits[events->id].user_hi_time_limit) { |
|
|
|
if (strcasecmp(createby, e->createby) != 0) { |
|
|
|
alert = true; |
|
|
|
K_RLOCK(users_free); |
|
|
|
cause = CAUSE_USER_HI; |
|
|
|
u_item = find_users(e->createby); |
|
|
|
tyme = e_limits[events->id].user_hi_time; |
|
|
|
K_RUNLOCK(users_free); |
|
|
|
limit = e_limits[events->id].user_hi_time_limit; |
|
|
|
if (u_item) { |
|
|
|
lifetime = e_limits[events->id].lifetime; |
|
|
|
alert = true; |
|
|
|
STRNCPY(name, e_limits[events->id].name); |
|
|
|
cause = CAUSE_HASH; |
|
|
|
|
|
|
|
tyme = 0; |
|
|
|
|
|
|
|
limit = 1; |
|
|
|
|
|
|
|
lifetime = event_limits_hash_lifetime; |
|
|
|
|
|
|
|
STRNCPY(name, "HASH"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
|
|
|
|
DATA_EVENTS_NULL(e, e_item); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Check User
|
|
|
|
|
|
|
|
e_item = last_events_user(events->id, events->createby, ctx); |
|
|
|
|
|
|
|
DATA_EVENTS_NULL(e, e_item); |
|
|
|
|
|
|
|
count = 0; |
|
|
|
|
|
|
|
while (e_item && e->id == events->id && |
|
|
|
|
|
|
|
strcmp(e->createby, events->createby) == 0 && |
|
|
|
|
|
|
|
CURRENT(&(e->expirydate))) { |
|
|
|
|
|
|
|
// rounded down seconds
|
|
|
|
|
|
|
|
secs = (int)tvdiff(&now, &(e->createdate)); |
|
|
|
|
|
|
|
// Is this event too old?
|
|
|
|
|
|
|
|
if (secs >= e_limits[events->id].lifetime) { |
|
|
|
|
|
|
|
tmp_item = e_item; |
|
|
|
|
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
|
|
|
|
// Discard the old event - e is still tmp_item
|
|
|
|
|
|
|
|
remove_from_ktree(events_user_root, tmp_item); |
|
|
|
|
|
|
|
if (--e->trees < 1) { |
|
|
|
|
|
|
|
// No longer in any of the event trees
|
|
|
|
|
|
|
|
k_unlink_item(events_store, tmp_item); |
|
|
|
|
|
|
|
k_add_head(events_free, tmp_item); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
DATA_EVENTS_NULL(e, e_item); |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
count++; |
|
|
|
|
|
|
|
if (alert == false && |
|
|
|
|
|
|
|
secs <= e_limits[events->id].user_low_time && |
|
|
|
|
|
|
|
count > e_limits[events->id].user_low_time_limit) { |
|
|
|
|
|
|
|
alert = true; |
|
|
|
|
|
|
|
cause = CAUSE_USER_LO; |
|
|
|
|
|
|
|
tyme = e_limits[events->id].user_low_time; |
|
|
|
|
|
|
|
limit = e_limits[events->id].user_low_time_limit; |
|
|
|
|
|
|
|
lifetime = e_limits[events->id].lifetime; |
|
|
|
|
|
|
|
STRNCPY(name, e_limits[events->id].name); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (alert == false && |
|
|
|
|
|
|
|
secs <= e_limits[events->id].user_hi_time && |
|
|
|
|
|
|
|
count > e_limits[events->id].user_hi_time_limit) { |
|
|
|
|
|
|
|
alert = true; |
|
|
|
|
|
|
|
cause = CAUSE_USER_HI; |
|
|
|
|
|
|
|
tyme = e_limits[events->id].user_hi_time; |
|
|
|
|
|
|
|
limit = e_limits[events->id].user_hi_time_limit; |
|
|
|
|
|
|
|
lifetime = e_limits[events->id].lifetime; |
|
|
|
|
|
|
|
STRNCPY(name, e_limits[events->id].name); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
|
|
|
|
DATA_EVENTS_NULL(e, e_item); |
|
|
|
} |
|
|
|
} |
|
|
|
// Check IP
|
|
|
|
// Check IP
|
|
|
|
e_item = last_events_ip(events->id, events->createinet, ctx); |
|
|
|
e_item = last_events_ip(events->id, events->createinet, ctx); |
|
|
|
if (e_item) { |
|
|
|
DATA_EVENTS_NULL(e, e_item); |
|
|
|
DATA_EVENTS(e, e_item); |
|
|
|
count = 0; |
|
|
|
count = 0; |
|
|
|
// Remember the first username
|
|
|
|
// Remember the first username
|
|
|
|
STRNCPY(createby, e->createby); |
|
|
|
STRNCPY(createby, e->createby); |
|
|
|
user2 = false; |
|
|
|
user2 = false; |
|
|
|
while (e_item && e->id == events->id && |
|
|
|
while (e_item && e->id == events->id && |
|
|
|
strcmp(e->createinet, events->createinet) == 0 && |
|
|
|
strcmp(e->createinet, events->createinet) == 0 && |
|
|
|
CURRENT(&(e->expirydate))) { |
|
|
|
CURRENT(&(e->expirydate))) { |
|
|
|
// rounded down seconds
|
|
|
|
count++; |
|
|
|
secs = (int)tvdiff(&now, &(e->createdate)); |
|
|
|
// rounded down seconds
|
|
|
|
// Is this event too old?
|
|
|
|
secs = (int)tvdiff(&now, &(e->createdate)); |
|
|
|
if (secs >= e_limits[events->id].lifetime) { |
|
|
|
// Is this event too old?
|
|
|
|
tmp_item = e_item; |
|
|
|
if (secs >= e_limits[events->id].lifetime) { |
|
|
|
|
|
|
|
tmp_item = e_item; |
|
|
|
|
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
|
|
|
|
// Discard the old event - e is still tmp_item
|
|
|
|
|
|
|
|
remove_from_ktree(events_ip_root, tmp_item); |
|
|
|
|
|
|
|
if (--e->trees < 1) { |
|
|
|
|
|
|
|
// No longer in any of the event trees
|
|
|
|
|
|
|
|
k_unlink_item(events_store, tmp_item); |
|
|
|
|
|
|
|
k_add_head(events_free, tmp_item); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Allow username case typing errors
|
|
|
|
|
|
|
|
if (strcasecmp(createby, e->createby) != 0) |
|
|
|
|
|
|
|
user2 = true; |
|
|
|
|
|
|
|
if (alert == false && |
|
|
|
|
|
|
|
secs <= e_limits[events->id].ip_low_time && |
|
|
|
|
|
|
|
count > e_limits[events->id].ip_low_time_limit) { |
|
|
|
|
|
|
|
alert = true; |
|
|
|
|
|
|
|
cause = CAUSE_IP_LO; |
|
|
|
|
|
|
|
tyme = e_limits[events->id].ip_low_time; |
|
|
|
|
|
|
|
limit = e_limits[events->id].ip_low_time_limit; |
|
|
|
|
|
|
|
lifetime = e_limits[events->id].lifetime; |
|
|
|
|
|
|
|
STRNCPY(name, e_limits[events->id].name); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (alert == false && |
|
|
|
|
|
|
|
secs <= e_limits[events->id].ip_hi_time && |
|
|
|
|
|
|
|
count > e_limits[events->id].ip_hi_time_limit) { |
|
|
|
|
|
|
|
alert = true; |
|
|
|
|
|
|
|
cause = CAUSE_IP_HI; |
|
|
|
|
|
|
|
tyme = e_limits[events->id].ip_hi_time; |
|
|
|
|
|
|
|
limit = e_limits[events->id].ip_hi_time_limit; |
|
|
|
|
|
|
|
lifetime = e_limits[events->id].lifetime; |
|
|
|
|
|
|
|
STRNCPY(name, e_limits[events->id].name); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
|
|
|
|
// Discard the old event - e is still tmp_item
|
|
|
|
|
|
|
|
remove_from_ktree(events_ip_root, tmp_item); |
|
|
|
|
|
|
|
if (--e->trees < 1) { |
|
|
|
|
|
|
|
// No longer in any of the event trees
|
|
|
|
|
|
|
|
k_unlink_item(events_store, tmp_item); |
|
|
|
|
|
|
|
k_add_head(events_free, tmp_item); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
DATA_EVENTS_NULL(e, e_item); |
|
|
|
|
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
/* If the ip alert was a single user then it's not an ip failure
|
|
|
|
count++; |
|
|
|
* since the User check already covers that */ |
|
|
|
// Allow username case typing errors
|
|
|
|
if (alert && (cause == CAUSE_IP_LO || cause == CAUSE_IP_HI) && |
|
|
|
if (strcasecmp(createby, e->createby) != 0) |
|
|
|
user2 == false) |
|
|
|
user2 = true; |
|
|
|
alert = false; |
|
|
|
if (alert == false && |
|
|
|
|
|
|
|
secs <= e_limits[events->id].ip_low_time && |
|
|
|
|
|
|
|
count > e_limits[events->id].ip_low_time_limit) { |
|
|
|
|
|
|
|
alert = true; |
|
|
|
|
|
|
|
cause = CAUSE_IP_LO; |
|
|
|
|
|
|
|
tyme = e_limits[events->id].ip_low_time; |
|
|
|
|
|
|
|
limit = e_limits[events->id].ip_low_time_limit; |
|
|
|
|
|
|
|
lifetime = e_limits[events->id].lifetime; |
|
|
|
|
|
|
|
STRNCPY(name, e_limits[events->id].name); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (alert == false && |
|
|
|
|
|
|
|
secs <= e_limits[events->id].ip_hi_time && |
|
|
|
|
|
|
|
count > e_limits[events->id].ip_hi_time_limit) { |
|
|
|
|
|
|
|
alert = true; |
|
|
|
|
|
|
|
cause = CAUSE_IP_HI; |
|
|
|
|
|
|
|
tyme = e_limits[events->id].ip_hi_time; |
|
|
|
|
|
|
|
limit = e_limits[events->id].ip_hi_time_limit; |
|
|
|
|
|
|
|
lifetime = e_limits[events->id].lifetime; |
|
|
|
|
|
|
|
STRNCPY(name, e_limits[events->id].name); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
|
|
|
|
DATA_EVENTS_NULL(e, e_item); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* If the ip alert was a single user then it's not an ip failure
|
|
|
|
|
|
|
|
* since the User check already covers that */ |
|
|
|
|
|
|
|
if (alert && (cause == CAUSE_IP_LO || cause == CAUSE_IP_HI) && |
|
|
|
|
|
|
|
user2 == false) |
|
|
|
|
|
|
|
alert = false; |
|
|
|
|
|
|
|
|
|
|
|
// Check IPC (Class C IP) use same rules as for IP
|
|
|
|
// Check IPC (Class C IP) use same rules as for IP
|
|
|
|
e_item = last_events_ipc(events->id, events->ipc, ctx); |
|
|
|
e_item = last_events_ipc(events->id, events->ipc, ctx); |
|
|
|
if (e_item) { |
|
|
|
DATA_EVENTS_NULL(e, e_item); |
|
|
|
DATA_EVENTS(e, e_item); |
|
|
|
count = 0; |
|
|
|
count = 0; |
|
|
|
// Remember the first username
|
|
|
|
// Remember the first username
|
|
|
|
STRNCPY(createby, e->createby); |
|
|
|
STRNCPY(createby, e->createby); |
|
|
|
user2 = false; |
|
|
|
user2 = false; |
|
|
|
while (e_item && e->id == events->id && |
|
|
|
while (e_item && e->id == events->id && |
|
|
|
strcmp(e->ipc, events->ipc) == 0 && |
|
|
|
strcmp(e->ipc, events->ipc) == 0 && |
|
|
|
CURRENT(&(e->expirydate))) { |
|
|
|
CURRENT(&(e->expirydate))) { |
|
|
|
// rounded down seconds
|
|
|
|
count++; |
|
|
|
secs = (int)tvdiff(&now, &(e->createdate)); |
|
|
|
// rounded down seconds
|
|
|
|
// Is this event too old?
|
|
|
|
secs = (int)tvdiff(&now, &(e->createdate)); |
|
|
|
if (secs >= e_limits[events->id].lifetime) { |
|
|
|
// Is this event too old?
|
|
|
|
tmp_item = e_item; |
|
|
|
if (secs >= e_limits[events->id].lifetime) { |
|
|
|
|
|
|
|
tmp_item = e_item; |
|
|
|
|
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
|
|
|
|
// Discard the old event - e is still tmp_item
|
|
|
|
|
|
|
|
remove_from_ktree(events_ipc_root, tmp_item); |
|
|
|
|
|
|
|
if (--e->trees < 1) { |
|
|
|
|
|
|
|
k_unlink_item(events_store, tmp_item); |
|
|
|
|
|
|
|
k_add_head(events_free, tmp_item); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Allow username case typing errors
|
|
|
|
|
|
|
|
if (strcasecmp(createby, e->createby) != 0) |
|
|
|
|
|
|
|
user2 = true; |
|
|
|
|
|
|
|
if (alert == false && |
|
|
|
|
|
|
|
secs <= e_limits[events->id].ip_low_time && |
|
|
|
|
|
|
|
count > e_limits[events->id].ip_low_time_limit) { |
|
|
|
|
|
|
|
alert = true; |
|
|
|
|
|
|
|
cause = CAUSE_IPC_LO; |
|
|
|
|
|
|
|
tyme = e_limits[events->id].ip_low_time; |
|
|
|
|
|
|
|
limit = e_limits[events->id].ip_low_time_limit; |
|
|
|
|
|
|
|
lifetime = e_limits[events->id].lifetime; |
|
|
|
|
|
|
|
STRNCPY(name, e_limits[events->id].name); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (alert == false && |
|
|
|
|
|
|
|
secs <= e_limits[events->id].ip_hi_time && |
|
|
|
|
|
|
|
count > e_limits[events->id].ip_hi_time_limit) { |
|
|
|
|
|
|
|
alert = true; |
|
|
|
|
|
|
|
cause = CAUSE_IPC_HI; |
|
|
|
|
|
|
|
tyme = e_limits[events->id].ip_hi_time; |
|
|
|
|
|
|
|
limit = e_limits[events->id].ip_hi_time_limit; |
|
|
|
|
|
|
|
lifetime = e_limits[events->id].lifetime; |
|
|
|
|
|
|
|
STRNCPY(name, e_limits[events->id].name); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
|
|
|
|
// Discard the old event - e is still tmp_item
|
|
|
|
|
|
|
|
remove_from_ktree(events_ipc_root, tmp_item); |
|
|
|
|
|
|
|
if (--e->trees < 1) { |
|
|
|
|
|
|
|
k_unlink_item(events_store, tmp_item); |
|
|
|
|
|
|
|
k_add_head(events_free, tmp_item); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
DATA_EVENTS_NULL(e, e_item); |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
count++; |
|
|
|
|
|
|
|
// Allow username case typing errors
|
|
|
|
|
|
|
|
if (strcasecmp(createby, e->createby) != 0) |
|
|
|
|
|
|
|
user2 = true; |
|
|
|
|
|
|
|
if (alert == false && |
|
|
|
|
|
|
|
secs <= e_limits[events->id].ip_low_time && |
|
|
|
|
|
|
|
count > e_limits[events->id].ip_low_time_limit) { |
|
|
|
|
|
|
|
alert = true; |
|
|
|
|
|
|
|
cause = CAUSE_IPC_LO; |
|
|
|
|
|
|
|
tyme = e_limits[events->id].ip_low_time; |
|
|
|
|
|
|
|
limit = e_limits[events->id].ip_low_time_limit; |
|
|
|
|
|
|
|
lifetime = e_limits[events->id].lifetime; |
|
|
|
|
|
|
|
STRNCPY(name, e_limits[events->id].name); |
|
|
|
} |
|
|
|
} |
|
|
|
/* If the ipc alert was a single user then it's not an ipc failure
|
|
|
|
if (alert == false && |
|
|
|
* since the User check already covers that */ |
|
|
|
secs <= e_limits[events->id].ip_hi_time && |
|
|
|
if (alert && (cause == CAUSE_IPC_LO || cause == CAUSE_IPC_HI) && |
|
|
|
count > e_limits[events->id].ip_hi_time_limit) { |
|
|
|
user2 == false) |
|
|
|
alert = true; |
|
|
|
alert = false; |
|
|
|
cause = CAUSE_IPC_HI; |
|
|
|
|
|
|
|
tyme = e_limits[events->id].ip_hi_time; |
|
|
|
|
|
|
|
limit = e_limits[events->id].ip_hi_time_limit; |
|
|
|
|
|
|
|
lifetime = e_limits[events->id].lifetime; |
|
|
|
|
|
|
|
STRNCPY(name, e_limits[events->id].name); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
e_item = prev_in_ktree(ctx); |
|
|
|
|
|
|
|
DATA_EVENTS_NULL(e, e_item); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* If the ipc alert was a single user then it's not an ipc failure
|
|
|
|
|
|
|
|
* since the User check already covers that */ |
|
|
|
|
|
|
|
if (alert && (cause == CAUSE_IPC_LO || cause == CAUSE_IPC_HI) && |
|
|
|
|
|
|
|
user2 == false) |
|
|
|
|
|
|
|
alert = false; |
|
|
|
|
|
|
|
|
|
|
|
K_RUNLOCK(event_limits_free); |
|
|
|
K_RUNLOCK(event_limits_free); |
|
|
|
K_WUNLOCK(events_free); |
|
|
|
K_WUNLOCK(events_free); |
|
|
|
if (alert) { |
|
|
|
if (alert) { |
|
|
@ -4786,15 +4788,17 @@ int check_events(EVENTS *events) |
|
|
|
exit(0); |
|
|
|
exit(0); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return lifetime; |
|
|
|
return -lifetime; |
|
|
|
} |
|
|
|
} |
|
|
|
return EVENT_OK; |
|
|
|
return EVENT_OK; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static char lurt[] = "alert="; |
|
|
|
static char lurt[] = "alert="; |
|
|
|
static size_t lurtsiz = sizeof(lurt); |
|
|
|
static size_t lurtsiz = sizeof(lurt); |
|
|
|
static char toomany[] = "Too many failures, come back later"; |
|
|
|
static char tmf[] = "Too many failures, come back later"; |
|
|
|
static size_t toomanysiz = sizeof(toomany); |
|
|
|
static size_t tmfsiz = sizeof(tmf); |
|
|
|
|
|
|
|
static char tma[] = "Too many accesses, come back later"; |
|
|
|
|
|
|
|
static size_t tmasiz = sizeof(tma); |
|
|
|
|
|
|
|
|
|
|
|
char *_reply_event(int event, char *buf, bool fre) |
|
|
|
char *_reply_event(int event, char *buf, bool fre) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -4814,16 +4818,299 @@ char *_reply_event(int event, char *buf, bool fre) |
|
|
|
|
|
|
|
|
|
|
|
len = strlen(buf); |
|
|
|
len = strlen(buf); |
|
|
|
len += 1 + lurtsiz; |
|
|
|
len += 1 + lurtsiz; |
|
|
|
len += toomanysiz + 1; |
|
|
|
if (event < 0) |
|
|
|
|
|
|
|
len += tmfsiz; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
len += tmasiz; |
|
|
|
reply = malloc(len); |
|
|
|
reply = malloc(len); |
|
|
|
if (!reply) |
|
|
|
if (!reply) |
|
|
|
quithere(1, "malloc (%d) OOM", (int)len); |
|
|
|
quithere(1, "malloc (%d) OOM", (int)len); |
|
|
|
snprintf(reply, len, "%s%c%s%s", buf, FLDSEP, lurt, toomany); |
|
|
|
snprintf(reply, len, "%s%c%s%s", buf, FLDSEP, lurt, |
|
|
|
|
|
|
|
event < 0 ? tmf : tma); |
|
|
|
if (fre) |
|
|
|
if (fre) |
|
|
|
free(buf); |
|
|
|
free(buf); |
|
|
|
return reply; |
|
|
|
return reply; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// order by key asc,hour asc,expirydate desc
|
|
|
|
|
|
|
|
cmp_t cmp_ovents(K_ITEM *a, K_ITEM *b) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
OVENTS *ea, *eb; |
|
|
|
|
|
|
|
DATA_OVENTS(ea, a); |
|
|
|
|
|
|
|
DATA_OVENTS(eb, b); |
|
|
|
|
|
|
|
cmp_t c = CMP_STR(ea->key, eb->key); |
|
|
|
|
|
|
|
if (c == 0) { |
|
|
|
|
|
|
|
c = CMP_INT(ea->hour, eb->hour); |
|
|
|
|
|
|
|
if (c == 0) { |
|
|
|
|
|
|
|
c = CMP_TV(eb->expirydate, ea->expirydate); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return c; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
K_ITEM *find_ovents(char *key, int hour, K_TREE_CTX *ctx) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
K_TREE_CTX ctx0[1]; |
|
|
|
|
|
|
|
OVENTS ovents; |
|
|
|
|
|
|
|
K_ITEM look; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ctx == NULL) |
|
|
|
|
|
|
|
ctx = ctx0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
STRNCPY(ovents.key, key); |
|
|
|
|
|
|
|
ovents.hour = hour; |
|
|
|
|
|
|
|
copy_tv(&(ovents.expirydate), &default_expiry); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
INIT_OVENTS(&look); |
|
|
|
|
|
|
|
look.data = (void *)(&ovents); |
|
|
|
|
|
|
|
return find_in_ktree(ovents_root, &look, ctx); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
K_ITEM *last_ovents(char *key, K_TREE_CTX *ctx) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
K_TREE_CTX ctx0[1]; |
|
|
|
|
|
|
|
OVENTS ovents; |
|
|
|
|
|
|
|
K_ITEM look; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ctx == NULL) |
|
|
|
|
|
|
|
ctx = ctx0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
STRNCPY(ovents.key, key); |
|
|
|
|
|
|
|
ovents.hour = SEC_TO_HOUR(DATE_S_EOT); |
|
|
|
|
|
|
|
copy_tv(&(ovents.expirydate), &default_expiry); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
INIT_OVENTS(&look); |
|
|
|
|
|
|
|
look.data = (void *)(&ovents); |
|
|
|
|
|
|
|
return find_before_in_ktree(ovents_root, &look, ctx); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum was_alert { |
|
|
|
|
|
|
|
ALERT_NO, |
|
|
|
|
|
|
|
ALERT_LO, |
|
|
|
|
|
|
|
ALERT_HI |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ovents must be W locked and event_limits R locked
|
|
|
|
|
|
|
|
static enum was_alert check_one_ovent(int id, char *key, tv_t *now, |
|
|
|
|
|
|
|
int low_time, int low_time_limit, |
|
|
|
|
|
|
|
int hi_time, int hi_time_limit) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
K_TREE_CTX ctx[1]; |
|
|
|
|
|
|
|
K_ITEM *o_item = NULL, *tmp_item; |
|
|
|
|
|
|
|
OVENTS *ovents = NULL; |
|
|
|
|
|
|
|
int low_count, hi_count, hour, min; |
|
|
|
|
|
|
|
enum was_alert ret = ALERT_NO; |
|
|
|
|
|
|
|
bool alert = false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
o_item = last_ovents(key, ctx); |
|
|
|
|
|
|
|
if (!o_item) |
|
|
|
|
|
|
|
return ret; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
low_count = hi_count = 0; |
|
|
|
|
|
|
|
hour = TV_TO_HOUR(now); |
|
|
|
|
|
|
|
DATA_OVENTS(ovents, o_item); |
|
|
|
|
|
|
|
while (o_item && strcmp(key, ovents->key) == 0 && |
|
|
|
|
|
|
|
CURRENT(&(ovents->expirydate))) { |
|
|
|
|
|
|
|
// Is this event too old?
|
|
|
|
|
|
|
|
if (((hour * 3600) - ((ovents->hour + 1) * 3600)) > |
|
|
|
|
|
|
|
o_limits_max_lifetime) { |
|
|
|
|
|
|
|
tmp_item = o_item; |
|
|
|
|
|
|
|
// Get the prev event
|
|
|
|
|
|
|
|
o_item = prev_in_ktree(ctx); |
|
|
|
|
|
|
|
DATA_OVENTS_NULL(ovents, o_item); |
|
|
|
|
|
|
|
// Discard the old event
|
|
|
|
|
|
|
|
remove_from_ktree(ovents_root, tmp_item); |
|
|
|
|
|
|
|
k_unlink_item(ovents_store, tmp_item); |
|
|
|
|
|
|
|
k_add_head(ovents_free, tmp_item); |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (alert == false) { |
|
|
|
|
|
|
|
min = hour * 3600 - low_time - ovents->hour * 3600; |
|
|
|
|
|
|
|
if (min < 0) |
|
|
|
|
|
|
|
min = 0; |
|
|
|
|
|
|
|
while (min < 60) { |
|
|
|
|
|
|
|
low_count += ovents->count[IDMIN(id, min)]; |
|
|
|
|
|
|
|
min++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (low_count > low_time_limit) { |
|
|
|
|
|
|
|
alert = true; |
|
|
|
|
|
|
|
ret = ALERT_LO; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (alert == false) { |
|
|
|
|
|
|
|
min = hour * 3600 - hi_time - ovents->hour * 3600; |
|
|
|
|
|
|
|
if (min < 0) |
|
|
|
|
|
|
|
min = 0; |
|
|
|
|
|
|
|
while (min < 60) { |
|
|
|
|
|
|
|
hi_count += ovents->count[IDMIN(id, min)]; |
|
|
|
|
|
|
|
min++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (hi_count > hi_time_limit) { |
|
|
|
|
|
|
|
alert = true; |
|
|
|
|
|
|
|
ret = ALERT_HI; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
o_item = prev_in_ktree(ctx); |
|
|
|
|
|
|
|
DATA_OVENTS_NULL(ovents, o_item); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return ret; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// return OVENT_OK or +timeout seconds
|
|
|
|
|
|
|
|
int check_ovents(int id, char *u_key, char *i_key, char *c_key, tv_t *now) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
K_ITEM *i_item; |
|
|
|
|
|
|
|
enum was_alert was; |
|
|
|
|
|
|
|
bool alert = false; |
|
|
|
|
|
|
|
char *st = NULL; |
|
|
|
|
|
|
|
enum event_cause cause = CAUSE_NONE; |
|
|
|
|
|
|
|
char cmd[MAX_ALERT_CMD+1]; |
|
|
|
|
|
|
|
int tyme, limit, lifetime; |
|
|
|
|
|
|
|
char name[TXT_SML+1]; |
|
|
|
|
|
|
|
pid_t pid; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
K_RLOCK(event_limits_free); |
|
|
|
|
|
|
|
if (ckdb_alert_cmd) |
|
|
|
|
|
|
|
STRNCPY(cmd, ckdb_alert_cmd); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
cmd[0] = '\0'; |
|
|
|
|
|
|
|
K_RUNLOCK(event_limits_free); |
|
|
|
|
|
|
|
// No way to send an alert, so don't test
|
|
|
|
|
|
|
|
if (!cmd[0]) |
|
|
|
|
|
|
|
return OVENT_OK; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (i_key[0]) { |
|
|
|
|
|
|
|
K_RLOCK(ips_free); |
|
|
|
|
|
|
|
i_item = find_ips(IPS_GROUP_OK, i_key); |
|
|
|
|
|
|
|
if (!i_item) |
|
|
|
|
|
|
|
i_item = find_ips(IPS_GROUP_OK, i_key); |
|
|
|
|
|
|
|
K_RUNLOCK(ips_free); |
|
|
|
|
|
|
|
if (i_item) |
|
|
|
|
|
|
|
return OVENT_OK; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
K_WLOCK(events_free); |
|
|
|
|
|
|
|
K_RLOCK(event_limits_free); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (u_key[0]) { |
|
|
|
|
|
|
|
was = check_one_ovent(id, u_key, now, |
|
|
|
|
|
|
|
o_limits[id].user_low_time, |
|
|
|
|
|
|
|
o_limits[id].user_low_time_limit, |
|
|
|
|
|
|
|
o_limits[id].user_hi_time, |
|
|
|
|
|
|
|
o_limits[id].user_hi_time_limit); |
|
|
|
|
|
|
|
if (was != ALERT_NO) { |
|
|
|
|
|
|
|
alert = true; |
|
|
|
|
|
|
|
if (was == ALERT_LO) { |
|
|
|
|
|
|
|
cause = CAUSE_USER_LO; |
|
|
|
|
|
|
|
tyme = o_limits[id].user_low_time; |
|
|
|
|
|
|
|
limit = o_limits[id].user_low_time_limit; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
cause = CAUSE_USER_HI; |
|
|
|
|
|
|
|
tyme = o_limits[id].user_hi_time; |
|
|
|
|
|
|
|
limit = o_limits[id].user_hi_time_limit; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
lifetime = o_limits[id].lifetime; |
|
|
|
|
|
|
|
STRNCPY(name, o_limits[id].name); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* If we already have the alert, the check_one_ovent()
|
|
|
|
|
|
|
|
* cleanup isn't needed since the first call cleans up all */ |
|
|
|
|
|
|
|
if (alert == false && i_key[0]) { |
|
|
|
|
|
|
|
was = check_one_ovent(id, i_key, now, |
|
|
|
|
|
|
|
o_limits[id].ip_low_time, |
|
|
|
|
|
|
|
o_limits[id].ip_low_time_limit, |
|
|
|
|
|
|
|
o_limits[id].ip_hi_time, |
|
|
|
|
|
|
|
o_limits[id].ip_hi_time_limit); |
|
|
|
|
|
|
|
if (was != ALERT_NO) { |
|
|
|
|
|
|
|
alert = true; |
|
|
|
|
|
|
|
if (was == ALERT_LO) { |
|
|
|
|
|
|
|
cause = CAUSE_IP_LO; |
|
|
|
|
|
|
|
tyme = o_limits[id].ip_low_time; |
|
|
|
|
|
|
|
limit = o_limits[id].ip_low_time_limit; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
cause = CAUSE_IP_HI; |
|
|
|
|
|
|
|
tyme = o_limits[id].ip_hi_time; |
|
|
|
|
|
|
|
limit = o_limits[id].ip_hi_time_limit; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
lifetime = o_limits[id].lifetime; |
|
|
|
|
|
|
|
STRNCPY(name, o_limits[id].name); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (alert == false && c_key[0]) { |
|
|
|
|
|
|
|
was = check_one_ovent(id, c_key, now, |
|
|
|
|
|
|
|
o_limits[id].ip_low_time, |
|
|
|
|
|
|
|
(int)(ovent_limits_ipc_factor * |
|
|
|
|
|
|
|
(double)(o_limits[id].ip_low_time_limit)), |
|
|
|
|
|
|
|
o_limits[id].ip_hi_time, |
|
|
|
|
|
|
|
(int)(ovent_limits_ipc_factor * |
|
|
|
|
|
|
|
(double)(o_limits[id].ip_hi_time_limit))); |
|
|
|
|
|
|
|
if (was != ALERT_NO) { |
|
|
|
|
|
|
|
alert = true; |
|
|
|
|
|
|
|
if (was == ALERT_LO) { |
|
|
|
|
|
|
|
cause = CAUSE_IPC_LO; |
|
|
|
|
|
|
|
tyme = o_limits[id].ip_low_time; |
|
|
|
|
|
|
|
limit = (int)(ovent_limits_ipc_factor * |
|
|
|
|
|
|
|
(double)(o_limits[id].ip_low_time_limit)); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
cause = CAUSE_IPC_HI; |
|
|
|
|
|
|
|
tyme = o_limits[id].ip_hi_time; |
|
|
|
|
|
|
|
limit = (int)(ovent_limits_ipc_factor * |
|
|
|
|
|
|
|
(double)(o_limits[id].ip_hi_time_limit)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
lifetime = o_limits[id].lifetime; |
|
|
|
|
|
|
|
STRNCPY(name, o_limits[id].name); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
K_RUNLOCK(event_limits_free); |
|
|
|
|
|
|
|
K_WUNLOCK(events_free); |
|
|
|
|
|
|
|
if (alert) { |
|
|
|
|
|
|
|
LOGERR("%s() OLERT ID:%d %s Lim:%d Time:%d Life:%d '%s/%s' " |
|
|
|
|
|
|
|
"'%s' '%s'", __func__, |
|
|
|
|
|
|
|
id, name, limit, tyme, lifetime, i_key, c_key, |
|
|
|
|
|
|
|
st = safe_text(u_key), cause_str(cause)); |
|
|
|
|
|
|
|
FREENULL(st); |
|
|
|
|
|
|
|
if (!i_key[0]) { |
|
|
|
|
|
|
|
LOGERR("%s() OLERT ID:%d '%s' can't ban, no IP", |
|
|
|
|
|
|
|
__func__, id, st = safe_text(u_key)); |
|
|
|
|
|
|
|
FREENULL(st); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
ips_add(IPS_GROUP_BAN, i_key, (char *)cause_str(cause), |
|
|
|
|
|
|
|
true, false, lifetime, false); |
|
|
|
|
|
|
|
pid = fork(); |
|
|
|
|
|
|
|
if (pid < 0) { |
|
|
|
|
|
|
|
LOGERR("%s() OLERT failed to fork (%d)", |
|
|
|
|
|
|
|
__func__, errno); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
if (pid == 0) { |
|
|
|
|
|
|
|
char buf1[16], buf2[16]; |
|
|
|
|
|
|
|
char buf3[16], buf4[16]; |
|
|
|
|
|
|
|
snprintf(buf1, sizeof(buf1), |
|
|
|
|
|
|
|
"%d", id); |
|
|
|
|
|
|
|
snprintf(buf2, sizeof(buf2), |
|
|
|
|
|
|
|
"%d", limit); |
|
|
|
|
|
|
|
snprintf(buf3, sizeof(buf3), |
|
|
|
|
|
|
|
"%d", tyme); |
|
|
|
|
|
|
|
snprintf(buf4, sizeof(buf4), |
|
|
|
|
|
|
|
"%d", lifetime); |
|
|
|
|
|
|
|
st = safe_text_nonull(u_key); |
|
|
|
|
|
|
|
execl(cmd, cmd, buf1, name, buf2, buf3, |
|
|
|
|
|
|
|
buf4, i_key, st, |
|
|
|
|
|
|
|
cause_str(cause), NULL); |
|
|
|
|
|
|
|
LOGERR("%s() OLERT fork failed to " |
|
|
|
|
|
|
|
"execute (%d)", |
|
|
|
|
|
|
|
__func__, errno); |
|
|
|
|
|
|
|
FREENULL(st); |
|
|
|
|
|
|
|
exit(0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return lifetime; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return OVENT_OK; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// order by userid asc,createdate asc,authid asc,expirydate desc
|
|
|
|
// order by userid asc,createdate asc,authid asc,expirydate desc
|
|
|
|
cmp_t cmp_auths(K_ITEM *a, K_ITEM *b) |
|
|
|
cmp_t cmp_auths(K_ITEM *a, K_ITEM *b) |
|
|
|
{ |
|
|
|
{ |
|
|
|