]> jfr.im git - irc/evilnet/x3.git/blobdiff - src/nickserv.c
fixing delpeon bug
[irc/evilnet/x3.git] / src / nickserv.c
index fdb78b00e175fa55d08b26062d883d40dbbe0e52..e189e7778e067b939e6a2bf422aa7f63df38f8b3 100644 (file)
@@ -27,7 +27,7 @@
 #include "sendmail.h"
 #include "timeq.h"
 
-#include <regex.h>
+#include <tre/regex.h>
 
 #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,8 +364,10 @@ 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." },
+    { "NSMSG_DEFCON_NO_NEW_NICKS", "You cannot register new %s at this time, please try again soon" },
     { NULL, NULL }
 };
 
@@ -381,6 +384,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 +414,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;
@@ -454,32 +459,6 @@ register_handle(const char *handle, const char *passwd, UNUSED_ARG(unsigned long
 {
     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 = '?';
@@ -488,11 +467,6 @@ register_handle(const char *handle, const char *passwd, UNUSED_ARG(unsigned long
     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;
 }
 
@@ -565,13 +539,6 @@ free_handle_info(void *vhi)
 {
     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);
@@ -922,11 +889,28 @@ reg_handle_rename_func(handle_rename_func_t func)
 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. */
@@ -1000,10 +984,8 @@ set_user_handle_info(struct userNode *user, struct handle_info *hi, int stamp)
     if (hi && !hi->users && !hi->opserv_level)
         HANDLE_CLEAR_FLAG(hi, HELPING);
 
-    if (GetUserH(user->nick)) {
-        for (n=0; n<auth_func_used; n++)
-            auth_func_list[n](user, old_info);
-    } else
+    /* Call auth handlers */
+    if (!GetUserH(user->nick))
       user->loc = 1;
 
     if (hi) {
@@ -1016,26 +998,28 @@ set_user_handle_info(struct userNode *user, struct handle_info *hi, int stamp)
                 send_message(other, nickserv, "NSMSG_CLONE_AUTH", user->nick, user->ident, user->hostname);
         }
 
+        /* Add this auth to users list of current auths */
        user->next_authed = hi->users;
        hi->users = user;
        hi->lastseen = now;
+        /* Add to helpers list */
        if (IsHelper(user))
             userList_append(&curr_helpers, user);
 
+        /* Set the fakehost */
         if (hi->fakehost || old_info)
             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
             const char *id = "???";
 #endif
+            /* Mark all the nicks registered to this
+             * account as registered nicks 
+             *  -  Why not just this one? -rubin */
             if (!nickserv_conf.disable_nicks) {
                 struct nick_info *ni;
                 for (ni = hi->nicks; ni; ni = ni->next) {
@@ -1045,15 +1029,23 @@ set_user_handle_info(struct userNode *user, struct handle_info *hi, int stamp)
                     }
                 }
             }
+            /* send the account to the ircd */
             StampUser(user, id, hi->registered);
         }
 
+        /* Stop trying to kick this user off their nick */
         if ((ni = get_nick_info(user->nick)) && (ni->owner == hi))
             timeq_del(0, nickserv_reclaim_p, user, TIMEQ_IGNORE_WHEN);
     } else {
         /* We cannot clear the user's account ID, unfortunately. */
        user->next_authed = NULL;
     }
+
+    /* Call auth handlers */
+    if (GetUserH(user->nick)) {
+        for (n=0; n<auth_func_used; n++)
+            auth_func_list[n](user, old_info);
+    }
 }
 
 static struct handle_info*
@@ -1275,6 +1267,11 @@ static NICKSERV_FUNC(cmd_register)
     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");
@@ -1575,9 +1572,6 @@ static NICKSERV_FUNC(cmd_handleinfo)
     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) {
@@ -1800,7 +1794,7 @@ static NICKSERV_FUNC(cmd_rename_handle)
 {
     struct handle_info *hi;
     struct userNode *uNode;
-    char msgbuf[MAXLEN], *old_handle;
+    char *old_handle;
     unsigned int nn;
 
     NICKSERV_MIN_PARMS(3);
@@ -1825,8 +1819,6 @@ static NICKSERV_FUNC(cmd_rename_handle)
     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)
@@ -1836,7 +1828,9 @@ static NICKSERV_FUNC(cmd_rename_handle)
     }
 
     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;
 }
@@ -2186,6 +2180,32 @@ static NICKSERV_FUNC(cmd_odelcookie)
         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);
 
@@ -2948,7 +2968,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 +2979,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 +3008,41 @@ 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, so for
+           consistency with opt_fakehost we will print this here.
+           This isnt actually used in P10, its just handled to keep from crashing... */
+        char *hs, *hidden_suffix, *rest;
+
+        hs = conf_get_data("server/hidden_host", RECDB_QSTRING);
+        hidden_suffix = strdup(hs);
+
+        /* Yes we do this twice */
+        if((rest = strchr(hidden_suffix, '.')))
+        {
+            *rest = '\0';
+            title = hidden_suffix;
+        }
+        else
+        {
+            /* A lame default if someone configured hidden_host to something lame */
+            title = strdup("users");
+            free(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 +3070,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 +3078,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 +3118,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);
@@ -3261,9 +3336,6 @@ nickserv_saxdb_write(struct saxdb_context *ctx) {
 
     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;
@@ -3314,9 +3386,6 @@ nickserv_saxdb_write(struct saxdb_context *ctx) {
             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])
@@ -3381,7 +3450,6 @@ static NICKSERV_FUNC(cmd_merge)
     struct userNode *last_user;
     struct userData *cList, *cListNext;
     unsigned int ii, jj, n;
-    char buffer[MAXLEN];
 
     NICKSERV_MIN_PARMS(3);
 
@@ -3492,9 +3560,9 @@ static NICKSERV_FUNC(cmd_merge)
         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);
@@ -4110,6 +4178,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);