Fix compilation warnings from gcc 4.6.
[srvx.git] / src / nickserv.c
index 5a5c7f5a770334dd526c1c87e794a4e39db0df69..f8941033ec820bfa388e0035707808e01ecdfc57 100644 (file)
@@ -51,6 +51,7 @@
 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
 #define KEY_SET_TITLE_LEVEL "set_title_level"
 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
+#define KEY_SET_FAKEIDENT_LEVEL "set_fakeident_level"
 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
 #define KEY_FLAG_LEVELS "flag_levels"
 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
 #define KEY_TABLE_WIDTH "table_width"
 #define KEY_MAXLOGINS "maxlogins"
 #define KEY_FAKEHOST "fakehost"
+#define KEY_FAKEIDENT "fakeident"
 #define KEY_NOTES "notes"
 #define KEY_NOTE_EXPIRES "expires"
 #define KEY_NOTE_SET "set"
@@ -192,7 +194,10 @@ static const struct message_entry msgtab[] = {
     { "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_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
+    { "NSMSG_TITLE_TRUNCATED_RENAME", "That account name combined with the user's title would result in a truncated host; please choose a shorter account name." },
     { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
+    { "NSMSG_FAKEIDENT_INVALID", "Fake idents must be shorter than %d characters." },
+    { "NSMSG_FAKEMASK_INVALID", "Fake ident@hosts must be shorter than %d characters." },
     { "NSMSG_HANDLEINFO_ON", "Account information for $b%s$b:" },
     { "NSMSG_HANDLEINFO_ID", "  Account ID: %lu" },
     { "NSMSG_HANDLEINFO_REGGED", "  Registered on: %s" },
@@ -209,7 +214,9 @@ static const struct message_entry msgtab[] = {
     { "NSMSG_HANDLEINFO_INFOLINE", "  Infoline: %s" },
     { "NSMSG_HANDLEINFO_FLAGS", "  Flags: %s" },
     { "NSMSG_HANDLEINFO_EPITHET", "  Epithet: %s" },
+    { "NSMSG_HANDLEINFO_FAKEIDENT", "  Fake ident: %s" },
     { "NSMSG_HANDLEINFO_FAKEHOST", "  Fake host: %s" },
+    { "NSMSG_HANDLEINFO_FAKEIDENTHOST", "  Fake host: %s@%s" },
     { "NSMSG_HANDLEINFO_LAST_HOST", "  Last quit hostmask: %s" },
     { "NSMSG_HANDLEINFO_NO_NOTES", "  Notes: None" },
     { "NSMSG_HANDLEINFO_NOTE_EXPIRES", "  Note %d (%s ago by %s, expires %s): %s" },
@@ -312,6 +319,8 @@ static const struct message_entry msgtab[] = {
     { "NSMSG_SET_EPITHET", "$bEPITHET:      $b%s" },
     { "NSMSG_SET_TITLE", "$bTITLE:        $b%s" },
     { "NSMSG_SET_FAKEHOST", "$bFAKEHOST:    $b%s" },
+    { "NSMSG_SET_FAKEIDENT", "$bFAKEIDENT:   $b%s" },
+    { "NSMSG_SET_FAKEIDENTHOST", "$bFAKEHOST:    $b%s@%s" },
     { "NSMSG_INVALID_KARMA", "$b%s$b is not a valid karma modifier." },
     { "NSMSG_SET_KARMA", "$bKARMA:       $b%d$b" },
     { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
@@ -374,10 +383,10 @@ static struct {
     unsigned long set_epithet_level;
     unsigned long set_title_level;
     unsigned long set_fakehost_level;
+    unsigned long set_fakeident_level;
     unsigned long handles_per_email;
     unsigned long email_search_level;
     const char *network_name;
-    const char *titlehost_suffix;
     regex_t valid_handle_regex;
     regex_t valid_nick_regex;
     dict_t weak_password_dict;
@@ -392,6 +401,8 @@ static struct {
     unsigned long ounregister_flags;
 } nickserv_conf;
 
+const char *titlehost_suffix = NULL;
+
 /* We have 2^32 unique account IDs to use. */
 unsigned long int highest_id = 0;
 
@@ -538,6 +549,7 @@ free_handle_info(void *vhi)
     free(hi->infoline);
     free(hi->epithet);
     free(hi->fakehost);
+    free(hi->fakeident);
     if (hi->cookie) {
         timeq_del(hi->cookie->expires, nickserv_free_cookie, hi->cookie, 0);
         nickserv_free_cookie(hi->cookie);
@@ -877,23 +889,47 @@ generate_fakehost(struct handle_info *handle)
         return buffer;
     } else if (handle->fakehost[0] == '.') {
         /* A leading dot indicates the stored value is actually a title. */
-        snprintf(buffer, sizeof(buffer), "%s.%s.%s", handle->handle, handle->fakehost+1, nickserv_conf.titlehost_suffix);
+        snprintf(buffer, sizeof(buffer), "%s.%s.%s", handle->handle, handle->fakehost+1, titlehost_suffix);
         return buffer;
     }
     return handle->fakehost;
 }
 
+static char *
+generate_fakeident(struct handle_info *handle, struct userNode *user)
+{
+    static char buffer[USERLEN+1];
+
+    if (!handle->fakeident) {
+        if (!user)
+            return NULL;
+        safestrncpy(buffer, user->ident, sizeof(buffer));
+        return buffer;
+    }
+    return handle->fakeident;
+}
+
 static void
-apply_fakehost(struct handle_info *handle)
+apply_fakehost(struct handle_info *handle, struct userNode *user)
 {
     struct userNode *target;
-    char *fake;
+    char *fakehost, *fakeident;
 
     if (!handle->users)
         return;
-    fake = generate_fakehost(handle);
-    for (target = handle->users; target; target = target->next_authed)
-        assign_fakehost(target, fake, 1);
+
+    fakehost = generate_fakehost(handle);
+
+    if (user) {
+        fakeident = generate_fakeident(handle, user);
+        assign_fakehost(user, fakehost, fakeident, 0, 1);
+        return;
+    }
+
+    for (target = handle->users; target; target = target->next_authed) {
+        fakeident = generate_fakeident(handle, target);
+        assign_fakehost(target, fakehost, fakeident, 0, 1);
+    }
 }
 
 static void
@@ -917,11 +953,14 @@ set_user_handle_info(struct userNode *user, struct handle_info *hi, int stamp)
         /* remove from next_authed linked list */
         if (user->handle_info->users == user) {
             user->handle_info->users = user->next_authed;
-        } else {
+        } else if (user->handle_info->users != NULL) {
             for (other = user->handle_info->users;
                  other->next_authed != user;
                  other = other->next_authed) ;
             other->next_authed = user->next_authed;
+        } else {
+            /* No users authed to the account - can happen if they get
+             * killed for authing. */
         }
         /* if nobody left on old handle, and they're not an oper, remove !god */
         if (!user->handle_info->users && !user->handle_info->opserv_level)
@@ -935,8 +974,11 @@ set_user_handle_info(struct userNode *user, struct handle_info *hi, int stamp)
     user->handle_info = hi;
     if (hi && !hi->users && !hi->opserv_level)
         HANDLE_CLEAR_FLAG(hi, HELPING);
-    for (n=0; (n<auth_func_used) && !user->dead; n++)
+    for (n=0; n<auth_func_used; n++) {
         auth_func_list[n](user, old_info);
+        if (user->dead)
+            return;
+    }
     if (hi) {
         struct nick_info *ni;
 
@@ -952,14 +994,14 @@ set_user_handle_info(struct userNode *user, struct handle_info *hi, int stamp)
         if (IsHelper(user) && !userList_contains(&curr_helpers, user))
             userList_append(&curr_helpers, user);
 
-        if (hi->fakehost || old_info)
-            apply_fakehost(hi);
+        if (hi->fakehost || hi->fakeident || old_info)
+            apply_fakehost(hi, user);
 
         if (stamp) {
             if (!nickserv_conf.disable_nicks) {
-                struct nick_info *ni;
-                for (ni = hi->nicks; ni; ni = ni->next) {
-                    if (!irccasecmp(user->nick, ni->nick)) {
+                struct nick_info *ni2;
+                for (ni2 = hi->nicks; ni2; ni2 = ni2->next) {
+                    if (!irccasecmp(user->nick, ni2->nick)) {
                         user->modes |= FLAGS_REGNICK;
                         break;
                     }
@@ -1258,15 +1300,34 @@ static NICKSERV_FUNC(cmd_oregister)
     char *mask;
     struct userNode *settee;
     struct handle_info *hi;
+    const char *pass, *email;
 
     NICKSERV_MIN_PARMS(3);
 
+    pass = argv[2];
+    argv[2] = "****";
+
     if (!is_valid_handle(argv[1])) {
         reply("NSMSG_BAD_HANDLE", argv[1]);
         return 0;
     }
 
-    if (argc < 4) {
+    if (argc < 5 || !nickserv_conf.email_enabled) {
+        email = NULL;
+    } else {
+        const char *str;
+        email = argv[4];
+        if (!is_valid_email_addr(email)) {
+            send_message(user, nickserv, "NSMSG_BAD_EMAIL_ADDR");
+            return 0;
+        }
+        if ((str = mail_prohibited_address(email))) {
+            send_message(user, nickserv, "NSMSG_EMAIL_PROHIBITED", email, str);
+            return 0;
+        }
+    }
+
+    if (argc < 4 || !strcmp(argv[3], "*")) {
         mask = NULL;
         settee = NULL;
     } else if (strchr(argv[3], '@')) {
@@ -1292,12 +1353,14 @@ static NICKSERV_FUNC(cmd_oregister)
         free(mask);
         return 0;
     }
-    if (!(hi = nickserv_register(user, settee, argv[1], argv[2], 0))) {
+    if (!(hi = nickserv_register(user, settee, argv[1], pass, 0))) {
         free(mask);
         return 0;
     }
     if (mask)
         string_list_append(hi->masks, mask);
+    if (email)
+        nickserv_set_email_addr(hi, email);
     return 1;
 }
 
@@ -1404,8 +1467,12 @@ static NICKSERV_FUNC(cmd_handleinfo)
         reply("NSMSG_HANDLEINFO_EPITHET", (hi->epithet ? hi->epithet : nsmsg_none));
     }
 
-    if (hi->fakehost)
-        reply("NSMSG_HANDLEINFO_FAKEHOST", (hi->fakehost ? hi->fakehost : handle_find_message(hi, "MSG_NONE")));
+    if (hi->fakeident && hi->fakehost)
+        reply("NSMSG_HANDLEINFO_FAKEIDENTHOST", hi->fakeident, hi->fakehost);
+    else if (hi->fakeident)
+        reply("NSMSG_HANDLEINFO_FAKEIDENT", hi->fakeident);
+    else if (hi->fakehost)
+        reply("NSMSG_HANDLEINFO_FAKEHOST", hi->fakehost);
 
     if (hi->last_quit_host[0])
         reply("NSMSG_HANDLEINFO_LAST_HOST", hi->last_quit_host);
@@ -1458,20 +1525,20 @@ static NICKSERV_FUNC(cmd_handleinfo)
     }
 
     if (hi->channels) {
-        struct userData *channel, *next;
+        struct userData *chan, *next;
         char *name;
 
-        for (channel = hi->channels; channel; channel = next) {
-            next = channel->u_next;
-            name = channel->channel->channel->name;
+        for (chan = hi->channels; chan; chan = next) {
+            next = chan->u_next;
+            name = chan->channel->channel->name;
             herelen = strlen(name);
             if (pos + herelen + 7 > ArrayLength(buff)) {
-                next = channel;
+                next = chan;
                 goto print_chans_buff;
             }
-            if (IsUserSuspended(channel))
+            if (IsUserSuspended(chan))
                 buff[pos++] = '-';
-            pos += sprintf(buff+pos, "%d:%s ", channel->access, name);
+            pos += sprintf(buff+pos, "%d:%s ", chan->access, name);
             if (next == NULL) {
               print_chans_buff:
                 buff[pos-1] = 0;
@@ -1576,6 +1643,12 @@ static NICKSERV_FUNC(cmd_rename_handle)
         reply("NSMSG_HANDLE_EXISTS", argv[2]);
         return 0;
     }
+    if (hi->fakehost && hi->fakehost[0] == '.' &&
+        (strlen(argv[2]) + strlen(hi->fakehost+1) +
+         strlen(titlehost_suffix) + 2) > HOSTLEN) {
+        send_message(user, nickserv, "NSMSG_TITLE_TRUNCATED_RENAME");
+        return 0;
+    }
 
     dict_remove2(nickserv_handle_dict, old_handle = hi->handle, 1);
     hi->handle = strdup(argv[2]);
@@ -2556,7 +2629,7 @@ static OPTION_FUNC(opt_title)
             return 0;
         }
         if ((strlen(user->handle_info->handle) + strlen(title) +
-             strlen(nickserv_conf.titlehost_suffix) + 2) > HOSTLEN) {
+             strlen(titlehost_suffix) + 2) > HOSTLEN) {
             send_message(user, nickserv, "NSMSG_TITLE_TRUNCATED");
             return 0;
         }
@@ -2569,7 +2642,7 @@ static OPTION_FUNC(opt_title)
             hi->fakehost[0] = '.';
             strcpy(hi->fakehost+1, title);
         }
-        apply_fakehost(hi);
+        apply_fakehost(hi, NULL);
     } else if (hi->fakehost && (hi->fakehost[0] == '.'))
         title = hi->fakehost + 1;
     else
@@ -2582,7 +2655,8 @@ static OPTION_FUNC(opt_title)
 
 static OPTION_FUNC(opt_fakehost)
 {
-    const char *fake;
+    char mask[USERLEN + HOSTLEN + 2];
+    char *host, *ident;
 
     if (!override) {
         send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]);
@@ -2590,34 +2664,109 @@ static OPTION_FUNC(opt_fakehost)
     }
 
     if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_fakehost_level, 0)) {
-        fake = argv[1];
-        if ((strlen(fake) > HOSTLEN) || (fake[0] == '.')) {
+        if(strlen(argv[1]) >= sizeof(mask)) {
+            send_message(user, nickserv, "NSMSG_FAKEMASK_INVALID", USERLEN + HOSTLEN + 1);
+            return 0;
+        }
+
+        safestrncpy(mask, argv[1], sizeof(mask));
+
+        if ((host = strrchr(mask, '@')) && host != mask) {
+            /* If ident@host was used and the user doesn't have access to set idents, do not change anything. */
+            if (!oper_has_access(user, nickserv, nickserv_conf.set_fakeident_level, 0)) {
+                host = NULL;
+                ident = NULL;
+            } else {
+                ident = mask;
+                *host++ = '\0';
+            }
+        } else {
+            ident = NULL;
+            host = mask;
+        }
+
+        if (ident && strlen(ident) > USERLEN) {
+            send_message(user, nickserv, "NSMSG_FAKEIDENT_INVALID", USERLEN);
+            return 0;
+        }
+
+        if (host && ((strlen(host) > HOSTLEN) || (host[0] == '.'))) {
             send_message(user, nickserv, "NSMSG_FAKEHOST_INVALID", HOSTLEN);
             return 0;
         }
-        free(hi->fakehost);
-        if (!strcmp(fake, "*"))
-            hi->fakehost = NULL;
+
+        if (host && host[0]) {
+            free(hi->fakehost);
+            if (!strcmp(host, "*"))
+                hi->fakehost = NULL;
+            else
+                hi->fakehost = strdup(host);
+            host = hi->fakehost;
+        }
         else
-            hi->fakehost = strdup(fake);
-        fake = hi->fakehost;
-        apply_fakehost(hi);
+            host = generate_fakehost(hi);
+
+        if (ident) {
+            free(hi->fakeident);
+            if (!strcmp(ident, "*"))
+                hi->fakeident = NULL;
+            else
+                hi->fakeident = strdup(ident);
+            ident = hi->fakeident;
+        }
+        else
+            ident = generate_fakeident(hi, NULL);
+
+        apply_fakehost(hi, NULL);
+    } else {
+        host = generate_fakehost(hi);
+        ident = generate_fakeident(hi, NULL);
+    }
+    if (!host)
+        host = (char *) user_find_message(user, "MSG_NONE");
+    if(ident)
+        send_message(user, nickserv, "NSMSG_SET_FAKEIDENTHOST", ident, host);
+    else
+        send_message(user, nickserv, "NSMSG_SET_FAKEHOST", host);
+    return 1;
+}
+
+static OPTION_FUNC(opt_fakeident)
+{
+    const char *ident;
+
+    if (!override) {
+        send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]);
+        return 0;
+    }
+
+    if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_fakeident_level, 0)) {
+        ident = argv[1];
+        if (strlen(ident) > USERLEN) {
+            send_message(user, nickserv, "NSMSG_FAKEIDENT_INVALID", USERLEN);
+            return 0;
+        }
+        free(hi->fakeident);
+        if (!strcmp(ident, "*"))
+            hi->fakeident = NULL;
+        else
+            hi->fakeident = strdup(ident);
+        ident = hi->fakeident;
+        apply_fakehost(hi, NULL);
     } else
-        fake = generate_fakehost(hi);
-    if (!fake)
-        fake = user_find_message(user, "MSG_NONE");
-    send_message(user, nickserv, "NSMSG_SET_FAKEHOST", fake);
+        ident = generate_fakeident(hi, NULL); /* NULL if no fake ident set */
+    if (!ident)
+        ident = user_find_message(user, "MSG_NONE");
+    send_message(user, nickserv, "NSMSG_SET_FAKEIDENT", ident);
     return 1;
 }
 
 static NICKSERV_FUNC(cmd_reclaim)
 {
-    struct handle_info *hi;
     struct nick_info *ni;
     struct userNode *victim;
 
     NICKSERV_MIN_PARMS(2);
-    hi = user->handle_info;
     ni = dict_find(nickserv_nick_dict, argv[1], 0);
     if (!ni) {
         reply("NSMSG_UNKNOWN_NICK", argv[1]);
@@ -2909,6 +3058,8 @@ nickserv_saxdb_write(struct saxdb_context *ctx) {
             saxdb_write_string(ctx, KEY_EPITHET, hi->epithet);
         if (hi->fakehost)
             saxdb_write_string(ctx, KEY_FAKEHOST, hi->fakehost);
+        if (hi->fakeident)
+            saxdb_write_string(ctx, KEY_FAKEIDENT, hi->fakeident);
         if (hi->flags) {
             int ii, flen;
 
@@ -3084,6 +3235,8 @@ static NICKSERV_FUNC(cmd_merge)
      */
     if (hi_from->fakehost && !hi_to->fakehost)
         hi_to->fakehost = strdup(hi_from->fakehost);
+    if (hi_from->fakeident && !hi_to->fakeident)
+        hi_to->fakeident = strdup(hi_from->fakeident);
 
     /* Notify of success. */
     sprintf(buffer, "%s (%s) merged account %s into %s.", user->nick, user->handle_info->handle, hi_from->handle, hi_to->handle);
@@ -3107,6 +3260,7 @@ struct nickserv_discrim {
     const char *nickmask;
     const char *hostmask;
     const char *fakehostmask;
+    const char *fakeidentmask;
     const char *handlemask;
     const char *emailmask;
 };
@@ -3206,6 +3360,12 @@ nickserv_discrim_create(struct userNode *user, unsigned int argc, char *argv[])
             } else {
                 discrim->fakehostmask = argv[i];
             }
+        } else if (!irccasecmp(argv[i], "fakeident")) {
+            if (!irccasecmp(argv[++i], "*")) {
+                discrim->fakeidentmask = 0;
+            } else {
+                discrim->fakeidentmask = argv[i];
+            }
         } else if (!irccasecmp(argv[i], "handlemask") || !irccasecmp(argv[i], "accountmask")) {
             if (!irccasecmp(argv[++i], "*")) {
                 discrim->handlemask = 0;
@@ -3281,6 +3441,7 @@ nickserv_discrim_match(struct nickserv_discrim *discrim, struct handle_info *hi)
         || (discrim->lastseen < (hi->users?now:hi->lastseen))
         || (discrim->handlemask && !match_ircglob(hi->handle, discrim->handlemask))
         || (discrim->fakehostmask && (!hi->fakehost || !match_ircglob(hi->fakehost, discrim->fakehostmask)))
+        || (discrim->fakeidentmask && (!hi->fakeident || !match_ircglob(hi->fakeident, discrim->fakeidentmask)))
         || (discrim->emailmask && (!hi->email_addr || !match_ircglob(hi->email_addr, discrim->emailmask)))
         || (discrim->min_level > hi->opserv_level)
         || (discrim->max_level < hi->opserv_level)
@@ -3485,7 +3646,7 @@ nickserv_db_read_handle(const char *handle, dict_t obj)
     struct string_list *masks, *slist;
     struct handle_info *hi;
     struct userNode *authed_users;
-    struct userData *channels;
+    struct userData *channel_list;
     unsigned long id;
     unsigned int ii;
     dict_t subdb;
@@ -3499,13 +3660,13 @@ nickserv_db_read_handle(const char *handle, dict_t obj)
     }
     if ((hi = get_handle_info(handle))) {
         authed_users = hi->users;
-        channels = hi->channels;
+        channel_list = hi->channels;
         hi->users = NULL;
         hi->channels = NULL;
         dict_remove(nickserv_handle_dict, hi->handle);
     } else {
         authed_users = NULL;
-        channels = NULL;
+        channel_list = NULL;
     }
     hi = register_handle(handle, str, id);
     if (authed_users) {
@@ -3515,7 +3676,7 @@ nickserv_db_read_handle(const char *handle, dict_t obj)
             authed_users = authed_users->next_authed;
         }
     }
-    hi->channels = channels;
+    hi->channels = channel_list;
     masks = database_get_data(obj, KEY_MASKS, RECDB_STRING_LIST);
     hi->masks = masks ? string_list_copy(masks) : alloc_string_list(1);
     str = database_get_data(obj, KEY_MAXLOGINS, RECDB_QSTRING);
@@ -3565,6 +3726,9 @@ nickserv_db_read_handle(const char *handle, dict_t obj)
     str = database_get_data(obj, KEY_FAKEHOST, RECDB_QSTRING);
     if (str)
         hi->fakehost = strdup(str);
+    str = database_get_data(obj, KEY_FAKEIDENT, RECDB_QSTRING);
+    if (str)
+        hi->fakeident = strdup(str);
     /* Read the "cookie" sub-database (if it exists). */
     subdb = database_get_data(obj, KEY_COOKIE, RECDB_OBJECT);
     if (subdb) {
@@ -3618,13 +3782,13 @@ nickserv_db_read_handle(const char *handle, dict_t obj)
             const char *setter;
             const char *text;
             const char *set;
-            const char *id;
+            const char *note_id;
             dict_t notedb;
 
-            id = iter_key(it);
+            note_id = iter_key(it);
             notedb = GET_RECORD_OBJECT((struct record_data*)iter_data(it));
             if (!notedb) {
-                log_module(NS_LOG, LOG_ERROR, "Malformed note %s for account %s; ignoring note.", id, hi->handle);
+                log_module(NS_LOG, LOG_ERROR, "Malformed note %s for account %s; ignoring note.", note_id, hi->handle);
                 continue;
             }
             expires = database_get_data(notedb, KEY_NOTE_EXPIRES, RECDB_QSTRING);
@@ -3632,14 +3796,14 @@ nickserv_db_read_handle(const char *handle, dict_t obj)
             text = database_get_data(notedb, KEY_NOTE_NOTE, RECDB_QSTRING);
             set = database_get_data(notedb, KEY_NOTE_SET, RECDB_QSTRING);
             if (!setter || !text || !set) {
-                log_module(NS_LOG, LOG_ERROR, "Missing field(s) from note %s for account %s; ignoring note.", id, hi->handle);
+                log_module(NS_LOG, LOG_ERROR, "Missing field(s) from note %s for account %s; ignoring note.", note_id, hi->handle);
                 continue;
             }
             note = calloc(1, sizeof(*note) + strlen(text));
             note->next = NULL;
             note->expires = expires ? strtoul(expires, NULL, 10) : 0;
             note->set = strtoul(set, NULL, 10);
-            note->id = strtoul(id, NULL, 10);
+            note->id = strtoul(note_id, NULL, 10);
             safestrncpy(note->setter, setter, sizeof(note->setter));
             strcpy(note->note, text);
             if (last_note)
@@ -3807,6 +3971,8 @@ nickserv_conf_read(void)
     nickserv_conf.set_title_level = str ? strtoul(str, NULL, 0) : 900;
     str = database_get_data(conf_node, KEY_SET_FAKEHOST_LEVEL, RECDB_QSTRING);
     nickserv_conf.set_fakehost_level = str ? strtoul(str, NULL, 0) : 1000;
+    str = database_get_data(conf_node, KEY_SET_FAKEIDENT_LEVEL, RECDB_QSTRING);
+    nickserv_conf.set_fakeident_level = str ? strtoul(str, NULL, 0) : 1000;
     str = database_get_data(conf_node, KEY_HANDLE_EXPIRE_FREQ, RECDB_QSTRING);
     if (!str)
         str = database_get_data(conf_node, KEY_ACCOUNT_EXPIRE_FREQ, RECDB_QSTRING);
@@ -3901,7 +4067,7 @@ nickserv_conf_read(void)
     str = database_get_data(conf_node, KEY_EMAIL_SEARCH_LEVEL, RECDB_QSTRING);
     nickserv_conf.email_search_level = str ? strtoul(str, NULL, 0) : 600;
     str = database_get_data(conf_node, KEY_TITLEHOST_SUFFIX, RECDB_QSTRING);
-    nickserv_conf.titlehost_suffix = str ? str : "example.net";
+    titlehost_suffix = str ? str : "example.net";
     str = conf_get_data("server/network", RECDB_QSTRING);
     nickserv_conf.network_name = str ? str : "some IRC network";
     if (!nickserv_conf.auth_policer_params) {
@@ -4152,9 +4318,10 @@ init_nickserv(const char *nick)
     dict_insert(nickserv_opt_dict, "ACCESS", opt_level);
     dict_insert(nickserv_opt_dict, "LEVEL", opt_level);
     dict_insert(nickserv_opt_dict, "EPITHET", opt_epithet);
-    if (nickserv_conf.titlehost_suffix) {
+    if (titlehost_suffix) {
         dict_insert(nickserv_opt_dict, "TITLE", opt_title);
         dict_insert(nickserv_opt_dict, "FAKEHOST", opt_fakehost);
+        dict_insert(nickserv_opt_dict, "FAKEIDENT", opt_fakeident);
     }
     dict_insert(nickserv_opt_dict, "MAXLOGINS", opt_maxlogins);
     dict_insert(nickserv_opt_dict, "LANGUAGE", opt_language);