/* nickserv.c - Nick/authentication service
- * Copyright 2000-2004 srvx Development Team
+ * Copyright 2000-2006 srvx Development Team
*
* This file is part of srvx.
*
#include "modcmd.h"
#include "opserv.h" /* for gag_create(), opserv_bad_channel() */
#include "saxdb.h"
-#include "sendmail.h"
+#include "mail.h"
#include "timeq.h"
#ifdef HAVE_REGEX_H
-#include <regex.h>
+# include <regex.h>
+#else
+# include "rx/rxposix.h"
#endif
#define NICKSERV_CONF_NAME "services/nickserv"
{ "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_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", "Account information for $b%s$b:" },
{ "NSMSG_HANDLEINFO_ID", " Account ID: %lu" },
};
static void nickserv_reclaim(struct userNode *user, struct nick_info *ni, enum reclaim_action action);
static void nickserv_reclaim_p(void *data);
+static int nickserv_addmask(struct userNode *user, struct handle_info *hi, const char *mask);
static struct {
unsigned int disable_nicks : 1;
dict_insert(nickserv_nick_dict, ni->nick, ni);
}
-static void
-free_nick_info(void *vni)
-{
- struct nick_info *ni = vni;
- free(ni);
-}
-
static void
delete_nick(struct nick_info *ni)
{
{
unsigned int i, len;
unsigned int cnt_digits = 0, cnt_upper = 0, cnt_lower = 0;
+ int p;
+
len = strlen(pass);
if (len < nickserv_conf.password_min_length) {
if (user)
send_message(user, nickserv, "NSMSG_PASSWORD_ACCOUNT");
return 0;
}
- dict_find(nickserv_conf.weak_password_dict, pass, &i);
- if (i) {
+ dict_find(nickserv_conf.weak_password_dict, pass, &p);
+ if (p) {
if (user)
send_message(user, nickserv, "NSMSG_PASSWORD_DICTIONARY");
return 0;
snprintf(subject, sizeof(subject), fmt, netname);
fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
snprintf(body, sizeof(body), fmt, netname, cookie->cookie+COOKIELEN/2, nickserv->nick, self->name, hi->handle, COOKIELEN/2);
- sendmail(nickserv, hi, subject, body, 1);
+ mail_send(nickserv, hi, subject, body, 1);
fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle, COOKIELEN/2, hi->email_addr);
} else {
snprintf(subject, sizeof(subject), fmt, netname);
fmt = handle_find_message(hi, "NSEMAIL_EMAIL_VERIFY_BODY");
snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
- sendmail(nickserv, hi, subject, body, 1);
+ mail_send(nickserv, hi, subject, body, 1);
subject[0] = 0;
}
hi->email_addr = misc;
break;
}
if (subject[0])
- sendmail(nickserv, hi, subject, body, first_time);
+ mail_send(nickserv, hi, subject, body, first_time);
nickserv_bake_cookie(cookie);
}
static NICKSERV_FUNC(cmd_register)
{
+ irc_in_addr_t ip;
struct handle_info *hi;
const char *email_addr, *password;
int no_auth;
}
/* .. and that we are allowed to send to it. */
- if ((str = sendmail_prohibited_address(email_addr))) {
+ if ((str = mail_prohibited_address(email_addr))) {
reply("NSMSG_EMAIL_PROHIBITED", email_addr, str);
return 0;
}
string_list_append(hi->masks, strdup("*@*"));
} else {
string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
- if (user->ip.s_addr && user->hostname[strspn(user->hostname, "0123456789.")])
+ 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_make_cookie(user, hi, ACTIVATION, hi->passwd);
/* Set registering flag.. */
- user->modes |= FLAGS_REGISTERING;
+ user->modes |= FLAGS_REGISTERING;
return 1;
}
struct userNode *settee;
struct handle_info *hi;
- NICKSERV_MIN_PARMS(4);
+ NICKSERV_MIN_PARMS(3);
if (!is_valid_handle(argv[1])) {
reply("NSMSG_BAD_HANDLE", argv[1]);
return 0;
}
- if (strchr(argv[3], '@')) {
+ if (argc < 4) {
+ mask = NULL;
+ settee = NULL;
+ } else if (strchr(argv[3], '@')) {
mask = canonicalize_hostmask(strdup(argv[3]));
if (argc > 4) {
settee = GetUserH(argv[4]);
free(mask);
return 0;
}
- string_list_append(hi->masks, mask);
+ if (mask)
+ string_list_append(hi->masks, mask);
return 1;
}
struct do_not_register *dnr;
if ((dnr = chanserv_is_dnr(NULL, hi)))
reply("NSMSG_HANDLEINFO_DNR", dnr->setter, dnr->reason);
- if (!oper_outranks(user, hi))
+ if ((user->handle_info->opserv_level < 900) && !oper_outranks(user, hi))
return 1;
} else if (hi != user->handle_info)
return 1;
reply("NSMSG_WEAK_PASSWORD");
if (hi->passwd[0] != '$')
cryptpass(passwd, hi->passwd);
- reply("NSMSG_AUTH_SUCCESS");
+ 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));
+ 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));
+ }
argv[pw_arg] = "****";
+ reply("NSMSG_AUTH_SUCCESS");
return 1;
}
nickserv_set_email_addr(hi, hi->cookie->data);
reply("NSMSG_EMAIL_CHANGED");
break;
- case ALLOWAUTH:
+ case ALLOWAUTH: {
+ char *mask = generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT);
set_user_handle_info(user, hi, 1);
+ nickserv_addmask(user, hi, mask);
reply("NSMSG_AUTH_SUCCESS");
+ free(mask);
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);
}
static int
-nickserv_delmask(struct userNode *user, struct handle_info *hi, const char *del_mask)
+nickserv_delmask(struct userNode *user, struct handle_info *hi, const char *del_mask, int force)
{
unsigned int i;
for (i=0; i<hi->masks->used; i++) {
if (!strcmp(del_mask, hi->masks->list[i])) {
char *old_mask = hi->masks->list[i];
- if (hi->masks->used == 1) {
+ if (hi->masks->used == 1 && !force) {
send_message(user, nickserv, "NSMSG_DELMASK_NOTLAST");
return 0;
}
static NICKSERV_FUNC(cmd_delmask)
{
NICKSERV_MIN_PARMS(2);
- return nickserv_delmask(user, user->handle_info, argv[1]);
+ return nickserv_delmask(user, user->handle_info, argv[1], 0);
}
static NICKSERV_FUNC(cmd_odelmask)
NICKSERV_MIN_PARMS(3);
if (!(hi = get_victim_oper(user, argv[1])))
return 0;
- return nickserv_delmask(user, hi, argv[2]);
+ return nickserv_delmask(user, hi, argv[2], 1);
}
int
send_message(user, nickserv, "NSMSG_BAD_EMAIL_ADDR");
return 0;
}
- if ((str = sendmail_prohibited_address(argv[1]))) {
+ if ((str = mail_prohibited_address(argv[1]))) {
send_message(user, nickserv, "NSMSG_EMAIL_PROHIBITED", argv[1], str);
return 0;
}
send_message(user, nickserv, "NSMSG_TITLE_INVALID");
return 0;
}
+ if ((strlen(user->handle_info->handle) + strlen(title) +
+ strlen(nickserv_conf.titlehost_suffix) + 2) > HOSTLEN) {
+ send_message(user, nickserv, "NSMSG_TITLE_TRUNCATED");
+ return 0;
+ }
+
free(hi->fakehost);
if (!strcmp(title, "*")) {
hi->fakehost = NULL;
if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_fakehost_level, 0)) {
fake = argv[1];
if ((strlen(fake) > HOSTLEN) || (fake[0] == '.')) {
- send_message(user, nickserv, "NSMSG_FAKEHOST_INVALID");
+ send_message(user, nickserv, "NSMSG_FAKEHOST_INVALID", HOSTLEN);
return 0;
}
free(hi->fakehost);
reply("NSMSG_NICK_NOT_REGISTERED", argv[1]);
return 0;
}
- if (ni->owner->opserv_level >= user->handle_info->opserv_level) {
- reply("MSG_USER_OUTRANKED", ni->nick);
- return 0;
- }
+ if (!oper_outranks(user, ni->owner))
+ return 0;
reply("NSMSG_UNREGNICK_SUCCESS", ni->nick);
delete_nick(ni);
return 1;
static NICKSERV_FUNC(cmd_ounregister)
{
struct handle_info *hi;
+ char reason[MAXLEN];
NICKSERV_MIN_PARMS(2);
if (!(hi = get_victim_oper(user, argv[1])))
return 0;
+ snprintf(reason, sizeof(reason), "%s unregistered account %s.", user->handle_info->handle, hi->handle);
+ global_message(MESSAGE_RECIPIENT_STAFF, reason);
nickserv_unregister_handle(hi, user);
- return 0;
+ return 1;
}
static NICKSERV_FUNC(cmd_status)
if (hi_from->lastseen > hi_to->lastseen)
hi_to->lastseen = hi_from->lastseen;
+ /* Does a fakehost carry over? (This intentionally doesn't set it
+ * for users previously attached to hi_to. They'll just have to
+ * reconnect.)
+ */
+ if (hi_from->fakehost && !hi_to->fakehost)
+ 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);
struct string_list *masks, *slist;
struct handle_info *hi;
struct userNode *authed_users;
+ struct userData *channels;
unsigned long int id;
unsigned int ii;
dict_t subdb;
}
if ((hi = get_handle_info(handle))) {
authed_users = hi->users;
+ channels = hi->channels;
hi->users = NULL;
+ hi->channels = NULL;
dict_remove(nickserv_handle_dict, hi->handle);
} else {
authed_users = NULL;
+ channels = NULL;
}
hi = register_handle(handle, str, id);
if (authed_users) {
authed_users = authed_users->next_authed;
}
}
+ hi->channels = channels;
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);
break;
case RECLAIM_KILL:
msg = user_find_message(user, "NSMSG_RECLAIM_KILL");
- irc_kill(nickserv, user, msg);
+ DelUser(user, nickserv, 1, msg);
break;
}
}
nickserv_define_func("USERINFO", cmd_userinfo, -1, 1, 0);
nickserv_define_func("RENAME", cmd_rename_handle, -1, 1, 0);
nickserv_define_func("VACATION", cmd_vacation, -1, 1, 0);
- nickserv_define_func("MERGE", cmd_merge, 0, 1, 0);
+ nickserv_define_func("MERGE", cmd_merge, 750, 1, 0);
if (!nickserv_conf.disable_nicks) {
/* nick management commands */
nickserv_define_func("REGNICK", cmd_regnick, -1, 1, 0);
dict_set_free_keys(nickserv_id_dict, free);
nickserv_nick_dict = dict_new();
- dict_set_free_data(nickserv_nick_dict, free_nick_info);
+ dict_set_free_data(nickserv_nick_dict, free);
nickserv_allow_auth_dict = dict_new();
userList_init(&curr_helpers);
if (nick) {
- nickserv = AddService(nick, "Nick Services", NULL);
+ const char *modes = conf_get_data("services/nickserv/modes", RECDB_QSTRING);
+ nickserv = AddLocalUser(nick, nick, NULL, "Nick Services", modes);
nickserv_service = service_register(nickserv);
}
saxdb_register("NickServ", nickserv_saxdb_read, nickserv_saxdb_write);