#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"
#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-_"
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;
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);
}
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;
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;
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;
}
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;
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;
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)
last_note = note;
}
}
+ if ((subdb = database_get_data(obj, KEY_AUTHLOG, RECDB_OBJECT)))
+ dict_foreach(subdb, nickserv_db_read_authlog, hi);
}
static int
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);
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)))
}
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);
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
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);