X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/c092fcad1208537de0115ebac7fc7e3b043dc39e..6a64b9cea9d7f537ce31c8df38fd738a3657fc39:/src/nickserv.c diff --git a/src/nickserv.c b/src/nickserv.c index fdb78b0..eb077f5 100644 --- a/src/nickserv.c +++ b/src/nickserv.c @@ -27,7 +27,7 @@ #include "sendmail.h" #include "timeq.h" -#include +#include #define NICKSERV_CONF_NAME "services/nickserv" @@ -42,6 +42,7 @@ #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" @@ -191,7 +192,7 @@ static const struct message_entry msgtab[] = { { "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" }, @@ -363,6 +364,7 @@ static const struct message_entry msgtab[] = { { "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." }, { NULL, NULL } @@ -381,6 +383,7 @@ static struct { 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; @@ -410,6 +413,7 @@ static struct { 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; @@ -2948,7 +2952,9 @@ static OPTION_FUNC(opt_epithet) 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) { @@ -2957,20 +2963,28 @@ static OPTION_FUNC(opt_title) } 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); @@ -2978,19 +2992,34 @@ static OPTION_FUNC(opt_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) { @@ -3018,6 +3047,7 @@ check_vhost(char *vhost, struct userNode *user, struct svccmd *cmd) 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--) { @@ -3025,12 +3055,27 @@ check_vhost(char *vhost, struct userNode *user, struct svccmd *cmd) 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; } @@ -3050,20 +3095,27 @@ static OPTION_FUNC(opt_fakehost) 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); @@ -4110,6 +4162,16 @@ nickserv_conf_read(void) } 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);