#include "sendmail.h"
#include "timeq.h"
-#include <regex.h>
+#include <tre/regex.h>
#define NICKSERV_CONF_NAME "services/nickserv"
#define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
#define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
#define KEY_VALID_NICK_REGEX "valid_nick_regex"
+#define KEY_VALID_FAKEHOST_REGEX "valid_fakehost_regex"
#define KEY_DB_BACKUP_FREQ "db_backup_freq"
#define KEY_MODOPER_LEVEL "modoper_level"
#define KEY_SET_EPITHET_LEVEL "set_epithet_level"
{ "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
{ "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
{ "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
- { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
+ { "NSMSG_TITLE_INVALID", "Titles may contain only a-z, A-Z, 0-9, and '-'. Please choose another." },
{ "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
{ "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
{ "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
{ "NSMSG_DENIED_FAKEHOST_WORD", "Access denied because there's a prohibited word in $b%s$b (%s)." },
{ "NSMSG_NOT_VALID_FAKEHOST_LEN", "$b%s$b is not a valid vhost. (can only be 63 characters)" },
{ "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", "$b%s$b is not a valid vhost. (TLD can only be 4 characters and less)" },
+ { "NSMSG_NOT_VALID_FAKEHOST_REGEX", "$b%s$b is not allowed by the admin, consult the valid vhost regex pattern in the config file under nickserv/valid_fakehost_regex." },
{ "CHECKPASS_YES", "Yes." },
{ "CHECKPASS_NO", "No." },
+ { "NSMSG_DEFCON_NO_NEW_NICKS", "You cannot register new %s at this time, please try again soon" },
{ NULL, NULL }
};
unsigned int disable_nicks : 1;
unsigned int valid_handle_regex_set : 1;
unsigned int valid_nick_regex_set : 1;
+ unsigned int valid_fakehost_regex_set : 1;
unsigned int autogag_enabled : 1;
unsigned int email_enabled : 1;
unsigned int email_required : 1;
const char *titlehost_suffix;
regex_t valid_handle_regex;
regex_t valid_nick_regex;
+ regex_t valid_fakehost_regex;
dict_t weak_password_dict;
struct policer_params *auth_policer_params;
enum reclaim_action reclaim_action;
{
struct handle_info *hi;
-#ifdef WITH_PROTOCOL_BAHAMUT
- char id_base64[IDLEN + 1];
- do
- {
- /* Assign a unique account ID to the account; note that 0 is
- an invalid account ID. 1 is therefore the first account ID. */
- if (!id) {
- id = 1 + highest_id++;
- } else {
- /* Note: highest_id is and must always be the highest ID. */
- if(id > highest_id) {
- highest_id = id;
- }
- }
- inttobase64(id_base64, id, IDLEN);
-
- /* Make sure an account with the same ID doesn't exist. If a
- duplicate is found, log some details and assign a new one.
- This should be impossible, but it never hurts to expect it. */
- if ((hi = dict_find(nickserv_id_dict, id_base64, NULL))) {
- log_module(NS_LOG, LOG_WARNING, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id, id_base64, hi->handle, handle);
- id = 0;
- }
- } while(!id);
-#endif
-
hi = calloc(1, sizeof(*hi));
hi->userlist_style = HI_DEFAULT_STYLE;
hi->announcements = '?';
hi->infoline = NULL;
dict_insert(nickserv_handle_dict, hi->handle, hi);
-#ifdef WITH_PROTOCOL_BAHAMUT
- hi->id = id;
- dict_insert(nickserv_id_dict, strdup(id_base64), hi);
-#endif
-
return hi;
}
{
struct handle_info *hi = vhi;
-#ifdef WITH_PROTOCOL_BAHAMUT
- char id[IDLEN + 1];
-
- inttobase64(id, hi->id, IDLEN);
- dict_remove(nickserv_id_dict, id);
-#endif
-
free_string_list(hi->masks);
free_string_list(hi->ignores);
assert(!hi->users);
static char *
generate_fakehost(struct handle_info *handle)
{
+ struct userNode *target;
extern const char *hidden_host_suffix;
static char buffer[HOSTLEN+1];
+ char *data;
+ int style = 1;
if (!handle->fakehost) {
- snprintf(buffer, sizeof(buffer), "%s.%s", handle->handle, hidden_host_suffix);
+ data = conf_get_data("server/hidden_host_type", RECDB_QSTRING);
+ if (data)
+ style = atoi(data);
+
+ if (style == 1)
+ snprintf(buffer, sizeof(buffer), "%s.%s", handle->handle, hidden_host_suffix);
+ else if (style == 2) {
+ /* Due to the way fakehost is coded theres no way i can
+ get the exact user, so for now ill just take the first
+ authed user. */
+ for (target = handle->users; target; target = target->next_authed)
+ break;
+
+ snprintf(buffer, sizeof(buffer), "%s", target->crypthost);
+ }
return buffer;
} else if (handle->fakehost[0] == '.') {
/* A leading dot indicates the stored value is actually a title. */
apply_fakehost(hi);
if (stamp) {
-#ifdef WITH_PROTOCOL_BAHAMUT
- /* Stamp users with their account ID. */
- char id[IDLEN + 1];
- inttobase64(id, hi->id, IDLEN);
-#elif WITH_PROTOCOL_P10
+#ifdef WITH_PROTOCOL_P10
/* Stamp users with their account name. */
char *id = hi->handle;
#else
char syncpass[MD5_CRYPT_LENGTH];
int no_auth, weblink;
+ if (checkDefCon(DEFCON_NO_NEW_NICKS) && !IsOper(user)) {
+ reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf.disable_nicks ? "accounts" : "nicknames");
+ return 0;
+ }
+
if (!IsOper(user) && !dict_size(nickserv_handle_dict)) {
/* Require the first handle registered to belong to someone +o. */
reply("NSMSG_REQUIRE_OPER");
nsmsg_none = handle_find_message(hi, "MSG_NONE");
reply("NSMSG_HANDLEINFO_ON", hi->handle);
reply("MSG_BAR");
-#ifdef WITH_PROTOCOL_BAHAMUT
- reply("NSMSG_HANDLEINFO_ID", hi->id);
-#endif
reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi->registered));
if (!hi->users) {
{
struct handle_info *hi;
struct userNode *uNode;
- char msgbuf[MAXLEN], *old_handle;
+ char *old_handle;
unsigned int nn;
NICKSERV_MIN_PARMS(3);
dict_insert(nickserv_handle_dict, hi->handle, hi);
for (nn=0; nn<rf_list_used; nn++)
rf_list[nn](hi, old_handle);
- snprintf(msgbuf, sizeof(msgbuf), "%s renamed account %s to %s.", user->handle_info->handle, old_handle, hi->handle);
-
if (nickserv_conf.sync_log) {
for (uNode = hi->users; uNode; uNode = uNode->next_authed)
}
reply("NSMSG_HANDLE_CHANGED", old_handle, hi->handle);
- global_message(MESSAGE_RECIPIENT_STAFF, msgbuf);
+ global_message_args(MESSAGE_RECIPIENT_OPERS, "NSMSG_ACCOUNT_RENAMED",
+ user->handle_info->handle, old_handle, hi->handle);
+
free(old_handle);
return 1;
}
return 0;
}
+ switch (hi->cookie->type) {
+ case ACTIVATION:
+ safestrncpy(hi->passwd, hi->cookie->data, sizeof(hi->passwd));
+ if (nickserv_conf.sync_log)
+ SyncLog("ACCOUNTACC %s", hi->handle);
+ break;
+ case PASSWORD_CHANGE:
+ safestrncpy(hi->passwd, hi->cookie->data, sizeof(hi->passwd));
+ if (nickserv_conf.sync_log)
+ SyncLog("PASSCHANGE %s %s", hi->handle, hi->passwd);
+ break;
+ case EMAIL_CHANGE:
+ if (!hi->email_addr && nickserv_conf.sync_log) {
+ if (nickserv_conf.sync_log)
+ SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, hi->cookie->data, user->info);
+ }
+ nickserv_set_email_addr(hi, hi->cookie->data);
+ if (nickserv_conf.sync_log)
+ SyncLog("EMAILCHANGE %s %s", hi->handle, hi->cookie->data);
+ break;
+ default:
+ reply("NSMSG_BAD_COOKIE_TYPE", hi->cookie->type);
+ log_module(NS_LOG, LOG_ERROR, "Bad cookie type %d for account %s.", hi->cookie->type, hi->handle);
+ break;
+ }
+
nickserv_eat_cookie(hi->cookie);
reply("NSMSG_ATE_FOREIGN_COOKIE", hi->handle);
static OPTION_FUNC(opt_title)
{
- const char *title;
+ char *title;
+ const char *none;
+ char *sptr;
if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_title_level, 0)) {
if (!override) {
}
title = argv[1];
- if (strchr(title, '.')) {
- reply("NSMSG_TITLE_INVALID");
- return 0;
- }
- if ((strlen(user->handle_info->handle) + strlen(title) +
- strlen(nickserv_conf.titlehost_suffix) + 2) > HOSTLEN) {
- reply("NSMSG_TITLE_TRUNCATED");
- return 0;
- }
-
- free(hi->fakehost);
- if (!strcmp(title, "*")) {
+ if(!strcmp(title, "*")) {
+ free(hi->fakehost);
hi->fakehost = NULL;
- } else {
+ }
+ else {
+ if (strchr(title, '.')) {
+ reply("NSMSG_TITLE_INVALID");
+ return 0;
+ }
+ /* Alphanumeric titles only. */
+ for(sptr = title; *sptr; sptr++) {
+ if(!isalnum(*sptr) && *sptr != '-') {
+ reply("NSMSG_TITLE_INVALID");
+ return 0;
+ }
+ }
+ if ((strlen(user->handle_info->handle) + strlen(title) +
+ strlen(nickserv_conf.titlehost_suffix) + 2) > HOSTLEN) {
+ reply("NSMSG_TITLE_TRUNCATED");
+ return 0;
+ }
+ free(hi->fakehost);
hi->fakehost = malloc(strlen(title)+2);
hi->fakehost[0] = '.';
strcpy(hi->fakehost+1, title);
apply_fakehost(hi);
} else if (hi->fakehost && (hi->fakehost[0] == '.'))
title = hi->fakehost + 1;
- else
- title = NULL;
+ else {
+ /* If theres no title set then the default title will therefore
+ be the first part of hidden_host in x3.conf.example, so for
+ consistency with opt_fakehost we will print this here */
+ char *hs, *hidden_suffix, *rest;
+
+ hs = conf_get_data("server/hidden_host", RECDB_QSTRING);
+ hidden_suffix = strdup(hs);
+
+ /* Yes we do this twice */
+ rest = strrchr(hidden_suffix, '.');
+ *rest++ = '\0';
+ rest = strrchr(hidden_suffix, '.');
+ *rest++ = '\0';
+
+ title = hidden_suffix;
+ }
+
if (!title)
- title = user_find_message(user, "MSG_NONE");
- send_message(user, nickserv, "NSMSG_SET_TITLE", title);
+ none = user_find_message(user, "MSG_NONE");
+ send_message(user, nickserv, "NSMSG_SET_TITLE", title ? title : none);
return 1;
}
int
check_vhost(char *vhost, struct userNode *user, struct svccmd *cmd)
{
- unsigned int y, depth;
- char *hostname;
+ unsigned int y;
// check for a dot in the vhost
if(strchr(vhost, '.') == NULL) {
return 0;
}
+ /* This can be handled by the regex now if desired.
if (vhost[strspn(vhost, "0123456789.")]) {
hostname = vhost + strlen(vhost);
for (depth = 1; depth && (hostname > vhost); depth--) {
while ((hostname > vhost) && (*hostname != '.')) hostname--;
}
- if (*hostname == '.') hostname++; /* advance past last dot we saw */
+ if (*hostname == '.') hostname++; * advance past last dot we saw *
if(strlen(hostname) > 4) {
reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
return 0;
}
}
+ */
+ /* test either regex or as valid handle */
+ if (nickserv_conf.valid_fakehost_regex_set) {
+ int err = regexec(&nickserv_conf.valid_fakehost_regex, vhost, 0, 0, 0);
+ if (err) {
+ char buff[256];
+ buff[regerror(err, &nickserv_conf.valid_fakehost_regex, buff, sizeof(buff))] = 0;
+ log_module(NS_LOG, LOG_INFO, "regexec error: %s (%d)", buff, err);
+ }
+ if(err == REG_NOMATCH) {
+ reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost);
+ return 0;
+ }
+ }
+
return 1;
}
reply("NSMSG_FAKEHOST_INVALID", HOSTLEN);
return 0;
}
- free(hi->fakehost);
if (!strcmp(fake, "*")) {
- hi->fakehost = NULL;
- } else {
- if (!check_vhost(argv[1], user, cmd))
- return 0;
-
+ if(hi->fakehost) {
+ free(hi->fakehost);
+ hi->fakehost = NULL;
+ }
+ }
+ else if (!check_vhost(argv[1], user, cmd)) {
+ /* check_vhost takes care of error reply */
+ return 0;
+ }
+ else {
+ if(hi->fakehost)
+ free(hi->fakehost);
hi->fakehost = strdup(fake);
}
- fake = hi->fakehost;
apply_fakehost(hi);
- } else {
+ fake = hi->fakehost;
+ } else
fake = generate_fakehost(hi);
- }
+
+ /* Tell them we set the host */
if (!fake)
fake = user_find_message(user, "MSG_NONE");
reply("NSMSG_SET_FAKEHOST", fake);
for (it = dict_first(nickserv_handle_dict); it; it = iter_next(it)) {
hi = iter_data(it);
-#ifdef WITH_PROTOCOL_BAHAMUT
- assert(hi->id);
-#endif
saxdb_start_record(ctx, iter_key(it), 0);
if (hi->announcements != '?') {
flags[0] = hi->announcements;
flags[flen] = 0;
saxdb_write_string(ctx, KEY_FLAGS, flags);
}
-#ifdef WITH_PROTOCOL_BAHAMUT
- saxdb_write_int(ctx, KEY_ID, hi->id);
-#endif
if (hi->infoline)
saxdb_write_string(ctx, KEY_INFO, hi->infoline);
if (hi->last_quit_host[0])
struct userNode *last_user;
struct userData *cList, *cListNext;
unsigned int ii, jj, n;
- char buffer[MAXLEN];
NICKSERV_MIN_PARMS(3);
hi_to->fakehost = strdup(hi_from->fakehost);
/* Notify of success. */
- sprintf(buffer, "%s (%s) merged account %s into %s.", user->nick, user->handle_info->handle, hi_from->handle, hi_to->handle);
reply("NSMSG_HANDLES_MERGED", hi_from->handle, hi_to->handle);
- global_message(MESSAGE_RECIPIENT_STAFF, buffer);
+ global_message_args(MESSAGE_RECIPIENT_OPERS, "NSMSG_ACCOUNT_MERGED", user->nick,
+ user->handle_info->handle, hi_from->handle, hi_to->handle);
/* Unregister the "from" handle. */
nickserv_unregister_handle(hi_from, NULL, cmd->parent->bot);
} else {
nickserv_conf.valid_nick_regex_set = 0;
}
+ str = database_get_data(conf_node, KEY_VALID_FAKEHOST_REGEX, RECDB_QSTRING);
+ if (nickserv_conf.valid_fakehost_regex_set)
+ regfree(&nickserv_conf.valid_fakehost_regex);
+ if (str) {
+ int err = regcomp(&nickserv_conf.valid_fakehost_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+ nickserv_conf.valid_fakehost_regex_set = !err;
+ if (err) log_module(NS_LOG, LOG_ERROR, "Bad valid_fakehost_regex (error %d)", err);
+ } else {
+ nickserv_conf.valid_fakehost_regex_set = 0;
+ }
str = database_get_data(conf_node, KEY_NICKS_PER_HANDLE, RECDB_QSTRING);
if (!str)
str = database_get_data(conf_node, KEY_NICKS_PER_ACCOUNT, RECDB_QSTRING);