]> jfr.im git - irc/evilnet/x3.git/blobdiff - src/nickserv.c
fix crash when rerouting without routing configured
[irc/evilnet/x3.git] / src / nickserv.c
index fdb78b00e175fa55d08b26062d883d40dbbe0e52..1f3ee2fdcd6990e51442d368703f17c5b003e230 100644 (file)
@@ -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);