fixed coding fails in the last 2 commits
[srvx.git] / src / nickserv.c
index 581d9b47d57ca0c881d6e6d3dca5af0eda1edcce..089cc935daab316d7c9e22647c75e6f367205617 100644 (file)
@@ -48,6 +48,7 @@
 #define KEY_VALID_NICK_REGEX "valid_nick_regex"
 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
 #define KEY_MODOPER_LEVEL "modoper_level"
+#define KEY_MODSTAFF_LEVEL "modstaff_level"
 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
 #define KEY_SET_TITLE_LEVEL "set_title_level"
 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
@@ -82,6 +83,7 @@
 #define KEY_NICKS "nicks"
 #define KEY_MASKS "masks"
 #define KEY_OPSERV_LEVEL "opserv_level"
+#define KEY_STAFF_LEVEL "staff_level"
 #define KEY_FLAGS "flags"
 #define KEY_REGISTER_ON "register"
 #define KEY_LAST_SEEN "lastseen"
@@ -330,6 +332,7 @@ static const struct message_entry msgtab[] = {
     { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS:    $b%d" },
     { "NSMSG_SET_LANGUAGE", "$bLANGUAGE:     $b%s" },
     { "NSMSG_SET_LEVEL", "$bLEVEL:        $b%d" },
+    { "NSMSG_SET_STAFFLEVEL", "$bSTAFF_LEVEL:    $b%d" },
     { "NSMSG_SET_EPITHET", "$bEPITHET:      $b%s" },
     { "NSMSG_SET_TITLE", "$bTITLE:        $b%s" },
     { "NSMSG_SET_FAKEHOST", "$bFAKEHOST:    $b%s" },
@@ -394,6 +397,7 @@ static struct {
     unsigned long handle_expire_delay;
     unsigned long nochan_handle_expire_delay;
     unsigned long modoper_level;
+    unsigned long modstaff_level;
     unsigned long set_epithet_level;
     unsigned long set_title_level;
     unsigned long set_fakehost_level;
@@ -487,7 +491,7 @@ register_handle(const char *handle, const char *passwd, unsigned long id)
 
     hi->id = id;
     hi->website = NULL;
-    hi->devnull = NULL;
+    hi->devnull_id = 0;
     dict_insert(nickserv_id_dict, strdup(id_base64), hi);
 
     return hi;
@@ -574,7 +578,6 @@ free_handle_info(void *vhi)
     free(hi->infoline);
     free(hi->epithet);
     free(hi->fakehost);
-    free(hi->devnull);
     free(hi->website);
     free(hi->fakeident);
     if (hi->cookie) {
@@ -690,6 +693,23 @@ oper_has_access(struct userNode *user, struct userNode *bot, unsigned int min_le
     return 1;
 }
 
+int
+staff_has_access(struct userNode *user, struct userNode *bot, unsigned int min_level, unsigned int quiet) {
+    if (!user->handle_info) {
+        if (!quiet)
+            send_message(user, bot, "MSG_AUTHENTICATE");
+        return 0;
+    }
+
+    if (user->handle_info->staff_level < min_level) {
+        if (!quiet)
+            send_message(user, bot, "NSMSG_NO_ACCESS");
+        return 0;
+    }
+
+    return 1;
+}
+
 static int
 is_valid_handle(const char *handle)
 {
@@ -967,7 +987,7 @@ reg_handle_rename_func(handle_rename_func_t func)
     rf_list[rf_list_used++] = func;
 }
 
-static char *
+char *
 generate_fakehost(struct handle_info *handle)
 {
     extern const char *hidden_host_suffix;
@@ -988,7 +1008,7 @@ generate_fakehost(struct handle_info *handle)
     return handle->fakehost;
 }
 
-static char *
+char *
 generate_fakeident(struct handle_info *handle, struct userNode *user)
 {
     static char buffer[USERLEN+1];
@@ -1002,7 +1022,7 @@ generate_fakeident(struct handle_info *handle, struct userNode *user)
     return handle->fakeident;
 }
 
-static void
+void
 apply_fakehost(struct handle_info *handle, struct userNode *user)
 {
     struct userNode *target;
@@ -1361,16 +1381,17 @@ static NICKSERV_FUNC(cmd_register)
         return 0;
     /* Add any masks they should get. */
     if (nickserv_conf.default_hostmask) {
-        string_list_append(hi->masks, strdup("*@*"));
+        nickserv_addmask(NULL, hi, strdup("*@*"));
     } else {
-        string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
+        nickserv_addmask(NULL, hi, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
         if (irc_in_addr_is_valid(user->ip) && !irc_pton(&ip, NULL, user->hostname))
-            string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_BYIP|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
+            nickserv_addmask(NULL, hi, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_BYIP|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
     }
 
     /* If they're the first to register, give them level 1000. */
     if (dict_size(nickserv_handle_dict) == 1) {
         hi->opserv_level = 1000;
+        hi->staff_level = 1000;
         reply("NSMSG_ROOT_HANDLE", argv[1]);
     }
 
@@ -1488,8 +1509,10 @@ static NICKSERV_FUNC(cmd_handleinfo)
     }
 
     reply("NSMSG_HANDLEINFO_INFOLINE", (hi->infoline ? hi->infoline : nsmsg_none));
-    if ((oper_has_access(user, cmd->parent->bot, 200, 1)) || IsNetworkHelper(user))
-        reply("NSMSG_HANDLEINFO_DEVNULL", (hi->devnull ? hi->devnull : nsmsg_none));
+    if ((oper_has_access(user, cmd->parent->bot, 200, 1)) || IsNetworkHelper(user)) {
+        struct devnull_class *devnull_c = (hi->devnull_id ? devnull_find_id(hi->devnull_id) : NULL);
+        reply("NSMSG_HANDLEINFO_DEVNULL", (devnull_c ? devnull_c->name : nsmsg_none));
+    }
     if (user->handle_info && HANDLE_FLAGGED(user->handle_info, BOT))
         reply("NSMSG_HANDLEINFO_WEBSITE", (hi->website ? hi->website : nsmsg_none));
     if(hi->opserv_level > 0 && user->handle_info && HANDLE_FLAGGED(user->handle_info, BOT))
@@ -1937,9 +1960,9 @@ static NICKSERV_FUNC(cmd_auth)
         cryptpass(passwd, hi->passwd);
     if (!hi->masks->used) {
         irc_in_addr_t ip;
-        string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
+        nickserv_addmask(NULL, hi, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
         if (irc_in_addr_is_valid(user->ip) && irc_pton(&ip, NULL, user->hostname))
-            string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_BYIP|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
+            nickserv_addmask(NULL, hi, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_BYIP|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
     }
     authlog_add(hi, user, NULL);
     argv[pw_arg] = "****";
@@ -1947,7 +1970,7 @@ static NICKSERV_FUNC(cmd_auth)
     return 1;
 }
 
-struct handle_info *checklogin(const char *user, const char *pass, const char *numeric, const char *hostmask, const char *ipmask)
+struct handle_info *checklogin(const char *user, const char *pass, UNUSED_ARG(const char *numeric), const char *hostmask, const char *ipmask)
 {
     struct handle_info *hi;
     unsigned int match = 0, ii = 0;
@@ -2020,7 +2043,7 @@ static MODCMD_FUNC(cmd_authlog)
 static MODCMD_FUNC(cmd_oauthlog) {
     struct handle_info *hi;
     
-    NICKSERV_MIN_PARMS(1);
+    NICKSERV_MIN_PARMS(2);
     
     if (!(hi = get_victim_oper(user, argv[1])))
         return 0;
@@ -2399,13 +2422,15 @@ nickserv_addmask(struct userNode *user, struct handle_info *hi, const char *mask
     char *new_mask = canonicalize_hostmask(strdup(mask));
     for (i=0; i<hi->masks->used; i++) {
         if (!irccasecmp(new_mask, hi->masks->list[i])) {
-            send_message(user, nickserv, "NSMSG_ADDMASK_ALREADY", new_mask);
+            if(user)
+                send_message(user, nickserv, "NSMSG_ADDMASK_ALREADY", new_mask);
             free(new_mask);
             return 0;
         }
     }
     string_list_append(hi->masks, new_mask);
-    send_message(user, nickserv, "NSMSG_ADDMASK_SUCCESS", new_mask);
+    if(user)
+        send_message(user, nickserv, "NSMSG_ADDMASK_SUCCESS", new_mask);
     return 1;
 }
 
@@ -2625,52 +2650,46 @@ static OPTION_FUNC(opt_info)
 
 static OPTION_FUNC(opt_devnull)
 {
-    const char *devnull;
-    
+    const char *devnull_name;
+    struct devnull_class *devnull_c;
+
     if (argc > 1) {
         if (!override) {
             send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]);
             return 0;
         }
         if ((argv[1][0] == '*') && (argv[1][1] == 0)) {
-            free(hi->devnull);
-            hi->devnull = NULL;
+            hi->devnull_id = 0;
         } else {
-            devnull = unsplit_string(argv+1, argc-1, NULL);
-            if(devnull_check(devnull) == 1) { 
-                if(hi->devnull)
-                    free(hi->devnull);
-                hi->devnull = strdup(devnull);
-            }
+            devnull_name = unsplit_string(argv+1, argc-1, NULL);
+            devnull_c = devnull_find_name(devnull_name);
+            if(devnull_c)
+                hi->devnull_id = devnull_c->id;
         }
     }
 
-    devnull = hi->devnull ? hi->devnull : user_find_message(user, "MSG_NONE");
-    send_message(user, nickserv, "NSMSG_SET_DEVNULL", devnull);
-    return 1;
-}
-
-void nickserv_devnull_delete(char *name) {
-    dict_iterator_t it;
-    struct handle_info *hi;
-
-    for (it = dict_first(nickserv_handle_dict); it; it = iter_next(it)) {
-        hi = iter_data(it);
-        if (hi->devnull && !irccasecmp(name, hi->devnull)) {
-            free(hi->devnull);
-            hi->devnull = NULL;
+    if(hi->devnull_id) {
+        devnull_c = devnull_find_id(hi->devnull_id);
+        if(devnull_c)
+            devnull_name = devnull_c->name;
+        else {
+            devnull_name = user_find_message(user, "MSG_NONE");
+            hi->devnull_id = 0;
         }
-    }
+    } else
+        devnull_name = user_find_message(user, "MSG_NONE");
+    send_message(user, nickserv, "NSMSG_SET_DEVNULL", devnull_name);
+    return 1;
 }
 
-void nickserv_devnull_rename(char *oldname, char *newname) {
+void nickserv_devnull_delete(unsigned int devnull_id) {
     dict_iterator_t it;
     struct handle_info *hi;
 
     for (it = dict_first(nickserv_handle_dict); it; it = iter_next(it)) {
         hi = iter_data(it);
-        if (hi->devnull && !irccasecmp(oldname, hi->devnull)) {
-            hi->devnull = strdup(newname);
+        if (hi->devnull_id == devnull_id) {
+            hi->devnull_id = 0;
         }
     }
 }
@@ -2947,6 +2966,24 @@ oper_try_set_access(struct userNode *user, struct userNode *bot, struct handle_i
     return 1;
 }
 
+int
+oper_try_set_staff_access(struct userNode *user, struct userNode *bot, struct handle_info *target, unsigned int new_level) {
+    if (!oper_has_access(user, bot, nickserv_conf.modstaff_level, 0))
+        return 0;
+    if ((user->handle_info->opserv_level < target->opserv_level)
+        || ((user->handle_info->opserv_level == target->opserv_level)
+            && (user->handle_info->opserv_level < 1000))) {
+        send_message(user, bot, "MSG_USER_OUTRANKED", target->handle);
+        return 0;
+    }
+    if (target->staff_level == new_level)
+        return 0;
+    log_module(NS_LOG, LOG_INFO, "Account %s setting staff level for account %s to %d (from %d).",
+        user->handle_info->handle, target->handle, new_level, target->staff_level);
+    target->staff_level = new_level;
+    return 1;
+}
+
 static OPTION_FUNC(opt_level)
 {
     int res;
@@ -2961,6 +2998,20 @@ static OPTION_FUNC(opt_level)
     return res;
 }
 
+static OPTION_FUNC(opt_staff_level)
+{
+    int res;
+
+    if (!override) {
+        send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]);
+        return 0;
+    }
+
+    res = (argc > 1) ? oper_try_set_staff_access(user, nickserv, hi, strtoul(argv[1], NULL, 0)) : 0;
+    send_message(user, nickserv, "NSMSG_SET_STAFFLEVEL", hi->staff_level);
+    return res;
+}
+
 static OPTION_FUNC(opt_epithet)
 {
     if (!override) {
@@ -3444,8 +3495,8 @@ nickserv_saxdb_write(struct saxdb_context *ctx) {
         saxdb_write_int(ctx, KEY_ID, hi->id);
         if (hi->infoline)
             saxdb_write_string(ctx, KEY_INFO, hi->infoline);
-        if (hi->devnull)
-            saxdb_write_string(ctx, KEY_DEVNULL, hi->devnull);
+        if (hi->devnull_id)
+            saxdb_write_int(ctx, KEY_DEVNULL, hi->devnull_id);
         if (hi->website)
             saxdb_write_string(ctx, KEY_WEBSITE, hi->website);
         if (hi->last_quit_host[0])
@@ -3469,6 +3520,8 @@ nickserv_saxdb_write(struct saxdb_context *ctx) {
         }
         if (hi->opserv_level)
             saxdb_write_int(ctx, KEY_OPSERV_LEVEL, hi->opserv_level);
+        if (hi->staff_level)
+            saxdb_write_int(ctx, KEY_STAFF_LEVEL, hi->staff_level);
         if (hi->language != lang_C)
             saxdb_write_string(ctx, KEY_LANGUAGE, hi->language->name);
         saxdb_write_string(ctx, KEY_PASSWD, hi->passwd);
@@ -3613,6 +3666,10 @@ static NICKSERV_FUNC(cmd_merge)
     if (hi_from->opserv_level > hi_to->opserv_level)
         hi_to->opserv_level = hi_from->opserv_level;
 
+    /* Do they get a staff level promotion? */
+    if (hi_from->staff_level > hi_to->staff_level)
+        hi_to->staff_level = hi_from->staff_level;
+
     /* What about last seen time? */
     if (hi_from->lastseen > hi_to->lastseen)
         hi_to->lastseen = hi_from->lastseen;
@@ -3668,9 +3725,10 @@ struct nickserv_discrim {
     const char *fakehostmask;
     const char *fakeidentmask;
     const char *website;
-    const char *devnullclass;
     const char *handlemask;
     const char *emailmask;
+    const char *devnull_name;
+    unsigned int devnull_id;
 };
 
 typedef void (*discrim_search_func)(struct userNode *source, struct handle_info *hi, struct nickserv_discrim *discrim);
@@ -3816,9 +3874,16 @@ nickserv_discrim_create(struct userNode *user, unsigned int argc, char *argv[])
             }
         } else if (!irccasecmp(argv[i], "devnull")) {
             if (!irccasecmp(argv[++i], "*")) {
-                discrim->devnullclass = 0;
+                discrim->devnull_id = 0;
+                discrim->devnull_name = 0;
             } else {
-                discrim->devnullclass = argv[i];
+                struct devnull_class *th = devnull_find_name(argv[i]);
+                if(!th) {
+                    send_message(user, nickserv, "OSMSG_DEVNULL_NOTFOUND", argv[i]);
+                    goto fail;
+                }
+                discrim->devnull_name = argv[i];
+                discrim->devnull_id = th->id;
             }
         } else if (!irccasecmp(argv[i], "handlemask") || !irccasecmp(argv[i], "accountmask")) {
             if (!irccasecmp(argv[++i], "*")) {
@@ -3897,7 +3962,7 @@ nickserv_discrim_match(struct nickserv_discrim *discrim, struct handle_info *hi)
         || (discrim->fakehostmask && (!hi->fakehost || !match_ircglob(hi->fakehost, discrim->fakehostmask)))
         || (discrim->fakeidentmask && (!hi->fakeident || !match_ircglob(hi->fakeident, discrim->fakeidentmask)))
         || (discrim->website && (!hi->website || !match_ircglob(hi->website, discrim->website)))
-        || (discrim->devnullclass && (!hi->devnull || !match_ircglob(hi->devnull, discrim->devnullclass)))
+        || (discrim->devnull_id && discrim->devnull_id != hi->devnull_id)
         || (discrim->emailmask && (!hi->email_addr || !match_ircglob(hi->email_addr, discrim->emailmask)))
         || (discrim->min_level > hi->opserv_level)
         || (discrim->max_level < hi->opserv_level)
@@ -3981,9 +4046,14 @@ search_print_func(struct userNode *source, struct handle_info *match, struct nic
                 discrim->output_table->contents[discrim->output_table_pos][i++] = (match->fakehost ? match->fakehost : "*");
             if(discrim->show_fields & NICKSERV_DISCRIM_FIELDS_WEBSITE)
                 discrim->output_table->contents[discrim->output_table_pos][i++] = (match->website ? match->website : "*");
-            if(discrim->show_fields & NICKSERV_DISCRIM_FIELDS_DEVNULL)
-                discrim->output_table->contents[discrim->output_table_pos][i++] = (match->devnull ? match->devnull : "*");
-            
+            if(discrim->show_fields & NICKSERV_DISCRIM_FIELDS_DEVNULL) {
+                if(discrim->devnull_name) 
+                    discrim->output_table->contents[discrim->output_table_pos][i++] = discrim->devnull_name;
+                else {
+                    struct devnull_class *devnull = devnull_find_id(match->devnull_id);
+                    discrim->output_table->contents[discrim->output_table_pos][i++] = (devnull ? devnull->name : "*");
+                }
+            }
         }
     } else
         send_message(source, nickserv, "NSMSG_SEARCH_MATCH", match->handle);
@@ -4259,6 +4329,8 @@ nickserv_db_read_handle(const char *handle, dict_t obj)
     hi->language = language_find(str ? str : "C");
     str = database_get_data(obj, KEY_OPSERV_LEVEL, RECDB_QSTRING);
     hi->opserv_level = str ? strtoul(str, NULL, 0) : 0;
+    str = database_get_data(obj, KEY_STAFF_LEVEL, RECDB_QSTRING);
+    hi->staff_level = str ? strtoul(str, NULL, 0) : 0;
     str = database_get_data(obj, KEY_INFO, RECDB_QSTRING);
     if (str)
         hi->infoline = strdup(str);
@@ -4266,8 +4338,7 @@ nickserv_db_read_handle(const char *handle, dict_t obj)
     if (str)
         hi->website = strdup(str);
     str = database_get_data(obj, KEY_DEVNULL, RECDB_QSTRING);
-    if (str)
-        hi->devnull = strdup(str);
+    hi->devnull_id = str ? strtoul(str, NULL, 0) : 0;
     str = database_get_data(obj, KEY_REGISTER_ON, RECDB_QSTRING);
     hi->registered = str ? strtoul(str, NULL, 0) : now;
     str = database_get_data(obj, KEY_LAST_SEEN, RECDB_QSTRING);
@@ -4547,6 +4618,8 @@ nickserv_conf_read(void)
     nickserv_conf.db_backup_frequency = str ? ParseInterval(str) : 7200;
     str = database_get_data(conf_node, KEY_MODOPER_LEVEL, RECDB_QSTRING);
     nickserv_conf.modoper_level = str ? strtoul(str, NULL, 0) : 900;
+    str = database_get_data(conf_node, KEY_MODSTAFF_LEVEL, RECDB_QSTRING);
+    nickserv_conf.modstaff_level = str ? strtoul(str, NULL, 0) : 800;
     str = database_get_data(conf_node, KEY_SET_EPITHET_LEVEL, RECDB_QSTRING);
     nickserv_conf.set_epithet_level = str ? strtoul(str, NULL, 0) : 1;
     str = database_get_data(conf_node, KEY_SET_TITLE_LEVEL, RECDB_QSTRING);
@@ -4704,19 +4777,18 @@ check_user_nick(struct userNode *user) {
     //check if this user is a pending LOC user
     if(pendingLOCUsers) {
         struct pendingLOCUser *pending, *next, *prev = NULL;
+        int remove;
         for(pending = pendingLOCUsers; pending; pending = next) {
             next = pending->next;
+            remove = 0;
             if(user->handle_info == pending->handle_info) {
                 pending->authlog->user = user;
                 free((char*) pending->authlog->hostmask);
                 pending->authlog->hostmask = generate_hostmask(user, GENMASK_USENICK|GENMASK_STRICT_IDENT|GENMASK_NO_HIDING|GENMASK_STRICT_HOST);
-                if(prev)
-                    prev->next = next;
-                else
-                    pendingLOCUsers = next;
-                free(pending);
-            }
-            if(now - pending->time > 10) {
+                remove = 1;
+            } else if(now - pending->time > 10)
+                remove = 1;
+            if(remove) {
                 if(prev)
                     prev->next = next;
                 else
@@ -4948,6 +5020,8 @@ init_nickserv(const char *nick)
     dict_insert(nickserv_opt_dict, "DEVNULL", opt_devnull);
     dict_insert(nickserv_opt_dict, "ACCESS", opt_level);
     dict_insert(nickserv_opt_dict, "LEVEL", opt_level);
+    dict_insert(nickserv_opt_dict, "STAFF", opt_staff_level);
+    dict_insert(nickserv_opt_dict, "STAFF_LEVEL", opt_staff_level);
     dict_insert(nickserv_opt_dict, "EPITHET", opt_epithet);
     if (titlehost_suffix) {
         dict_insert(nickserv_opt_dict, "TITLE", opt_title);