From 9432cb5959de161d2663875412d2306ba50a859d Mon Sep 17 00:00:00 2001 From: pk910 Date: Tue, 10 Jan 2012 15:56:05 +0100 Subject: [PATCH] added authlog --- src/nickserv.c | 276 ++++++++++++++++++++++++++++++++++++++++++++----- src/nickserv.h | 10 ++ 2 files changed, 261 insertions(+), 25 deletions(-) diff --git a/src/nickserv.c b/src/nickserv.c index e9aaad4..31ee22f 100644 --- a/src/nickserv.c +++ b/src/nickserv.c @@ -75,6 +75,7 @@ #define KEY_OUNREGISTER_INACTIVE "ounregister_inactive" #define KEY_OUNREGISTER_FLAGS "ounregister_flags" #define KEY_HANDLE_TS_MODE "account_timestamp_mode" +#define KEY_MAX_AUTHLOG_LEN "max_authlog_len" #define KEY_ID "id" #define KEY_PASSWD "passwd" @@ -111,6 +112,11 @@ #define KEY_NOTE_SETTER "setter" #define KEY_NOTE_NOTE "note" #define KEY_KARMA "karma" +#define KEY_AUTHLOG "authlog" +#define KEY_AUTHLOG_LOGIN_TIME "login_time" +#define KEY_AUTHLOG_LOGOUT_TIME "logout_time" +#define KEY_AUTHLOG_HOSTMASK "hostmask" +#define KEY_AUTHLOG_QUIT_REASON "quit_reason" #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" @@ -407,9 +413,18 @@ static struct { unsigned char hard_maxlogins; unsigned long ounregister_inactive; unsigned long ounregister_flags; + unsigned int max_authlog_len; } nickserv_conf; +struct pendingLOCUser { + char numeric[COMBO_NUMERIC_LEN+1]; + unsigned long time; + struct authlogEntry *authlog; + struct pendingLOCUser *next; +}; + const char *titlehost_suffix = NULL; +static struct pendingLOCUser *pendingLOCUsers = NULL; /* We have 2^32 unique account IDs to use. */ unsigned long int highest_id = 0; @@ -577,6 +592,26 @@ free_handle_info(void *vhi) if (!hil->used) dict_remove(nickserv_email_dict, hi->email_addr); } + struct authlogEntry *authlog, *next; + for(authlog = hi->authlog; authlog; authlog = next) { + next = authlog->next; + struct pendingLOCUser *pending, *prev_pending = NULL; + for(pending = pendingLOCUsers; pending; pending = pending->next) { + if(pending->authlog == authlog) { + if(prev_pending) + prev_pending->next = pending->next; + else + pendingLOCUsers = pending->next; + free(pending); + break; + } + prev_pending = pending; + } + free((char *) authlog->hostmask); + if(authlog->quit_reason) + free((char *) authlog->quit_reason); + free(authlog); + } free(hi); } @@ -1745,6 +1780,50 @@ reg_failpw_func(failpw_func_t func) failpw_func_list[failpw_func_used++] = func; } +static struct authlogEntry *authlog_add(struct handle_info *hi, struct userNode *user, const char *mask) { + if(!hi || (!user && !mask)) return NULL; + if(!mask) + mask = generate_hostmask(user, GENMASK_USENICK|GENMASK_STRICT_IDENT|GENMASK_NO_HIDING|GENMASK_STRICT_HOST); + struct authlogEntry *authlog, *next, *prev = NULL; + authlog = malloc(sizeof(*authlog)); + authlog->login_time = now; + authlog->logout_time = 0; + authlog->hostmask = mask; + authlog->quit_reason = NULL; + authlog->user = user; + authlog->next = hi->authlog; + hi->authlog = authlog; + unsigned int i = 0; + for(authlog = hi->authlog; authlog; authlog = next) { + i++; + next = authlog->next; + if(i > nickserv_conf.max_authlog_len) { + struct pendingLOCUser *pending, *prev_pending = NULL; + for(pending = pendingLOCUsers; pending; pending = pending->next) { + if(pending->authlog == authlog) { + if(prev_pending) + prev_pending->next = pending->next; + else + pendingLOCUsers = pending->next; + free(pending); + break; + } + prev_pending = pending; + } + free((char *) authlog->hostmask); + if(authlog->quit_reason) + free((char *) authlog->quit_reason); + if(prev) + prev->next = authlog->next; + else + hi->authlog = authlog->next; + free(authlog); + } else + prev = authlog; + } + return hi->authlog; +} + static NICKSERV_FUNC(cmd_auth) { int pw_arg, used, maxlogins; @@ -1862,6 +1941,7 @@ static NICKSERV_FUNC(cmd_auth) if (irc_in_addr_is_valid(user->ip) && irc_pton(&ip, NULL, user->hostname)) string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_BYIP|GENMASK_NO_HIDING|GENMASK_ANY_IDENT)); } + authlog_add(hi, user, NULL); argv[pw_arg] = "****"; reply("NSMSG_AUTH_SUCCESS"); return 1; @@ -1889,31 +1969,19 @@ struct handle_info *checklogin(const char *user, const char *pass, const char *n return NULL; if (HANDLE_FLAGGED(hi, SUSPENDED)) return NULL; - /** following in one of the next commits - struct last_login *login,*clogin,*old; - unsigned int ii = 0; - login = calloc(1, sizeof(*login)); - login->last_login = hi->last_login; - login->hostmask = strdup(hostmask); - login->authtime = now; - login->quittime = 0; - login->quit = NULL; - login->user = NULL; - login->loc_pending = strdup(numeric); - for (clogin = hi->last_login; clogin != NULL && ii < 9; clogin = clogin->last_login) { - if(ii == 8 && clogin->last_login) { - old = clogin->last_login; - clogin->last_login = NULL; - free(old->hostmask); - if(old->quit) - free(old->quit); - if(old->loc_pending) - free(old->loc_pending); - free(old); - } + char *ptr = malloc(strlen(hostmask)+1); + strcpy(ptr, hostmask); + struct authlogEntry *authlog = authlog_add(hi, NULL, ptr); + struct pendingLOCUser *pending; + if(authlog && (pending = malloc(sizeof(*pending)))) { + for(ii = 0; ii < COMBO_NUMERIC_LEN; ii++) + pending->numeric[ii] = numeric[ii]; + pending->numeric[COMBO_NUMERIC_LEN] = '\0'; + pending->time = now; + pending->authlog = authlog; + pending->next = pendingLOCUsers; + pendingLOCUsers = pending; } - hi->last_login = login; - */ return hi; } @@ -1944,6 +2012,69 @@ reg_allowauth_func(allowauth_func_t func) allowauth_func_list[allowauth_func_used++] = func; } +static MODCMD_FUNC(cmd_authlog) +{ + struct handle_info *hi = user->handle_info; + struct helpfile_table tbl; + struct authlogEntry *authlog; + int i = 0; + + for(authlog = hi->authlog; authlog; authlog = authlog->next) { + i++; + } + + tbl.length = i+1; + tbl.width = 4; + tbl.flags = 0; + tbl.flags = TABLE_NO_FREE; + tbl.contents = malloc(tbl.length * sizeof(tbl.contents[0])); + tbl.contents[0] = malloc(tbl.width * sizeof(tbl.contents[0][0])); + tbl.contents[0][0] = "Hostmask"; + tbl.contents[0][1] = "Login"; + tbl.contents[0][2] = "Logout"; + tbl.contents[0][3] = "Quit Reason"; + + if(!tbl.length) { + table_send(cmd->parent->bot, user->nick, 0, NULL, tbl); + reply("MSG_NONE"); + free(tbl.contents[0]); + free(tbl.contents); + return 0; + } + + char *str, *ptr; + char intervalBuf[INTERVALLEN]; + i = 0; + for(authlog = hi->authlog; authlog; authlog = authlog->next) { + tbl.contents[++i] = malloc(tbl.width * sizeof(tbl.contents[0][0])); + tbl.contents[i][0] = authlog->hostmask; + str = intervalString(intervalBuf, now - authlog->login_time, hi); + ptr = malloc(strlen(str)+1); + strcpy(ptr, str); + tbl.contents[i][1] = ptr; + if(authlog->logout_time) + str = intervalString(intervalBuf, now - authlog->logout_time, hi); + else + str = (authlog->user ? "Never" : "Unknown"); + ptr = malloc(strlen(str)+1); + strcpy(ptr, str); + tbl.contents[i][2] = ptr; + tbl.contents[i][3] = (authlog->quit_reason ? authlog->quit_reason : "-"); + } + + table_send(cmd->parent->bot, user->nick, 0, NULL, tbl); + for(i = 1; i < tbl.length; ++i) + { + free((char *) tbl.contents[i][1]); + free((char *) tbl.contents[i][2]); + free(tbl.contents[i]); + } + free(tbl.contents[0]); + free(tbl.contents); + + return 0; +} + static NICKSERV_FUNC(cmd_allowauth) { struct userNode *target; @@ -3329,6 +3460,21 @@ nickserv_saxdb_write(struct saxdb_context *ctx) { flags[0] = hi->userlist_style; flags[1] = 0; saxdb_write_string(ctx, KEY_USERLIST_STYLE, flags); + if(hi->authlog) { + saxdb_start_record(ctx, KEY_AUTHLOG, 0); + struct authlogEntry *authlog; + int i = 0; + for(authlog = hi->authlog; authlog; authlog = authlog->next) { + saxdb_start_record(ctx, strtab(++i), 0); + saxdb_write_int(ctx, KEY_AUTHLOG_LOGIN_TIME, authlog->login_time); + saxdb_write_int(ctx, KEY_AUTHLOG_LOGOUT_TIME, authlog->logout_time); + saxdb_write_string(ctx, KEY_AUTHLOG_HOSTMASK, authlog->hostmask); + if(authlog->quit_reason) + saxdb_write_string(ctx, KEY_AUTHLOG_QUIT_REASON, authlog->quit_reason); + saxdb_end_record(ctx); + } + saxdb_end_record(ctx); //END KEY_AUTHLOG + } saxdb_end_record(ctx); } return 0; @@ -4007,6 +4153,43 @@ static MODCMD_FUNC(cmd_checkemail) return 1; } +static int +nickserv_db_read_authlog(UNUSED_ARG(const char *key), void *data, void *extra) +{ + struct record_data *rd = data; + struct handle_info *hi = extra; + const char *str; + struct authlogEntry *authlog; + authlog = malloc(sizeof(*authlog)); + + str = database_get_data(rd->d.object, KEY_AUTHLOG_LOGIN_TIME, RECDB_QSTRING); + authlog->login_time = str ? strtoul(str, NULL, 0) : 0; + + str = database_get_data(rd->d.object, KEY_AUTHLOG_LOGOUT_TIME, RECDB_QSTRING); + authlog->logout_time = str ? strtoul(str, NULL, 0) : 0; + + str = database_get_data(rd->d.object, KEY_AUTHLOG_HOSTMASK, RECDB_QSTRING); + authlog->hostmask = str ? strdup(str) : NULL; + + str = database_get_data(rd->d.object, KEY_AUTHLOG_QUIT_REASON, RECDB_QSTRING); + authlog->quit_reason = str ? strdup(str) : NULL; + + authlog->next = NULL; + + //append it to the end of the list... + struct authlogEntry *authlog_entry; + if(!hi->authlog) { + hi->authlog = authlog; + } else { + for(authlog_entry = hi->authlog; authlog_entry; authlog_entry = authlog_entry->next) { + if(!authlog_entry->next) { + authlog_entry->next = authlog; + break; + } + } + } + return 0; +} static void nickserv_db_read_handle(const char *handle, dict_t obj) @@ -4188,6 +4371,8 @@ nickserv_db_read_handle(const char *handle, dict_t obj) last_note = note; } } + if ((subdb = database_get_data(obj, KEY_AUTHLOG, RECDB_OBJECT))) + dict_foreach(subdb, nickserv_db_read_authlog, hi); } static int @@ -4366,6 +4551,8 @@ nickserv_conf_read(void) nickserv_conf.default_maxlogins = str ? strtoul(str, NULL, 0) : 2; str = database_get_data(conf_node, "hard_maxlogins", RECDB_QSTRING); nickserv_conf.hard_maxlogins = str ? strtoul(str, NULL, 0) : 10; + str = database_get_data(conf_node, KEY_MAX_AUTHLOG_LEN, RECDB_QSTRING); + nickserv_conf.max_authlog_len = str ? strtoul(str, NULL, 0) : 30; str = database_get_data(conf_node, KEY_OUNREGISTER_INACTIVE, RECDB_QSTRING); nickserv_conf.ounregister_inactive = str ? ParseInterval(str) : 86400*28; str = database_get_data(conf_node, KEY_OUNREGISTER_FLAGS, RECDB_QSTRING); @@ -4492,6 +4679,26 @@ nickserv_reclaim_p(void *data) { static void check_user_nick(struct userNode *user) { + //check if this user is a pending LOC user + struct pendingLOCUser *pending, *next, *prev = NULL; + for(pending = pendingLOCUsers; pending; pending = next) { + next = pending->next; + if(!strcmp(user->numeric, pending->numeric)) { + pending->authlog->user = user; + if(prev) + prev->next = next; + else + pendingLOCUsers = next; + free(pending); + } + if(now - pending->time > 10) { + if(prev) + prev->next = next; + else + pendingLOCUsers = next; + free(pending); + } + } struct nick_info *ni; user->modes &= ~FLAGS_REGNICK; if (!(ni = get_nick_info(user->nick))) @@ -4552,8 +4759,20 @@ handle_nick_change(struct userNode *user, const char *old_nick) } void -nickserv_remove_user(struct userNode *user, UNUSED_ARG(struct userNode *killer), UNUSED_ARG(const char *why)) +nickserv_remove_user(struct userNode *user, UNUSED_ARG(struct userNode *killer), const char *why) { + if(user->handle_info) { + //check if theres an open authlog entry + struct authlogEntry *authlog; + for(authlog = user->handle_info->authlog; authlog; authlog = authlog->next) { + if(authlog->user == user) { + authlog->user = NULL; + authlog->logout_time = now; + authlog->quit_reason = strdup(why); + break; + } + } + } dict_remove(nickserv_allow_auth_dict, user->nick); timeq_del(0, nickserv_reclaim_p, user, TIMEQ_IGNORE_WHEN); set_user_handle_info(user, NULL, 0); @@ -4608,6 +4827,12 @@ nickserv_db_cleanup(void) regfree(&nickserv_conf.valid_handle_regex); if (nickserv_conf.valid_nick_regex_set) regfree(&nickserv_conf.valid_nick_regex); + struct pendingLOCUser *pending, *next; + for(pending = pendingLOCUsers; pending; pending = next) { + next = pending->next; + free(pending); + } + pendingLOCUsers = NULL; } void @@ -4680,6 +4905,7 @@ init_nickserv(const char *nick) nickserv_define_func("MERGEDB", cmd_mergedb, 999, 1, 0); nickserv_define_func("CHECKPASS", cmd_checkpass, 601, 1, 0); nickserv_define_func("CHECKEMAIL", cmd_checkemail, 0, 1, 0); + nickserv_define_func("AUTHLOG", cmd_authlog, 0, 1, 0); /* other options */ dict_insert(nickserv_opt_dict, "INFO", opt_info); dict_insert(nickserv_opt_dict, "WIDTH", opt_width); diff --git a/src/nickserv.h b/src/nickserv.h index 93579ff..ee0db3b 100644 --- a/src/nickserv.h +++ b/src/nickserv.h @@ -88,6 +88,15 @@ struct handle_note { char note[1]; }; +struct authlogEntry { + unsigned long login_time; + unsigned long logout_time; + const char *hostmask; + const char *quit_reason; + struct userNode *user; + struct authlogEntry *next; +}; + struct handle_info { struct nick_info *nicks; struct string_list *masks; @@ -96,6 +105,7 @@ struct handle_info { struct handle_cookie *cookie; struct handle_note *notes; struct language *language; + struct authlogEntry *authlog; char *website; char *devnull; char *email_addr; -- 2.20.1