]> jfr.im git - irc/evilnet/x3.git/blame_incremental - src/nickserv.c
Extended channel ban support. As well as text and nick change bans, however these...
[irc/evilnet/x3.git] / src / nickserv.c
... / ...
CommitLineData
1/* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
3 *
4 * This file is part of x3.
5 *
6 * x3 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 */
20
21#include "chanserv.h"
22#include "conf.h"
23#include "config.h"
24#include "global.h"
25#include "modcmd.h"
26#include "opserv.h" /* for gag_create(), opserv_bad_channel() */
27#include "saxdb.h"
28#include "mail.h"
29#include "timeq.h"
30#include "x3ldap.h"
31
32#include <tre/regex.h>
33
34#ifdef WITH_LDAP
35#include <ldap.h>
36#endif
37
38#define NICKSERV_CONF_NAME "services/nickserv"
39
40#define KEY_DISABLE_NICKS "disable_nicks"
41#define KEY_DEFAULT_HOSTMASK "default_hostmask"
42#define KEY_NICKS_PER_HANDLE "nicks_per_handle"
43#define KEY_NICKS_PER_ACCOUNT "nicks_per_account"
44#define KEY_PASSWORD_MIN_LENGTH "password_min_length"
45#define KEY_PASSWORD_MIN_DIGITS "password_min_digits"
46#define KEY_PASSWORD_MIN_UPPER "password_min_upper"
47#define KEY_PASSWORD_MIN_LOWER "password_min_lower"
48#define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
49#define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
50#define KEY_VALID_NICK_REGEX "valid_nick_regex"
51#define KEY_VALID_FAKEHOST_REGEX "valid_fakehost_regex"
52#define KEY_DB_BACKUP_FREQ "db_backup_freq"
53#define KEY_MODOPER_LEVEL "modoper_level"
54#define KEY_SET_EPITHET_LEVEL "set_epithet_level"
55#define KEY_SET_TITLE_LEVEL "set_title_level"
56#define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
57#define KEY_DENIED_FAKEHOST_WORDS "denied_fakehost_words"
58#define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
59#define KEY_AUTO_OPER "auto_oper"
60#define KEY_AUTO_ADMIN "auto_admin"
61#define KEY_FLAG_LEVELS "flag_levels"
62#define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
63#define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
64#define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
65#define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
66#define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
67#define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
68#define KEY_DICT_FILE "dict_file"
69#define KEY_NICK "nick"
70#define KEY_LANGUAGE "language"
71#define KEY_AUTOGAG_ENABLED "autogag_enabled"
72#define KEY_AUTOGAG_DURATION "autogag_duration"
73#define KEY_AUTH_POLICER "auth_policer"
74#define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
75#define KEY_EMAIL_ENABLED "email_enabled"
76#define KEY_EMAIL_REQUIRED "email_required"
77#define KEY_SYNC_LOG "sync_log"
78#define KEY_COOKIE_TIMEOUT "cookie_timeout"
79#define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
80#define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
81#define KEY_DEFAULT_STYLE "default_style"
82#define KEY_OUNREGISTER_INACTIVE "ounregister_inactive"
83#define KEY_OUNREGISTER_FLAGS "ounregister_flags"
84
85#define KEY_ID "id"
86#define KEY_PASSWD "passwd"
87#define KEY_NICKS "nicks"
88#define KEY_MASKS "masks"
89#define KEY_IGNORES "ignores"
90#define KEY_OPSERV_LEVEL "opserv_level"
91#define KEY_FLAGS "flags"
92#define KEY_REGISTER_ON "register"
93#define KEY_LAST_SEEN "lastseen"
94#define KEY_INFO "info"
95#define KEY_USERLIST_STYLE "user_style"
96#define KEY_SCREEN_WIDTH "screen_width"
97#define KEY_LAST_AUTHED_HOST "last_authed_host"
98#define KEY_LAST_QUIT_HOST "last_quit_host"
99#define KEY_EMAIL_ADDR "email_addr"
100#define KEY_COOKIE "cookie"
101#define KEY_COOKIE_DATA "data"
102#define KEY_COOKIE_TYPE "type"
103#define KEY_COOKIE_EXPIRES "expires"
104#define KEY_ACTIVATION "activation"
105#define KEY_PASSWORD_CHANGE "password change"
106#define KEY_EMAIL_CHANGE "email change"
107#define KEY_ALLOWAUTH "allowauth"
108#define KEY_EPITHET "epithet"
109#define KEY_TABLE_WIDTH "table_width"
110#define KEY_ANNOUNCEMENTS "announcements"
111#define KEY_MAXLOGINS "maxlogins"
112#define KEY_FAKEHOST "fakehost"
113#define KEY_NOTE_NOTE "note"
114#define KEY_NOTE_SETTER "setter"
115#define KEY_NOTE_DATE "date"
116#define KEY_KARMA "karma"
117#define KEY_FORCE_HANDLES_LOWERCASE "force_handles_lowercase"
118
119#define KEY_LDAP_ENABLE "ldap_enable"
120
121#ifdef WITH_LDAP
122#define KEY_LDAP_URI "ldap_uri"
123#define KEY_LDAP_BASE "ldap_base"
124#define KEY_LDAP_DN_FMT "ldap_dn_fmt"
125#define KEY_LDAP_VERSION "ldap_version"
126#define KEY_LDAP_AUTOCREATE "ldap_autocreate"
127#define KEY_LDAP_ADMIN_DN "ldap_admin_dn"
128#define KEY_LDAP_ADMIN_PASS "ldap_admin_pass"
129#define KEY_LDAP_FIELD_ACCOUNT "ldap_field_account"
130#define KEY_LDAP_FIELD_PASSWORD "ldap_field_password"
131#define KEY_LDAP_FIELD_EMAIL "ldap_field_email"
132#define KEY_LDAP_OBJECT_CLASSES "ldap_object_classes"
133#define KEY_LDAP_OPER_GROUP_DN "ldap_oper_group_dn"
134#define KEY_LDAP_OPER_GROUP_LEVEL "ldap_oper_group_level"
135#define KEY_LDAP_FIELD_GROUP_MEMBER "ldap_field_group_member"
136#define KEY_LDAP_TIMEOUT "ldap_timeout"
137#endif
138
139#define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
140
141#define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
142#define OPTION_FUNC(NAME) int NAME(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
143typedef OPTION_FUNC(option_func_t);
144
145DEFINE_LIST(handle_info_list, struct handle_info*)
146
147#define NICKSERV_MIN_PARMS(N) do { \
148 if (argc < N) { \
149 reply("MSG_MISSING_PARAMS", argv[0]); \
150 svccmd_send_help_brief(user, nickserv, cmd); \
151 return 0; \
152 } } while (0)
153
154struct userNode *nickserv;
155struct userList curr_helpers;
156const char *handle_flags = HANDLE_FLAGS;
157
158extern struct string_list *autojoin_channels;
159static struct module *nickserv_module;
160static struct service *nickserv_service;
161static struct log_type *NS_LOG;
162static dict_t nickserv_handle_dict; /* contains struct handle_info* */
163static dict_t nickserv_id_dict; /* contains struct handle_info* */
164static dict_t nickserv_nick_dict; /* contains struct nick_info* */
165static dict_t nickserv_opt_dict; /* contains option_func_t* */
166static dict_t nickserv_allow_auth_dict; /* contains struct handle_info* */
167static dict_t nickserv_email_dict; /* contains struct handle_info_list*, indexed by email addr */
168static char handle_inverse_flags[256];
169static unsigned int flag_access_levels[32];
170static const struct message_entry msgtab[] = {
171 { "NSMSG_NO_ANGLEBRACKETS", "The < and > in help indicate that that word is a required parameter, but DO NOT actually type them in messages to me." },
172 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
173 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu characters or less."},
174 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
175 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
176 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
177 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
178 { "NSMSG_LDAP_FAIL", "There was a problem in contacting the account server (ldap): %s. Please try again later." },
179 { "NSMSG_LDAP_FAIL_ADD", "There was a problem in adding account %s to ldap: %s." },
180 { "NSMSG_LDAP_FAIL_SEND_EMAIL", "There was a problem in storing your email address in the account server (ldap): %s. Please try again later." },
181 { "NSMSG_LDAP_FAIL_GET_EMAIL", "There was a problem in retrieving your email address from the account server (ldap): %s. Please try again later." },
182 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
183 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
184 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
185 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
186 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
187 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
188 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
189 { "NSMSG_USE_COOKIE_REGISTER", "To activate your account, you must check your email for the \"cookie\" that has been mailed to it. When you have it, use the $bcookie$b command to complete registration." },
190 { "NSMSG_USE_COOKIE_RESETPASS", "A cookie has been mailed to your account's email address. You must check your email and use the $bcookie$b command to confirm the password change." },
191 { "NSMSG_USE_COOKIE_EMAIL_1", "A cookie has been mailed to the new address you requested. To finish setting your email address, please check your email for the cookie and use the $bcookie$b command to verify." },
192 { "NSMSG_USE_COOKIE_EMAIL_2", "A cookie has been generated, and half mailed to each your old and new addresses. To finish changing your email address, please check your email for the cookie and use the $bcookie$b command to verify." },
193 { "NSMSG_USE_COOKIE_AUTH", "A cookie has been generated and sent to your email address. Once you have checked your email and received the cookie, auth using the $bcookie$b command." },
194 { "NSMSG_COOKIE_LIVE", "Account $b%s$b already has a cookie active. Please either finish using that cookie, wait for it to expire, or auth to the account and use the $bdelcookie$b command." },
195 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
196 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
197 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
198 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
199 { "NSMSG_BAD_COOKIE", "That cookie is not the right one. Please make sure you are copying it EXACTLY from the email; it is case-sensitive, so $bABC$b is different from $babc$b." },
200 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
201 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
202 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
203 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
204 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
205 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
206 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
207 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
208 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
209 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
210 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
211 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
212 { "NSMSG_REGISTER_BAD_NICKMASK", "You must provide a hostmask, or online nick to generate one automatically. (or set a default hostmask in the config such as *@*)." },
213 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
214 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
215 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
216 { "NSMSG_USE_AUTHCOOKIE", "Your hostmask is not valid for account $b%1$s$b. Please use the $bauthcookie$b command to grant yourself access. (/msg $S authcookie %1$s)" },
217 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
218 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
219 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
220 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
221 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
222 { "NSMSG_BAD_ADVANCED", "Advanced must be either 1 to enable it or 0 to disable it." },
223 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
224 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
225 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
226 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
227 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
228 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
229 { "NSMSG_TITLE_INVALID", "Titles may contain only a-z, A-Z, 0-9, and '-'. Please choose another." },
230 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
231 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
232 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
233 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
234 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
235 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
236 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
237 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
238 { "NSMSG_HANDLEINFO_KARMA", " Karma: %d" },
239 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
240 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
241 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
242 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
243 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
244 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
245 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
246 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
247 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
248 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
249 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
250 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
251 { "NSMSG_INVALID_KARMA", "$b%s$b is not a valid karma modifier." },
252 { "NSMSG_SET_KARMA", "$bKARMA: $b%d$b" },
253 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
254 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
255 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
256 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
257 { "NSMSG_HANDLEINFO_IGNORES", "Ignore(s): %s" },
258 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
259 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
260 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
261 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
262 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
263 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
264 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
265 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
266 { "NSMSG_WEAK_PASSWORD", "WARNING: You are using a password that is considered weak (easy to guess). It is STRONGLY recommended you change it (now, if not sooner) by typing \"/msg $S@$s PASS oldpass newpass\" (with your current password and a new password)." },
267 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
268 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
269 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
270 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
271 { "NSMSG_AUTH_ALLOWED_MSG", "You may now authenticate to account $b%s$b by typing $b/msg $N@$s auth %s password$b (using your password). If you will be using this computer regularly, please type $b/msg $N addmask$b (AFTER you auth) to permanently add your hostmask." },
272 { "NSMSG_AUTH_ALLOWED_EMAIL", "You may also (after you auth) type $b/msg $N set email user@your.isp$b to set an email address. This will let you use the $bauthcookie$b command to be authenticated in the future." },
273 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
274 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
275 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
276 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
277 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
278 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
279 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
280 { "NSMSG_PASS_SUCCESS", "Password changed." },
281 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
282 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
283 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
284 { "NSMSG_ADDIGNORE_ALREADY", "$b%s$b is already an ignored hostmask in your account." },
285 { "NSMSG_ADDIGNORE_SUCCESS", "Hostmask %s added." },
286 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
287 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
288 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
289 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
290 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
291 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
292 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
293 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
294 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
295 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
296 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
297 { "NSMSG_UNREGISTER_MUST_FORCE", "Account $b%s$b is not inactive or has special flags set; use FORCE to unregister it." },
298 { "NSMSG_UNREGISTER_CANNOT_FORCE", "Account $b%s$b is not inactive or has special flags set; have an IRCOp use FORCE to unregister it." },
299 { "NSMSG_UNREGISTER_NODELETE", "Account $b%s$b is protected from unregistration." },
300 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
301 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
302 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
303 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
304 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
305 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
306 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
307 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
308 { "NSMSG_NO_ACCESS", "Access denied." },
309 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
310 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
311 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
312 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
313 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T".%03lu seconds)." },
314 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
315 { "NSMSG_BAD_HANDLE", "Account $b%s$b is not allowed because it is reserved, is too long, or contains invalid characters." },
316 { "NSMSG_BAD_NICK", "Nickname $b%s$b not registered because it is in use by a network service, is too long, or contains invalid characters." },
317 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
318 { "NSMSG_FAIL_RENAME", "Account $b%s$b not renamed to $b%s$b because it is in use by a network services, or contains invalid characters." },
319 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
320 { "NSMSG_SEARCH_MATCH", "Match: %s" },
321 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
322 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
323 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
324 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
325 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
326 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
327 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
328 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
329 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
330 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
331 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
332 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
333 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
334 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
335 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
336 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
337 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
338 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
339 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
340 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
341 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
342 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
343 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
344 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
345 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
346 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
347 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
348 { "NSMSG_SET_ADVANCED", "$bADVANCED: $b%s" },
349 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
350 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
351 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
352 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
353 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
354 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
355
356 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
357 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
358
359 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
360 { "NSEMAIL_ACTIVATION_BODY",
361 "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n"
362 "%2$s\n"
363 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
364 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
365 "This command is only used once to complete your account registration, and never again. Once you have run this command, you will need to authenticate everytime you reconnect to the network. To do this, you will have to type this command every time you reconnect:\n"
366 "/msg %3$s@%4$s AUTH %5$s your-password\n"
367 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
368 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
369 "\n"
370 "If you did NOT request this account, you do not need to do anything.\n"
371 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
372 { "NSEMAIL_ACTIVATION_BODY_WEB",
373 "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n"
374 "%2$s\n"
375 "To verify your email address and complete the account registration, visit the following URL:\n"
376 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
377 "\n"
378 "If you did NOT request this account, you do not need to do anything.\n"
379 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
380 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
381 { "NSEMAIL_PASSWORD_CHANGE_BODY",
382 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
383 "To complete the password change, log on to %1$s and type the following command:\n"
384 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
385 "If you did NOT request your password to be changed, you do not need to do anything.\n"
386 "Please contact the %1$s staff if you have questions." },
387 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
388 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
389 "To complete the password change, click the following URL:\n"
390 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
391 "If you did NOT request your password to be changed, you do not need to do anything.\n"
392 "Please contact the %1$s staff if you have questions." },
393 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
394#ifdef stupid_verify_old_email
395 { "NSEMAIL_EMAIL_CHANGE_BODY_NEW", "This email has been sent to verify that your email address belongs to the same person as account %5$s on %1$s. The SECOND HALF of your cookie is %2$.*6$s.\nTo verify your address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s ?????%2$.*6$s\n(Replace the ????? with the FIRST HALF of the cookie, as sent to your OLD email address.)\nIf you did NOT request this email address to be associated with this account, you do not need to do anything. Please contact the %1$s staff if you have questions." },
396 { "NSEMAIL_EMAIL_CHANGE_BODY_OLD", "This email has been sent to verify that you want to change your email for account %5$s on %1$s from this address to %7$s. The FIRST HALF of your cookie is %2$.*6$s\nTo verify your new address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$.*6$s?????\n(Replace the ????? with the SECOND HALF of the cookie, as sent to your NEW email address.)\nIf you did NOT request this change of email address, you do not need to do anything. Please contact the %1$s staff if you have questions." },
397#endif
398 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
399 { "NSEMAIL_EMAIL_VERIFY_BODY", "This email has been sent to verify that this address belongs to the same person as %5$s on %1$s. Your cookie is %2$s.\nTo verify your address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nIf you did NOT request this email address to be associated with this account, you do not need to do anything. Please contact the %1$s staff if you have questions." },
400 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
401 { "NSEMAIL_ALLOWAUTH_BODY", "This email has been sent to let you authenticate (auth) to account %5$s on %1$s. Your cookie is %2$s.\nTo auth to that account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nIf you did NOT request this authorization, you do not need to do anything. Please contact the %1$s staff if you have questions." },
402 { "NSMSG_NOT_VALID_FAKEHOST_DOT", "$b%s$b is not a valid vhost. (needs at least one dot)" },
403 { "NSMSG_NOT_VALID_FAKEHOST_AT", "$b%s$b is not a valid vhost. (it can not have a '@')" },
404 { "NSMSG_DENIED_FAKEHOST_WORD", "Access denied because there's a prohibited word in $b%s$b (%s)." },
405 { "NSMSG_NOT_VALID_FAKEHOST_LEN", "$b%s$b is not a valid vhost. (can only be 63 characters)" },
406 { "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", "$b%s$b is not a valid vhost. (TLD can only be 4 characters and less)" },
407 { "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." },
408 { "CHECKPASS_YES", "Yes." },
409 { "CHECKPASS_NO", "No." },
410 { "CHECKEMAIL_NOT_SET", "No email set." },
411 { "CHECKEMAIL_YES", "Yes." },
412 { "CHECKEMAIL_NO", "No." },
413 { "NSMSG_DEFCON_NO_NEW_NICKS", "You cannot register new %s at this time, please try again soon" },
414 { NULL, NULL }
415};
416
417static void nickserv_reclaim(struct userNode *user, struct nick_info *ni, enum reclaim_action action);
418static void nickserv_reclaim_p(void *data);
419static int nickserv_addmask(struct userNode *user, struct handle_info *hi, const char *mask);
420
421struct nickserv_config nickserv_conf;
422
423/* We have 2^32 unique account IDs to use. */
424unsigned long int highest_id = 0;
425
426static char *
427canonicalize_hostmask(char *mask)
428{
429 char *out = mask, *temp;
430 if ((temp = strchr(mask, '!'))) {
431 temp++;
432 while (*temp) *out++ = *temp++;
433 *out++ = 0;
434 }
435 return mask;
436}
437
438static struct handle_note *
439nickserv_add_note(const char *setter, time_t date, const char *text)
440{
441 struct handle_note *note = calloc(1, sizeof(*note) + strlen(text));
442
443 strncpy(note->setter, setter, sizeof(note->setter)-1);
444 note->date = date;
445 memcpy(note->note, text, strlen(text));
446 return note;
447}
448
449static struct handle_info *
450register_handle(const char *handle, const char *passwd, UNUSED_ARG(unsigned long id))
451{
452 struct handle_info *hi;
453
454 hi = calloc(1, sizeof(*hi));
455 hi->userlist_style = nickserv_conf.default_style ? nickserv_conf.default_style : HI_DEFAULT_STYLE;
456 hi->announcements = '?';
457 hi->handle = strdup(handle);
458 safestrncpy(hi->passwd, passwd, sizeof(hi->passwd));
459 hi->infoline = NULL;
460 dict_insert(nickserv_handle_dict, hi->handle, hi);
461
462 return hi;
463}
464
465static void
466register_nick(const char *nick, struct handle_info *owner)
467{
468 struct nick_info *ni;
469 ni = malloc(sizeof(struct nick_info));
470 safestrncpy(ni->nick, nick, sizeof(ni->nick));
471 ni->owner = owner;
472 ni->next = owner->nicks;
473 owner->nicks = ni;
474 dict_insert(nickserv_nick_dict, ni->nick, ni);
475}
476
477static void
478delete_nick(struct nick_info *ni)
479{
480 struct nick_info *last, *next;
481 struct userNode *user;
482 /* Check to see if we should mark a user as unregistered. */
483 if ((user = GetUserH(ni->nick)) && IsReggedNick(user)) {
484 user->modes &= ~FLAGS_REGNICK;
485 irc_regnick(user);
486 }
487 /* Remove ni from the nick_info linked list. */
488 if (ni == ni->owner->nicks) {
489 ni->owner->nicks = ni->next;
490 } else {
491 last = ni->owner->nicks;
492 next = last->next;
493 while (next != ni) {
494 last = next;
495 next = last->next;
496 }
497 last->next = next->next;
498 }
499 dict_remove(nickserv_nick_dict, ni->nick);
500}
501
502static unreg_func_t *unreg_func_list;
503static unsigned int unreg_func_size = 0, unreg_func_used = 0;
504
505void
506reg_unreg_func(unreg_func_t func)
507{
508 if (unreg_func_used == unreg_func_size) {
509 if (unreg_func_size) {
510 unreg_func_size <<= 1;
511 unreg_func_list = realloc(unreg_func_list, unreg_func_size*sizeof(unreg_func_t));
512 } else {
513 unreg_func_size = 8;
514 unreg_func_list = malloc(unreg_func_size*sizeof(unreg_func_t));
515 }
516 }
517 unreg_func_list[unreg_func_used++] = func;
518}
519
520static void
521nickserv_free_cookie(void *data)
522{
523 struct handle_cookie *cookie = data;
524 if (cookie->hi) cookie->hi->cookie = NULL;
525 if (cookie->data) free(cookie->data);
526 free(cookie);
527}
528
529static void
530free_handle_info(void *vhi)
531{
532 struct handle_info *hi = vhi;
533
534 free_string_list(hi->masks);
535 free_string_list(hi->ignores);
536 assert(!hi->users);
537
538 while (hi->nicks)
539 delete_nick(hi->nicks);
540 free(hi->infoline);
541 free(hi->epithet);
542 free(hi->note);
543 free(hi->fakehost);
544 if (hi->cookie) {
545 timeq_del(hi->cookie->expires, nickserv_free_cookie, hi->cookie, 0);
546 nickserv_free_cookie(hi->cookie);
547 }
548 if (hi->email_addr) {
549 struct handle_info_list *hil = dict_find(nickserv_email_dict, hi->email_addr, NULL);
550 handle_info_list_remove(hil, hi);
551 if (!hil->used)
552 dict_remove(nickserv_email_dict, hi->email_addr);
553 }
554 free(hi);
555}
556
557static void set_user_handle_info(struct userNode *user, struct handle_info *hi, int stamp);
558
559static int
560nickserv_unregister_handle(struct handle_info *hi, struct userNode *notify, struct userNode *bot)
561{
562 unsigned int n;
563 struct userNode *uNode;
564
565#ifdef WITH_LDAP
566 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
567 int rc;
568 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
569 if( (rc = ldap_delete_account(hi->handle)) != LDAP_SUCCESS) {
570 if(notify) {
571 send_message(notify, bot, "NSMSG_LDAP_FAIL", ldap_err2string(rc));
572 }
573 if(rc != LDAP_NO_SUCH_OBJECT)
574 return false; /* if theres noone there to delete, its kinda ok, right ?:) */
575 }
576 }
577 }
578#endif
579 for (n=0; n<unreg_func_used; n++)
580 unreg_func_list[n](notify, hi);
581 while (hi->users) {
582 if (nickserv_conf.sync_log) {
583 uNode = GetUserH(hi->users->nick);
584 if (uNode)
585 irc_delete(uNode);
586 }
587 set_user_handle_info(hi->users, NULL, 0);
588 }
589 if (notify) {
590 if (nickserv_conf.disable_nicks)
591 send_message(notify, bot, "NSMSG_UNREGISTER_SUCCESS", hi->handle);
592 else
593 send_message(notify, bot, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi->handle);
594 }
595
596 if (nickserv_conf.sync_log)
597 SyncLog("UNREGISTER %s", hi->handle);
598
599 dict_remove(nickserv_handle_dict, hi->handle);
600 return true;
601}
602
603struct handle_info*
604get_handle_info(const char *handle)
605{
606 return dict_find(nickserv_handle_dict, handle, 0);
607}
608
609struct nick_info*
610get_nick_info(const char *nick)
611{
612 return nickserv_conf.disable_nicks ? 0 : dict_find(nickserv_nick_dict, nick, 0);
613}
614
615struct modeNode *
616find_handle_in_channel(struct chanNode *channel, struct handle_info *handle, struct userNode *except)
617{
618 unsigned int nn;
619 struct modeNode *mn;
620
621 for (nn=0; nn<channel->members.used; ++nn) {
622 mn = channel->members.list[nn];
623 if ((mn->user != except) && (mn->user->handle_info == handle))
624 return mn;
625 }
626 return NULL;
627}
628
629int
630oper_has_access(struct userNode *user, struct userNode *bot, unsigned int min_level, unsigned int quiet) {
631 if (!user->handle_info) {
632 if (!quiet)
633 send_message(user, bot, "MSG_AUTHENTICATE");
634 return 0;
635 }
636
637 if (!IsOper(user) && (!IsHelping(user) || min_level)) {
638 if (!quiet)
639 send_message(user, bot, "NSMSG_NO_ACCESS");
640 return 0;
641 }
642
643 if (HANDLE_FLAGGED(user->handle_info, OPER_SUSPENDED)) {
644 if (!quiet)
645 send_message(user, bot, "MSG_OPER_SUSPENDED");
646 return 0;
647 }
648
649 if (user->handle_info->opserv_level < min_level) {
650 if (!quiet)
651 send_message(user, bot, "NSMSG_NO_ACCESS");
652 return 0;
653 }
654
655 return 1;
656}
657
658static int
659is_valid_handle(const char *handle)
660{
661 struct userNode *user;
662 /* cant register a juped nick/service nick as handle, to prevent confusion */
663 user = GetUserH(handle);
664 if (user && IsLocal(user))
665 return 0;
666 /* check against maximum length */
667 if (strlen(handle) > NICKSERV_HANDLE_LEN)
668 return 0;
669 /* for consistency, only allow account names that could be nicks */
670 if (!is_valid_nick(handle))
671 return 0;
672 /* disallow account names that look like bad words */
673 if (opserv_bad_channel(handle))
674 return 0;
675 /* test either regex or containing all valid chars */
676 if (nickserv_conf.valid_handle_regex_set) {
677 int err = regexec(&nickserv_conf.valid_handle_regex, handle, 0, 0, 0);
678 if (err) {
679 char buff[256];
680 buff[regerror(err, &nickserv_conf.valid_handle_regex, buff, sizeof(buff))] = 0;
681 log_module(NS_LOG, LOG_INFO, "regexec error: %s (%d)", buff, err);
682 }
683 return !err;
684 } else {
685 return !handle[strspn(handle, NICKSERV_VALID_CHARS)];
686 }
687}
688
689static int
690is_registerable_nick(const char *nick)
691{
692 struct userNode *user;
693 /* cant register a juped nick/service nick as nick, to prevent confusion */
694 user = GetUserH(nick);
695 if (user && IsLocal(user))
696 return 0;
697 /* for consistency, only allow nicks names that could be nicks */
698 if (!is_valid_nick(nick))
699 return 0;
700 /* disallow nicks that look like bad words */
701 if (opserv_bad_channel(nick))
702 return 0;
703 /* check length */
704 if (strlen(nick) > NICKLEN)
705 return 0;
706 /* test either regex or as valid handle */
707 if (nickserv_conf.valid_nick_regex_set) {
708 int err = regexec(&nickserv_conf.valid_nick_regex, nick, 0, 0, 0);
709 if (err) {
710 char buff[256];
711 buff[regerror(err, &nickserv_conf.valid_nick_regex, buff, sizeof(buff))] = 0;
712 log_module(NS_LOG, LOG_INFO, "regexec error: %s (%d)", buff, err);
713 }
714 return !err;
715 }
716 return 1;
717}
718/* this has been replaced with one in tools.c
719
720static int
721is_valid_email_addr(const char *email)
722{
723 return strchr(email, '@') != NULL;
724}
725
726*/
727
728static const char *
729visible_email_addr(struct userNode *user, struct handle_info *hi)
730{
731 if (hi->email_addr) {
732 if (oper_has_access(user, nickserv, nickserv_conf.email_visible_level, 1)) {
733 return hi->email_addr;
734 } else {
735 return "Set.";
736 }
737 } else {
738 return "Not set.";
739 }
740}
741
742struct handle_info *
743smart_get_handle_info(struct userNode *service, struct userNode *user, const char *name)
744{
745 struct handle_info *hi;
746 struct userNode *target;
747
748 switch (*name) {
749 case '*':
750 if (!(hi = get_handle_info(++name))) {
751 send_message(user, service, "MSG_HANDLE_UNKNOWN", name);
752 return 0;
753 }
754 return hi;
755 default:
756 if (!(target = GetUserH(name))) {
757 send_message(user, service, "MSG_NICK_UNKNOWN", name);
758 return 0;
759 }
760 if (IsLocal(target)) {
761 if (IsService(target))
762 send_message(user, service, "NSMSG_USER_IS_SERVICE", target->nick);
763 else
764 send_message(user, service, "MSG_USER_AUTHENTICATE", target->nick);
765 return 0;
766 }
767 if (!(hi = target->handle_info)) {
768 send_message(user, service, "MSG_USER_AUTHENTICATE", target->nick);
769 return 0;
770 }
771 return hi;
772 }
773}
774
775int
776oper_outranks(struct userNode *user, struct handle_info *hi) {
777 if (user->handle_info->opserv_level > hi->opserv_level)
778 return 1;
779 if (user->handle_info->opserv_level == hi->opserv_level) {
780 if ((user->handle_info->opserv_level == 1000)
781 || (user->handle_info == hi)
782 || ((user->handle_info->opserv_level == 0)
783 && !(HANDLE_FLAGGED(hi, SUPPORT_HELPER) || HANDLE_FLAGGED(hi, NETWORK_HELPER))
784 && HANDLE_FLAGGED(user->handle_info, HELPING))) {
785 return 1;
786 }
787 }
788 send_message(user, nickserv, "MSG_USER_OUTRANKED", hi->handle);
789 return 0;
790}
791
792struct handle_info *
793get_victim_oper(struct userNode *user, const char *target)
794{
795 struct handle_info *hi;
796 if (!(hi = smart_get_handle_info(nickserv, user, target)))
797 return 0;
798 if (HANDLE_FLAGGED(user->handle_info, OPER_SUSPENDED)) {
799 send_message(user, nickserv, "MSG_OPER_SUSPENDED");
800 return 0;
801 }
802 return oper_outranks(user, hi) ? hi : NULL;
803}
804
805static int
806valid_user_for(struct userNode *user, struct handle_info *hi)
807{
808 unsigned int ii;
809
810 /* If no hostmasks on the account, allow it. */
811 if (!hi->masks->used)
812 return 1;
813 /* If any hostmask matches, allow it. */
814 for (ii=0; ii<hi->masks->used; ii++)
815 if (user_matches_glob(user, hi->masks->list[ii], 0))
816 return 1;
817 /* If they are allowauthed to this account, allow it (removing the aa). */
818 if (dict_find(nickserv_allow_auth_dict, user->nick, NULL) == hi) {
819 dict_remove(nickserv_allow_auth_dict, user->nick);
820 return 2;
821 }
822 /* The user is not allowed to use this account. */
823 return 0;
824}
825
826static int
827is_secure_password(const char *handle, const char *pass, struct userNode *user)
828{
829 unsigned int i, len;
830 unsigned int cnt_digits = 0, cnt_upper = 0, cnt_lower = 0;
831 int p;
832
833 len = strlen(pass);
834 if (len < nickserv_conf.password_min_length) {
835 if (user)
836 send_message(user, nickserv, "NSMSG_PASSWORD_SHORT", nickserv_conf.password_min_length);
837 return 0;
838 }
839 if (!irccasecmp(pass, handle)) {
840 if (user)
841 send_message(user, nickserv, "NSMSG_PASSWORD_ACCOUNT");
842 return 0;
843 }
844 dict_find(nickserv_conf.weak_password_dict, pass, &p);
845 if (p) {
846 if (user)
847 send_message(user, nickserv, "NSMSG_PASSWORD_DICTIONARY");
848 return 0;
849 }
850 for (i=0; i<len; i++) {
851 if (isdigit(pass[i]))
852 cnt_digits++;
853 if (isupper(pass[i]))
854 cnt_upper++;
855 if (islower(pass[i]))
856 cnt_lower++;
857 }
858 if ((cnt_lower < nickserv_conf.password_min_lower)
859 || (cnt_upper < nickserv_conf.password_min_upper)
860 || (cnt_digits < nickserv_conf.password_min_digits)) {
861 if (user)
862 send_message(user, nickserv, "NSMSG_PASSWORD_READABLE", nickserv_conf.password_min_digits, nickserv_conf.password_min_upper, nickserv_conf.password_min_lower);
863 return 0;
864 }
865 return 1;
866}
867
868static auth_func_t *auth_func_list;
869static unsigned int auth_func_size = 0, auth_func_used = 0;
870
871void
872reg_auth_func(auth_func_t func)
873{
874 if (auth_func_used == auth_func_size) {
875 if (auth_func_size) {
876 auth_func_size <<= 1;
877 auth_func_list = realloc(auth_func_list, auth_func_size*sizeof(auth_func_t));
878 } else {
879 auth_func_size = 8;
880 auth_func_list = malloc(auth_func_size*sizeof(auth_func_t));
881 }
882 }
883 auth_func_list[auth_func_used++] = func;
884}
885
886static handle_rename_func_t *rf_list;
887static unsigned int rf_list_size, rf_list_used;
888
889void
890reg_handle_rename_func(handle_rename_func_t func)
891{
892 if (rf_list_used == rf_list_size) {
893 if (rf_list_size) {
894 rf_list_size <<= 1;
895 rf_list = realloc(rf_list, rf_list_size*sizeof(rf_list[0]));
896 } else {
897 rf_list_size = 8;
898 rf_list = malloc(rf_list_size*sizeof(rf_list[0]));
899 }
900 }
901 rf_list[rf_list_used++] = func;
902}
903
904static char *
905generate_fakehost(struct handle_info *handle)
906{
907 struct userNode *target;
908 extern const char *hidden_host_suffix;
909 static char buffer[HOSTLEN+1];
910 char *data;
911 int style = 1;
912
913 if (!handle->fakehost) {
914 data = conf_get_data("server/hidden_host_type", RECDB_QSTRING);
915 if (data)
916 style = atoi(data);
917
918 if (style == 1)
919 snprintf(buffer, sizeof(buffer), "%s.%s", handle->handle, hidden_host_suffix);
920 else if (style == 2) {
921 /* Due to the way fakehost is coded theres no way i can
922 get the exact user, so for now ill just take the first
923 authed user. */
924 for (target = handle->users; target; target = target->next_authed)
925 break;
926
927 snprintf(buffer, sizeof(buffer), "%s", target->crypthost);
928 }
929 return buffer;
930 } else if (handle->fakehost[0] == '.') {
931 /* A leading dot indicates the stored value is actually a title. */
932 snprintf(buffer, sizeof(buffer), "%s.%s.%s", handle->handle, handle->fakehost+1, nickserv_conf.titlehost_suffix);
933 return buffer;
934 }
935 return handle->fakehost;
936}
937
938static void
939apply_fakehost(struct handle_info *handle)
940{
941 struct userNode *target;
942 char *fake;
943
944 if (!handle->users)
945 return;
946 fake = generate_fakehost(handle);
947 for (target = handle->users; target; target = target->next_authed)
948 assign_fakehost(target, fake, 1);
949}
950
951void send_func_list(struct userNode *user)
952{
953 unsigned int n;
954 struct handle_info *old_info;
955
956 old_info = user->handle_info;
957
958 for (n=0; n<auth_func_used; n++)
959 auth_func_list[n](user, old_info);
960}
961
962static void
963set_user_handle_info(struct userNode *user, struct handle_info *hi, int stamp)
964{
965 unsigned int n;
966 struct handle_info *old_info;
967
968 /* This can happen if somebody uses COOKIE while authed, or if
969 * they re-auth to their current handle (which is silly, but users
970 * are like that). */
971 if (user->handle_info == hi)
972 return;
973
974 if (user->handle_info) {
975 struct userNode *other;
976
977 if (IsHelper(user))
978 userList_remove(&curr_helpers, user);
979
980 /* remove from next_authed linked list */
981 if (user->handle_info->users == user) {
982 user->handle_info->users = user->next_authed;
983 } else if (user->handle_info->users != NULL) {
984 for (other = user->handle_info->users;
985 other->next_authed != user;
986 other = other->next_authed) ;
987 other->next_authed = user->next_authed;
988 } else {
989 /* No users authed to the account - can happen if they get
990 * killed for authing. */
991 }
992 /* if nobody left on old handle, and they're not an oper, remove !god */
993 if (!user->handle_info->users && !user->handle_info->opserv_level)
994 HANDLE_CLEAR_FLAG(user->handle_info, HELPING);
995 /* record them as being last seen at this time */
996 user->handle_info->lastseen = now;
997 /* and record their hostmask */
998 snprintf(user->handle_info->last_quit_host, sizeof(user->handle_info->last_quit_host), "%s@%s", user->ident, user->hostname);
999 }
1000 old_info = user->handle_info;
1001 user->handle_info = hi;
1002 if (hi && !hi->users && !hi->opserv_level)
1003 HANDLE_CLEAR_FLAG(hi, HELPING);
1004
1005 /* Call auth handlers */
1006 if (!GetUserH(user->nick))
1007 user->loc = 1;
1008
1009 if (hi) {
1010 struct nick_info *ni;
1011
1012 HANDLE_CLEAR_FLAG(hi, FROZEN);
1013 if (nickserv_conf.warn_clone_auth) {
1014 struct userNode *other;
1015 for (other = hi->users; other; other = other->next_authed)
1016 send_message(other, nickserv, "NSMSG_CLONE_AUTH", user->nick, user->ident, user->hostname);
1017 }
1018
1019 /* Add this auth to users list of current auths */
1020 user->next_authed = hi->users;
1021 hi->users = user;
1022 hi->lastseen = now;
1023 /* Add to helpers list */
1024 if (IsHelper(user) && !userList_contains(&curr_helpers, user))
1025 userList_append(&curr_helpers, user);
1026
1027 /* Set the fakehost */
1028 if (hi->fakehost || old_info)
1029 apply_fakehost(hi);
1030
1031 if (stamp) {
1032#ifdef WITH_PROTOCOL_P10
1033 /* Stamp users with their account name. */
1034 char *id = hi->handle;
1035#else
1036 const char *id = "???";
1037#endif
1038 /* Mark all the nicks registered to this
1039 * account as registered nicks
1040 * - Why not just this one? -rubin */
1041 if (!nickserv_conf.disable_nicks) {
1042 struct nick_info *ni2;
1043 for (ni2 = hi->nicks; ni2; ni2 = ni2->next) {
1044 if (!irccasecmp(user->nick, ni2->nick)) {
1045 user->modes |= FLAGS_REGNICK;
1046 break;
1047 }
1048 }
1049 }
1050 /* send the account to the ircd */
1051 StampUser(user, id, hi->registered);
1052 }
1053
1054 /* Stop trying to kick this user off their nick */
1055 if ((ni = get_nick_info(user->nick)) && (ni->owner == hi))
1056 timeq_del(0, nickserv_reclaim_p, user, TIMEQ_IGNORE_WHEN);
1057 } else {
1058 /* We cannot clear the user's account ID, unfortunately. */
1059 user->next_authed = NULL;
1060 }
1061
1062 /* Call auth handlers */
1063 if (GetUserH(user->nick)) {
1064 for (n=0; n<auth_func_used; n++) {
1065 auth_func_list[n](user, old_info);
1066 if (user->dead)
1067 return;
1068 }
1069 }
1070}
1071
1072static struct handle_info*
1073nickserv_register(struct userNode *user, struct userNode *settee, const char *handle, const char *passwd, int no_auth)
1074{
1075 struct handle_info *hi;
1076 struct nick_info *ni;
1077 char crypted[MD5_CRYPT_LENGTH];
1078
1079 if ((hi = dict_find(nickserv_handle_dict, handle, NULL))) {
1080 if(user)
1081 send_message(user, nickserv, "NSMSG_HANDLE_EXISTS", handle);
1082 return 0;
1083 }
1084
1085 if(strlen(handle) > 30)
1086 {
1087 if(user)
1088 send_message(user, nickserv, "NSMSG_HANDLE_TOLONG", handle, 30);
1089 return 0;
1090 }
1091
1092 if (!is_secure_password(handle, passwd, user))
1093 return 0;
1094
1095 cryptpass(passwd, crypted);
1096#ifdef WITH_LDAP
1097 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
1098 int rc;
1099 rc = ldap_do_add(handle, crypted, NULL);
1100 if(LDAP_SUCCESS != rc && LDAP_ALREADY_EXISTS != rc ) {
1101 if(user)
1102 send_message(user, nickserv, "NSMSG_LDAP_FAIL", ldap_err2string(rc));
1103 return 0;
1104 }
1105 }
1106#endif
1107 hi = register_handle(handle, crypted, 0);
1108 hi->masks = alloc_string_list(1);
1109 hi->ignores = alloc_string_list(1);
1110 hi->users = NULL;
1111 hi->language = lang_C;
1112 hi->registered = now;
1113 hi->lastseen = now;
1114 hi->flags = HI_DEFAULT_FLAGS;
1115 if (settee && !no_auth)
1116 set_user_handle_info(settee, hi, 1);
1117
1118 if (user != settee) {
1119 if(user)
1120 send_message(user, nickserv, "NSMSG_OREGISTER_H_SUCCESS");
1121 }
1122 else if (nickserv_conf.disable_nicks) {
1123 if(user) {
1124 send_message(user, nickserv, "NSMSG_REGISTER_H_SUCCESS");
1125 }
1126 }
1127 else if ((ni = dict_find(nickserv_nick_dict, user->nick, NULL))) {
1128 if(user) {
1129 send_message(user, nickserv, "NSMSG_PARTIAL_REGISTER");
1130 }
1131 }
1132 else {
1133 if(user) {
1134 if (is_registerable_nick(user->nick)) {
1135 register_nick(user->nick, hi);
1136 send_message(user, nickserv, "NSMSG_REGISTER_HN_SUCCESS");
1137 }
1138 }
1139 }
1140 if (settee && (user != settee)) {
1141 if(user) {
1142 send_message(settee, nickserv, "NSMSG_OREGISTER_VICTIM", user->nick, hi->handle);
1143 }
1144 }
1145 return hi;
1146}
1147
1148static void
1149nickserv_bake_cookie(struct handle_cookie *cookie)
1150{
1151 cookie->hi->cookie = cookie;
1152 timeq_add(cookie->expires, nickserv_free_cookie, cookie);
1153}
1154
1155/* Contributed by the great sneep of afternet ;) */
1156/* Since this gets used in a URL, we want to avoid stuff that confuses
1157 * email clients such as ] and ?. a-z, 0-9 only.
1158 */
1159void genpass(char *str, int len)
1160{
1161 int i = 0;
1162 char c = 0;
1163
1164 for(i = 0; i < len; i++)
1165 {
1166 do
1167 {
1168 c = (char)((float)rand() / (float)RAND_MAX * (float)256);
1169 } while(!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')));
1170 str[i] = c;
1171 }
1172 str[i] = '\0';
1173 return;
1174}
1175
1176static void
1177nickserv_make_cookie(struct userNode *user, struct handle_info *hi, enum cookie_type type, const char *cookie_data, int weblink)
1178{
1179 struct handle_cookie *cookie;
1180 char subject[128], body[4096], *misc;
1181 const char *netname, *fmt;
1182 int first_time = 0;
1183
1184 if (hi->cookie) {
1185 send_message(user, nickserv, "NSMSG_COOKIE_LIVE", hi->handle);
1186 return;
1187 }
1188
1189 cookie = calloc(1, sizeof(*cookie));
1190 cookie->hi = hi;
1191 cookie->type = type;
1192 cookie->data = cookie_data ? strdup(cookie_data) : NULL;
1193
1194 cookie->expires = now + nickserv_conf.cookie_timeout;
1195 /* Adding dedicated password gen function for more control -Rubin */
1196 genpass(cookie->cookie, 10);
1197 /*
1198 *inttobase64(cookie->cookie, rand(), 5);
1199 *inttobase64(cookie->cookie+5, rand(), 5);
1200 */
1201
1202 netname = nickserv_conf.network_name;
1203 subject[0] = 0;
1204
1205 switch (cookie->type) {
1206 case ACTIVATION:
1207 hi->passwd[0] = 0; /* invalidate password */
1208 send_message(user, nickserv, "NSMSG_USE_COOKIE_REGISTER");
1209 fmt = handle_find_message(hi, "NSEMAIL_ACTIVATION_SUBJECT");
1210 snprintf(subject, sizeof(subject), fmt, netname);
1211
1212 if(weblink)
1213 fmt = handle_find_message(hi, "NSEMAIL_ACTIVATION_BODY_WEB");
1214 else
1215 fmt = handle_find_message(hi, "NSEMAIL_ACTIVATION_BODY");
1216
1217 snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
1218 first_time = 1;
1219 break;
1220 case PASSWORD_CHANGE:
1221 send_message(user, nickserv, "NSMSG_USE_COOKIE_RESETPASS");
1222 fmt = handle_find_message(hi, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1223 snprintf(subject, sizeof(subject), fmt, netname);
1224 if(weblink)
1225 fmt = handle_find_message(hi, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1226 else
1227 fmt = handle_find_message(hi, "NSEMAIL_PASSWORD_CHANGE_BODY");
1228 snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
1229 first_time = 0;
1230 break;
1231 case EMAIL_CHANGE:
1232 misc = hi->email_addr;
1233 hi->email_addr = cookie->data;
1234#ifdef stupid_verify_old_email
1235 if (misc) {
1236 send_message(user, nickserv, "NSMSG_USE_COOKIE_EMAIL_2");
1237 fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1238 snprintf(subject, sizeof(subject), fmt, netname);
1239 fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1240 snprintf(body, sizeof(body), fmt, netname, cookie->cookie+COOKIELEN/2, nickserv->nick, self->name, hi->handle, COOKIELEN/2);
1241 mail_send(nickserv, hi, subject, body, 1);
1242 fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1243 snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle, COOKIELEN/2, hi->email_addr);
1244 first_time = 1;
1245 } else {
1246#endif
1247 send_message(user, nickserv, "NSMSG_USE_COOKIE_EMAIL_1");
1248 fmt = handle_find_message(hi, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1249 snprintf(subject, sizeof(subject), fmt, netname);
1250 fmt = handle_find_message(hi, "NSEMAIL_EMAIL_VERIFY_BODY");
1251 snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
1252 mail_send(nickserv, hi, subject, body, 1);
1253 subject[0] = 0;
1254#ifdef stupid_verify_old_email
1255 }
1256#endif
1257 hi->email_addr = misc;
1258 break;
1259 case ALLOWAUTH:
1260 fmt = handle_find_message(hi, "NSEMAIL_ALLOWAUTH_SUBJECT");
1261 snprintf(subject, sizeof(subject), fmt, netname);
1262 fmt = handle_find_message(hi, "NSEMAIL_ALLOWAUTH_BODY");
1263 snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
1264 send_message(user, nickserv, "NSMSG_USE_COOKIE_AUTH");
1265 break;
1266 default:
1267 log_module(NS_LOG, LOG_ERROR, "Bad cookie type %d in nickserv_make_cookie.", cookie->type);
1268 break;
1269 }
1270 if (subject[0])
1271 mail_send(nickserv, hi, subject, body, first_time);
1272 nickserv_bake_cookie(cookie);
1273}
1274
1275static void
1276nickserv_eat_cookie(struct handle_cookie *cookie)
1277{
1278 cookie->hi->cookie = NULL;
1279 timeq_del(cookie->expires, nickserv_free_cookie, cookie, 0);
1280 nickserv_free_cookie(cookie);
1281}
1282
1283static void
1284nickserv_free_email_addr(void *data)
1285{
1286 handle_info_list_clean(data);
1287 free(data);
1288}
1289
1290static void
1291nickserv_set_email_addr(struct handle_info *hi, const char *new_email_addr)
1292{
1293 struct handle_info_list *hil;
1294 /* Remove from old handle_info_list ... */
1295 if (hi->email_addr && (hil = dict_find(nickserv_email_dict, hi->email_addr, 0))) {
1296 handle_info_list_remove(hil, hi);
1297 if (!hil->used) dict_remove(nickserv_email_dict, hil->tag);
1298 hi->email_addr = NULL;
1299 }
1300 /* Add to the new list.. */
1301 if (new_email_addr) {
1302 if (!(hil = dict_find(nickserv_email_dict, new_email_addr, 0))) {
1303 hil = calloc(1, sizeof(*hil));
1304 hil->tag = strdup(new_email_addr);
1305 handle_info_list_init(hil);
1306 dict_insert(nickserv_email_dict, hil->tag, hil);
1307 }
1308 handle_info_list_append(hil, hi);
1309 hi->email_addr = hil->tag;
1310 }
1311}
1312
1313static NICKSERV_FUNC(cmd_register)
1314{
1315 irc_in_addr_t ip;
1316 struct handle_info *hi;
1317 const char *email_addr, *password;
1318 char syncpass[MD5_CRYPT_LENGTH];
1319 int no_auth, weblink;
1320
1321 if (checkDefCon(DEFCON_NO_NEW_NICKS) && !IsOper(user)) {
1322 reply("NSMSG_DEFCON_NO_NEW_NICKS", nickserv_conf.disable_nicks ? "accounts" : "nicknames");
1323 return 0;
1324 }
1325
1326 if (!IsOper(user) && !dict_size(nickserv_handle_dict)) {
1327 /* Require the first handle registered to belong to someone +o. */
1328 reply("NSMSG_REQUIRE_OPER");
1329 return 0;
1330 }
1331
1332 if (user->handle_info) {
1333 reply("NSMSG_USE_RENAME", user->handle_info->handle);
1334 return 0;
1335 }
1336
1337 if (IsRegistering(user)) {
1338 reply("NSMSG_ALREADY_REGISTERING");
1339 return 0;
1340 }
1341
1342 if (IsStamped(user)) {
1343 /* Unauthenticated users might still have been stamped
1344 previously and could therefore have a hidden host;
1345 do not allow them to register a new account. */
1346 reply("NSMSG_STAMPED_REGISTER");
1347 return 0;
1348 }
1349
1350 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf.email_required);
1351
1352 if(nickserv_conf.force_handles_lowercase)
1353 irc_strtolower(argv[1]);
1354 if (!is_valid_handle(argv[1])) {
1355 reply("NSMSG_BAD_HANDLE", argv[1]);
1356 return 0;
1357 }
1358
1359
1360 if ((argc >= 4) && nickserv_conf.email_enabled) {
1361 struct handle_info_list *hil;
1362 const char *str;
1363
1364 /* Remember email address. */
1365 email_addr = argv[3];
1366
1367 /* Check that the email address looks valid.. */
1368 if (!valid_email(email_addr)) {
1369 reply("NSMSG_BAD_EMAIL_ADDR");
1370 return 0;
1371 }
1372
1373 /* .. and that we are allowed to send to it. */
1374 if ((str = mail_prohibited_address(email_addr))) {
1375 reply("NSMSG_EMAIL_PROHIBITED", email_addr, str);
1376 return 0;
1377 }
1378
1379 /* If we do email verify, make sure we don't spam the address. */
1380 if ((hil = dict_find(nickserv_email_dict, email_addr, NULL))) {
1381 unsigned int nn;
1382 for (nn=0; nn<hil->used; nn++) {
1383 if (hil->list[nn]->cookie) {
1384 reply("NSMSG_EMAIL_UNACTIVATED");
1385 return 0;
1386 }
1387 }
1388 if (hil->used >= nickserv_conf.handles_per_email) {
1389 reply("NSMSG_EMAIL_OVERUSED");
1390 return 0;
1391 }
1392 }
1393
1394 no_auth = 1;
1395 } else {
1396 email_addr = 0;
1397 no_auth = 0;
1398 }
1399
1400 password = argv[2];
1401 argv[2] = "****";
1402 /* Webregister hack - send URL instead of IRC cookie
1403 * commands in email
1404 */
1405 if((argc >= 5) && !strcmp(argv[4],"WEBLINK"))
1406 weblink = 1;
1407 else
1408 weblink = 0;
1409 if (!(hi = nickserv_register(user, user, argv[1], password, no_auth)))
1410 return 0;
1411 /* Add any masks they should get. */
1412 if (nickserv_conf.default_hostmask) {
1413 string_list_append(hi->masks, strdup("*@*"));
1414 } else {
1415 string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
1416 if (irc_in_addr_is_valid(user->ip) && !irc_pton(&ip, NULL, user->hostname))
1417 string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_BYIP|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
1418 }
1419
1420 /* If they're the first to register, give them level 1000. */
1421 if (dict_size(nickserv_handle_dict) == 1) {
1422 hi->opserv_level = 1000;
1423 reply("NSMSG_ROOT_HANDLE", argv[1]);
1424 }
1425
1426 /* Set their email address. */
1427 if (email_addr) {
1428#ifdef WITH_LDAP
1429 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
1430 int rc;
1431 if((rc = ldap_do_modify(hi->handle, NULL, email_addr)) != LDAP_SUCCESS) {
1432 /* Falied to update email in ldap, but still
1433 * updated it here.. what should we do? */
1434 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc));
1435 } else {
1436 nickserv_set_email_addr(hi, email_addr);
1437 }
1438 }
1439 else {
1440 nickserv_set_email_addr(hi, email_addr);
1441 }
1442#else
1443 nickserv_set_email_addr(hi, email_addr);
1444#endif
1445 }
1446
1447 /* If they need to do email verification, tell them. */
1448 if (no_auth)
1449 nickserv_make_cookie(user, hi, ACTIVATION, hi->passwd, weblink);
1450
1451 /* Set registering flag.. */
1452 user->modes |= FLAGS_REGISTERING;
1453
1454 if (nickserv_conf.sync_log) {
1455 cryptpass(password, syncpass);
1456 /*
1457 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1458 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1459 * -SiRVulcaN
1460 */
1461 SyncLog("REGISTER %s %s %s %s", hi->handle, syncpass, email_addr ? email_addr : "0", user->info);
1462 }
1463
1464 /* this wont work if email is required .. */
1465 process_adduser_pending(user);
1466
1467 return 1;
1468}
1469
1470static NICKSERV_FUNC(cmd_oregister)
1471{
1472 struct userNode *settee = NULL;
1473 struct handle_info *hi;
1474 char* account = NULL;
1475 char* pass = NULL;
1476 char* email = NULL;
1477 char* mask = NULL;
1478 char* nick = NULL;
1479
1480 NICKSERV_MIN_PARMS(2);
1481
1482 account = argv[1];
1483 pass = argv[2];
1484 if(nickserv_conf.force_handles_lowercase)
1485 irc_strtolower(account);
1486 if (nickserv_conf.email_required) {
1487 NICKSERV_MIN_PARMS(3);
1488 email = argv[3];
1489 if (argc >= 4) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1490 if (argc < 4) {
1491 mask = NULL;
1492 settee = NULL;
1493 } else if (strchr(argv[4], '@'))
1494 mask = argv[4];
1495 else
1496 nick = argv[4];
1497 }
1498 if (argc >= 6) {
1499 nick = argv[5];
1500 }
1501 }
1502 else {
1503 if (argc >= 4) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1504 if (argc < 4) {
1505 mask = NULL;
1506 settee = NULL;
1507 } else if (strchr(argv[3], '@'))
1508 mask = argv[3];
1509 else
1510 nick = argv[3];
1511 }
1512 if (argc >= 5) {
1513 nick = argv[4];
1514 }
1515 }
1516 /* If they passed a nick, look for that user.. */
1517 if (nick && !(settee = GetUserH(nick))) {
1518 reply("MSG_NICK_UNKNOWN", argv[4]);
1519 return 0;
1520 }
1521 /* If the setee is already authed, we cant add a 2nd account for them.. */
1522 if (settee && settee->handle_info) {
1523 reply("NSMSG_USER_PREV_AUTH", settee->nick);
1524 return 0;
1525 }
1526 /* If there is no default mask in the conf, and they didn't pass a mask,
1527 * but we did find a user by nick, generate the mask */
1528 if (!mask) {
1529 if (nickserv_conf.default_hostmask)
1530 mask = "*@*";
1531 else if (settee)
1532 mask = generate_hostmask(settee, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT);
1533 else {
1534 reply("NSMSG_REGISTER_BAD_NICKMASK");
1535 return 0;
1536 }
1537 }
1538
1539 if (!(hi = nickserv_register(user, settee, account, pass, 0))) {
1540 return 0; /* error reply handled by above */
1541 }
1542 if (email) {
1543#ifdef WITH_LDAP
1544 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
1545 int rc;
1546 if((rc = ldap_do_modify(hi->handle, NULL, email)) != LDAP_SUCCESS) {
1547 /* Falied to update email in ldap, but still
1548 * updated it here.. what should we do? */
1549 reply("NSMSG_LDAP_FAIL_EMAIL", ldap_err2string(rc));
1550 } else {
1551 nickserv_set_email_addr(hi, email);
1552 }
1553 }
1554 else {
1555 nickserv_set_email_addr(hi, email);
1556 }
1557#else
1558 nickserv_set_email_addr(hi, email);
1559#endif
1560 }
1561 if (mask) {
1562 char* mask_canonicalized = canonicalize_hostmask(strdup(mask));
1563 if (mask_canonicalized)
1564 string_list_append(hi->masks, mask_canonicalized);
1565 }
1566
1567 if (nickserv_conf.sync_log)
1568 SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, email ? email : "@", user->info); /* Send just @ for email if none */
1569 return 1;
1570}
1571
1572static int
1573nickserv_ignore(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, char *mask)
1574{
1575 unsigned int i;
1576 struct userNode *target;
1577 char *new_mask = strdup(pretty_mask(mask));
1578 for (i=0; i<hi->ignores->used; i++) {
1579 if (!irccasecmp(new_mask, hi->ignores->list[i])) {
1580 reply("NSMSG_ADDIGNORE_ALREADY", new_mask);
1581 free(new_mask);
1582 return 0;
1583 }
1584 }
1585 string_list_append(hi->ignores, new_mask);
1586 reply("NSMSG_ADDIGNORE_SUCCESS", new_mask);
1587
1588 for (target = hi->users; target; target = target->next_authed) {
1589 irc_silence(target, new_mask, 1);
1590 }
1591 return 1;
1592}
1593
1594static NICKSERV_FUNC(cmd_addignore)
1595{
1596 NICKSERV_MIN_PARMS(2);
1597
1598 return nickserv_ignore(cmd, user, user->handle_info, argv[1]);
1599}
1600
1601static NICKSERV_FUNC(cmd_oaddignore)
1602{
1603 struct handle_info *hi;
1604
1605 NICKSERV_MIN_PARMS(3);
1606 if (!(hi = get_victim_oper(user, argv[1])))
1607 return 0;
1608
1609 return nickserv_ignore(cmd, user, hi, argv[2]);
1610}
1611
1612static int
1613nickserv_delignore(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, char *del_mask)
1614{
1615 unsigned int i;
1616 struct userNode *target;
1617 char *pmask = strdup(pretty_mask(del_mask));
1618 for (i=0; i<hi->ignores->used; i++) {
1619 if (!strcmp(pmask, hi->ignores->list[i]) || !strcmp(del_mask, hi->ignores->list[i])) {
1620 char *old_mask = hi->ignores->list[i];
1621 hi->ignores->list[i] = hi->ignores->list[--hi->ignores->used];
1622 reply("NSMSG_DELMASK_SUCCESS", old_mask);
1623 for (target = hi->users; target; target = target->next_authed) {
1624 irc_silence(target, old_mask, 0);
1625 }
1626 free(old_mask);
1627 free(pmask);
1628 return 1;
1629 }
1630 }
1631 reply("NSMSG_DELMASK_NOT_FOUND");
1632 return 0;
1633}
1634
1635static NICKSERV_FUNC(cmd_delignore)
1636{
1637 NICKSERV_MIN_PARMS(2);
1638 return nickserv_delignore(cmd, user, user->handle_info, argv[1]);
1639}
1640
1641static NICKSERV_FUNC(cmd_odelignore)
1642{
1643 struct handle_info *hi;
1644 NICKSERV_MIN_PARMS(3);
1645 if (!(hi = get_victim_oper(user, argv[1])))
1646 return 0;
1647 return nickserv_delignore(cmd, user, hi, argv[2]);
1648}
1649
1650static NICKSERV_FUNC(cmd_handleinfo)
1651{
1652 char buff[400];
1653 unsigned int i, pos=0, herelen;
1654 struct userNode *target, *next_un;
1655 struct handle_info *hi;
1656 const char *nsmsg_none;
1657
1658 if (argc < 2) {
1659 if (!(hi = user->handle_info)) {
1660 reply("NSMSG_MUST_AUTH");
1661 return 0;
1662 }
1663 } else if (!(hi = modcmd_get_handle_info(user, argv[1]))) {
1664 return 0;
1665 }
1666
1667 nsmsg_none = handle_find_message(hi, "MSG_NONE");
1668 reply("NSMSG_HANDLEINFO_ON", hi->handle);
1669 reply("MSG_BAR");
1670 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi->registered));
1671
1672 if (!hi->users) {
1673 intervalString(buff, now - hi->lastseen, user->handle_info);
1674 reply("NSMSG_HANDLEINFO_LASTSEEN", buff);
1675 } else {
1676 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1677 }
1678
1679 reply("NSMSG_HANDLEINFO_INFOLINE", (hi->infoline ? hi->infoline : nsmsg_none));
1680 if (HANDLE_FLAGGED(hi, FROZEN))
1681 reply("NSMSG_HANDLEINFO_VACATION");
1682
1683 if (oper_has_access(user, cmd->parent->bot, 0, 1)) {
1684 struct do_not_register *dnr;
1685 if ((dnr = chanserv_is_dnr(NULL, hi)))
1686 reply("NSMSG_HANDLEINFO_DNR", dnr->setter, dnr->reason);
1687 if ((user->handle_info->opserv_level < 900) && !oper_outranks(user, hi))
1688 return 1;
1689 } else if (hi != user->handle_info) {
1690 reply("NSMSG_HANDLEINFO_END");
1691 return 1;
1692 }
1693
1694 if (IsOper(user))
1695 reply("NSMSG_HANDLEINFO_KARMA", hi->karma);
1696
1697 if (nickserv_conf.email_enabled)
1698 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user, hi));
1699
1700 if (hi->cookie) {
1701 const char *type;
1702 switch (hi->cookie->type) {
1703 case ACTIVATION: type = "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1704 case PASSWORD_CHANGE: type = "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1705 case EMAIL_CHANGE: type = "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1706 case ALLOWAUTH: type = "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1707 default: type = "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1708 }
1709 reply(type);
1710 }
1711
1712 if (hi->flags) {
1713 unsigned long flen = 1;
1714 char flags[34]; /* 32 bits possible plus '+' and '\0' */
1715 flags[0] = '+';
1716 for (i=0, flen=1; handle_flags[i]; i++)
1717 if (hi->flags & 1 << i)
1718 flags[flen++] = handle_flags[i];
1719 flags[flen] = 0;
1720 reply("NSMSG_HANDLEINFO_FLAGS", flags);
1721 } else {
1722 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none);
1723 }
1724
1725 if (HANDLE_FLAGGED(hi, SUPPORT_HELPER)
1726 || HANDLE_FLAGGED(hi, NETWORK_HELPER)
1727 || (hi->opserv_level > 0)) {
1728 reply("NSMSG_HANDLEINFO_EPITHET", (hi->epithet ? hi->epithet : nsmsg_none));
1729 }
1730
1731 if (IsHelping(user) || IsOper(user))
1732 {
1733 if (hi->note)
1734 {
1735 char date[64];
1736 strftime(date, 64, "%b %d %Y", localtime(&hi->note->date));
1737 reply("NSMSG_HANDLEINFO_NOTE", hi->note->setter, date, hi->note->note);
1738 }
1739 }
1740
1741 if (hi->fakehost)
1742 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi->fakehost ? hi->fakehost : handle_find_message(hi, "MSG_NONE")));
1743
1744 if (hi->last_quit_host[0])
1745 reply("NSMSG_HANDLEINFO_LAST_HOST", hi->last_quit_host);
1746 else
1747 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1748
1749 if (nickserv_conf.disable_nicks) {
1750 /* nicks disabled; don't show anything about registered nicks */
1751 } else if (hi->nicks) {
1752 struct nick_info *ni, *next_ni;
1753 for (ni = hi->nicks; ni; ni = next_ni) {
1754 herelen = strlen(ni->nick);
1755 if (pos + herelen + 1 > ArrayLength(buff)) {
1756 next_ni = ni;
1757 goto print_nicks_buff;
1758 } else {
1759 next_ni = ni->next;
1760 }
1761 memcpy(buff+pos, ni->nick, herelen);
1762 pos += herelen; buff[pos++] = ' ';
1763 if (!next_ni) {
1764 print_nicks_buff:
1765 buff[pos-1] = 0;
1766 reply("NSMSG_HANDLEINFO_NICKS", buff);
1767 pos = 0;
1768 }
1769 }
1770 } else {
1771 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none);
1772 }
1773
1774 if (hi->masks->used) {
1775 for (i=0; i < hi->masks->used; i++) {
1776 herelen = strlen(hi->masks->list[i]);
1777 if (pos + herelen + 1 > ArrayLength(buff)) {
1778 i--;
1779 goto print_mask_buff;
1780 }
1781 memcpy(buff+pos, hi->masks->list[i], herelen);
1782 pos += herelen; buff[pos++] = ' ';
1783 if (i+1 == hi->masks->used) {
1784 print_mask_buff:
1785 buff[pos-1] = 0;
1786 reply("NSMSG_HANDLEINFO_MASKS", buff);
1787 pos = 0;
1788 }
1789 }
1790 } else {
1791 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none);
1792 }
1793
1794 if (hi->ignores->used) {
1795 for (i=0; i < hi->ignores->used; i++) {
1796 herelen = strlen(hi->ignores->list[i]);
1797 if (pos + herelen + 1 > ArrayLength(buff)) {
1798 i--;
1799 goto print_ignore_buff;
1800 }
1801 memcpy(buff+pos, hi->ignores->list[i], herelen);
1802 pos += herelen; buff[pos++] = ' ';
1803 if (i+1 == hi->ignores->used) {
1804 print_ignore_buff:
1805 buff[pos-1] = 0;
1806 reply("NSMSG_HANDLEINFO_IGNORES", buff);
1807 pos = 0;
1808 }
1809 }
1810 } else {
1811 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none);
1812 }
1813
1814 if (hi->channels) {
1815 struct userData *chan, *next;
1816 char *name;
1817
1818 for (chan = hi->channels; chan; chan = next) {
1819 next = chan->u_next;
1820 name = chan->channel->channel->name;
1821 herelen = strlen(name);
1822 if (pos + herelen + 7 > ArrayLength(buff)) {
1823 next = chan;
1824 goto print_chans_buff;
1825 }
1826 if (IsUserSuspended(chan))
1827 buff[pos++] = '-';
1828 pos += sprintf(buff+pos, "%s:%s ", user_level_name_from_level(chan->access), name);
1829 if (next == NULL) {
1830 print_chans_buff:
1831 buff[pos-1] = 0;
1832 reply("NSMSG_HANDLEINFO_CHANNELS", buff);
1833 pos = 0;
1834 }
1835 }
1836 } else {
1837 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none);
1838 }
1839
1840 for (target = hi->users; target; target = next_un) {
1841 herelen = strlen(target->nick);
1842 if (pos + herelen + 1 > ArrayLength(buff)) {
1843 next_un = target;
1844 goto print_cnick_buff;
1845 } else {
1846 next_un = target->next_authed;
1847 }
1848 memcpy(buff+pos, target->nick, herelen);
1849 pos += herelen; buff[pos++] = ' ';
1850 if (!next_un) {
1851 print_cnick_buff:
1852 buff[pos-1] = 0;
1853 reply("NSMSG_HANDLEINFO_CURRENT", buff);
1854 pos = 0;
1855 }
1856 }
1857
1858 reply("NSMSG_HANDLEINFO_END");
1859 return 1 | ((hi != user->handle_info) ? CMD_LOG_STAFF : 0);
1860}
1861
1862static NICKSERV_FUNC(cmd_userinfo)
1863{
1864 struct userNode *target;
1865
1866 NICKSERV_MIN_PARMS(2);
1867 if (!(target = GetUserH(argv[1]))) {
1868 reply("MSG_NICK_UNKNOWN", argv[1]);
1869 return 0;
1870 }
1871 if (target->handle_info)
1872 reply("NSMSG_USERINFO_AUTHED_AS", target->nick, target->handle_info->handle);
1873 else
1874 reply("NSMSG_USERINFO_NOT_AUTHED", target->nick);
1875 return 1;
1876}
1877
1878static NICKSERV_FUNC(cmd_nickinfo)
1879{
1880 struct nick_info *ni;
1881
1882 NICKSERV_MIN_PARMS(2);
1883 if (!(ni = get_nick_info(argv[1]))) {
1884 reply("MSG_NICK_UNKNOWN", argv[1]);
1885 return 0;
1886 }
1887 reply("NSMSG_NICKINFO_OWNER", ni->nick, ni->owner->handle);
1888 return 1;
1889}
1890
1891static NICKSERV_FUNC(cmd_rename_handle)
1892{
1893 struct handle_info *hi;
1894 struct userNode *uNode;
1895 char *old_handle;
1896 unsigned int nn;
1897
1898 NICKSERV_MIN_PARMS(3);
1899 if(nickserv_conf.force_handles_lowercase)
1900 irc_strtolower(argv[2]);
1901 if (!(hi = get_victim_oper(user, argv[1])))
1902 return 0;
1903 if (!is_valid_handle(argv[2])) {
1904 reply("NSMSG_FAIL_RENAME", argv[1], argv[2]);
1905 return 0;
1906 }
1907 if (get_handle_info(argv[2])) {
1908 reply("NSMSG_HANDLE_EXISTS", argv[2]);
1909 return 0;
1910 }
1911 if(strlen(argv[2]) > 30)
1912 {
1913 reply("NMSG_HANDLE_TOLONG", argv[2], 30);
1914 return 0;
1915 }
1916#ifdef WITH_LDAP
1917 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
1918 int rc;
1919 if( (rc = ldap_rename_account(hi->handle, argv[2])) != LDAP_SUCCESS) {
1920 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
1921 return 0;
1922 }
1923 }
1924#endif
1925
1926 dict_remove2(nickserv_handle_dict, old_handle = hi->handle, 1);
1927 hi->handle = strdup(argv[2]);
1928 dict_insert(nickserv_handle_dict, hi->handle, hi);
1929 for (nn=0; nn<rf_list_used; nn++)
1930 rf_list[nn](hi, old_handle);
1931
1932 if (nickserv_conf.sync_log) {
1933 for (uNode = hi->users; uNode; uNode = uNode->next_authed)
1934 irc_rename(uNode, hi->handle);
1935
1936 SyncLog("RENAME %s %s", old_handle, hi->handle);
1937 }
1938
1939 reply("NSMSG_HANDLE_CHANGED", old_handle, hi->handle);
1940 global_message_args(MESSAGE_RECIPIENT_OPERS, "NSMSG_ACCOUNT_RENAMED",
1941 user->handle_info->handle, old_handle, hi->handle);
1942
1943 free(old_handle);
1944 return 1;
1945}
1946
1947static failpw_func_t *failpw_func_list;
1948static unsigned int failpw_func_size = 0, failpw_func_used = 0;
1949
1950void
1951reg_failpw_func(failpw_func_t func)
1952{
1953 if (failpw_func_used == failpw_func_size) {
1954 if (failpw_func_size) {
1955 failpw_func_size <<= 1;
1956 failpw_func_list = realloc(failpw_func_list, failpw_func_size*sizeof(failpw_func_t));
1957 } else {
1958 failpw_func_size = 8;
1959 failpw_func_list = malloc(failpw_func_size*sizeof(failpw_func_t));
1960 }
1961 }
1962 failpw_func_list[failpw_func_used++] = func;
1963}
1964
1965/*
1966 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1967 *
1968 * called by nefariouses enhanced AC login-on-connect code
1969 *
1970 */
1971struct handle_info *loc_auth(char *handle, char *password, char *userhost)
1972{
1973 int pw_arg, used, maxlogins;
1974 unsigned int ii;
1975 int wildmask = 0;
1976 struct handle_info *hi;
1977 struct userNode *other;
1978#ifdef WITH_LDAP
1979 int ldap_result = LDAP_SUCCESS;
1980 char *email = NULL;
1981#endif
1982
1983 hi = dict_find(nickserv_handle_dict, handle, NULL);
1984 pw_arg = 2;
1985
1986#ifdef WITH_LDAP
1987 if(nickserv_conf.ldap_enable) {
1988 ldap_result = ldap_check_auth(handle, password);
1989 if(ldap_result != LDAP_SUCCESS) {
1990 return NULL;
1991 }
1992 }
1993#else
1994 if (!hi) {
1995 return NULL;
1996 }
1997
1998 if (!checkpass(password, hi->passwd)) {
1999 return NULL;
2000 }
2001#endif
2002#ifdef WITH_LDAP
2003 /* ldap libs are present but we are not using them... */
2004 if( !nickserv_conf.ldap_enable ) {
2005 if (!hi) {
2006 return NULL;
2007 }
2008 if (!checkpass(password, hi->passwd)) {
2009 return NULL;
2010 }
2011 }
2012 else if( (!hi) && ldap_result == LDAP_SUCCESS && nickserv_conf.ldap_autocreate) {
2013 /* user not found, but authed to ldap successfully..
2014 * create the account.
2015 */
2016 char *mask;
2017 int rc;
2018
2019 /* Add a *@* mask */
2020 /* TODO if userhost is not null, build mask based on that. */
2021 if(nickserv_conf.default_hostmask)
2022 mask = "*@*";
2023 else
2024 return NULL; /* They dont have a *@* mask so they can't loc */
2025
2026 if(!(hi = nickserv_register(NULL, NULL, handle, password, 0))) {
2027 return 0; /* couldn't add the user for some reason */
2028 }
2029
2030 if((rc = ldap_get_user_info(handle, &email) != LDAP_SUCCESS))
2031 {
2032 if(nickserv_conf.email_required) {
2033 return 0;
2034 }
2035 }
2036 if(email) {
2037 nickserv_set_email_addr(hi, email);
2038 free(email);
2039 }
2040 if(mask) {
2041 char* mask_canonicalized = canonicalize_hostmask(strdup(mask));
2042 string_list_append(hi->masks, mask_canonicalized);
2043 }
2044 if(nickserv_conf.sync_log)
2045 SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, "@", handle);
2046 }
2047#endif
2048
2049 /* Still no account, so just fail out */
2050 if (!hi) {
2051 return NULL;
2052 }
2053
2054 /* We don't know the users hostname, or anything because they
2055 * havn't registered yet. So we can only allow LOC if your
2056 * account has *@* as a hostmask.
2057 *
2058 * UPDATE: New nefarious LOC supports u@h
2059 */
2060 if(userhost) {
2061 char *buf;
2062 char *ident;
2063 char *realhost;
2064 char *ip;
2065 char *uh;
2066 char *ui;
2067
2068 buf = strdup(userhost);
2069 ident = mysep(&buf, "@");
2070 realhost = mysep(&buf, ":");
2071 ip = mysep(&buf, ":");
2072 if(!ip || !realhost || !ident) {
2073 free(buf);
2074 return NULL; /* Invalid AC request, just quit */
2075 }
2076 uh = malloc(strlen(userhost));
2077 ui = malloc(strlen(userhost));
2078 sprintf(uh, "%s@%s", ident, realhost);
2079 sprintf(ui, "%s@%s", ident, ip);
2080 for (ii=0; ii<hi->masks->used; ii++)
2081 {
2082 if(match_ircglob(uh, hi->masks->list[ii])
2083 || match_ircglob(ui, hi->masks->list[ii]))
2084 {
2085 wildmask++;
2086 break;
2087 }
2088 }
2089 free(buf);
2090 free(uh);
2091 free(ui);
2092 }
2093 else {
2094
2095 for (ii=0; ii<hi->masks->used; ii++)
2096 {
2097 if (!strcmp(hi->masks->list[ii], "*@*"))
2098 {
2099 wildmask++;
2100 break;
2101 }
2102 }
2103 }
2104 if(wildmask < 1)
2105 return NULL;
2106
2107 if (HANDLE_FLAGGED(hi, SUSPENDED)) {
2108 return NULL;
2109 }
2110
2111 maxlogins = hi->maxlogins ? hi->maxlogins : nickserv_conf.default_maxlogins;
2112 for (used = 0, other = hi->users; other; other = other->next_authed) {
2113 if (++used >= maxlogins) {
2114 return NULL;
2115 }
2116 }
2117 /* TODO - Add LOGGING to this function so LOC's are logged.. */
2118 return hi;
2119}
2120
2121static NICKSERV_FUNC(cmd_auth)
2122{
2123 int pw_arg, used, maxlogins;
2124 struct handle_info *hi;
2125 const char *passwd;
2126 struct userNode *other;
2127#ifdef WITH_LDAP
2128 int ldap_result = LDAP_OTHER;
2129 char *email = NULL;
2130#endif
2131
2132 if (user->handle_info) {
2133 reply("NSMSG_ALREADY_AUTHED", user->handle_info->handle);
2134 return 0;
2135 }
2136 if (IsStamped(user)) {
2137 /* Unauthenticated users might still have been stamped
2138 previously and could therefore have a hidden host;
2139 do not allow them to authenticate. */
2140 reply("NSMSG_STAMPED_AUTH");
2141 return 0;
2142 }
2143 if (argc == 3) {
2144#ifdef WITH_LDAP
2145 if(strchr(argv[1], '<') || strchr(argv[1], '>')) {
2146 reply("NSMSG_NO_ANGLEBRACKETS");
2147 return 0;
2148 }
2149 if (!is_valid_handle(argv[1])) {
2150 reply("NSMSG_BAD_HANDLE", argv[1]);
2151 return 0;
2152 }
2153
2154 if(nickserv_conf.ldap_enable) {
2155 ldap_result = ldap_check_auth(argv[1], argv[2]);
2156 /* Get the users email address and update it */
2157 if(ldap_result == LDAP_SUCCESS) {
2158 int rc;
2159 if((rc = ldap_get_user_info(argv[1], &email) != LDAP_SUCCESS))
2160 {
2161 if(nickserv_conf.email_required) {
2162 reply("NSMSG_LDAP_FAIL_GET_EMAIL", ldap_err2string(rc));
2163 return 0;
2164 }
2165 }
2166 }
2167 else if(ldap_result != LDAP_INVALID_CREDENTIALS) {
2168 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result));
2169 return 0;
2170 }
2171 }
2172
2173#endif
2174 hi = dict_find(nickserv_handle_dict, argv[1], NULL);
2175 pw_arg = 2;
2176 } else if (argc == 2 && !nickserv_conf.ldap_enable) {
2177 if (nickserv_conf.disable_nicks) {
2178 if (!(hi = get_handle_info(user->nick))) {
2179 reply("NSMSG_HANDLE_NOT_FOUND");
2180 return 0;
2181 }
2182 } else {
2183 /* try to look up their handle from their nick */
2184 /* TODO: handle ldap auth on nickserv style networks, too */
2185 struct nick_info *ni;
2186 ni = get_nick_info(user->nick);
2187 if (!ni) {
2188 reply("NSMSG_NICK_NOT_REGISTERED", user->nick);
2189 return 0;
2190 }
2191 hi = ni->owner;
2192 }
2193 pw_arg = 1;
2194 } else {
2195 reply("MSG_MISSING_PARAMS", argv[0]);
2196 svccmd_send_help_brief(user, nickserv, cmd);
2197 return 0;
2198 }
2199 if (!hi) {
2200#ifdef WITH_LDAP
2201 if(nickserv_conf.ldap_enable && ldap_result == LDAP_SUCCESS && nickserv_conf.ldap_autocreate) {
2202 /* user not found, but authed to ldap successfully..
2203 * create the account.
2204 */
2205 char *mask;
2206 if(!(hi = nickserv_register(user, NULL, argv[1], argv[2], 0))) {
2207 reply("NSMSG_UNABLE_TO_ADD");
2208 return 0; /* couldn't add the user for some reason */
2209 }
2210 /* Add a *@* mask */
2211 if(nickserv_conf.default_hostmask)
2212 mask = "*@*";
2213 else
2214 mask = generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT);
2215
2216 if(mask) {
2217 char* mask_canonicalized = canonicalize_hostmask(strdup(mask));
2218 string_list_append(hi->masks, mask_canonicalized);
2219 }
2220 if(email) {
2221 nickserv_set_email_addr(hi, email);
2222 free(email);
2223 }
2224 if(nickserv_conf.sync_log)
2225 SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, email ? email : "@", user->info);
2226 }
2227 else {
2228#endif
2229 reply("NSMSG_HANDLE_NOT_FOUND");
2230 return 0;
2231#ifdef WITH_LDAP
2232 }
2233#endif
2234 }
2235 /* Responses from here on look up the language used by the handle they asked about. */
2236 passwd = argv[pw_arg];
2237 if (!valid_user_for(user, hi)) {
2238 if (hi->email_addr && nickserv_conf.email_enabled)
2239 send_message_type(4, user, cmd->parent->bot,
2240 handle_find_message(hi, "NSMSG_USE_AUTHCOOKIE"),
2241 hi->handle);
2242 else
2243 send_message_type(4, user, cmd->parent->bot,
2244 handle_find_message(hi, "NSMSG_HOSTMASK_INVALID"),
2245 hi->handle);
2246 argv[pw_arg] = "BADMASK";
2247 return 1;
2248 }
2249#ifdef WITH_LDAP
2250 if( ( nickserv_conf.ldap_enable && ldap_result == LDAP_INVALID_CREDENTIALS ) ||
2251 ( (!nickserv_conf.ldap_enable) && (!checkpass(passwd, hi->passwd)) ) ) {
2252#else
2253 if (!checkpass(passwd, hi->passwd)) {
2254#endif
2255 unsigned int n;
2256 send_message_type(4, user, cmd->parent->bot,
2257 handle_find_message(hi, "NSMSG_PASSWORD_INVALID"));
2258 argv[pw_arg] = "BADPASS";
2259 for (n=0; n<failpw_func_used; n++) failpw_func_list[n](user, hi);
2260 if (nickserv_conf.autogag_enabled) {
2261 if (!user->auth_policer.params) {
2262 user->auth_policer.last_req = now;
2263 user->auth_policer.params = nickserv_conf.auth_policer_params;
2264 }
2265 if (!policer_conforms(&user->auth_policer, now, 1.0)) {
2266 char *hostmask;
2267 hostmask = generate_hostmask(user, GENMASK_STRICT_HOST|GENMASK_BYIP|GENMASK_NO_HIDING);
2268 log_module(NS_LOG, LOG_INFO, "%s auto-gagged for repeated password guessing.", hostmask);
2269 gag_create(hostmask, nickserv->nick, "Repeated password guessing.", now+nickserv_conf.autogag_duration);
2270 free(hostmask);
2271 argv[pw_arg] = "GAGGED";
2272 }
2273 }
2274 return 1;
2275 }
2276 if (HANDLE_FLAGGED(hi, SUSPENDED)) {
2277 send_message_type(4, user, cmd->parent->bot,
2278 handle_find_message(hi, "NSMSG_HANDLE_SUSPENDED"));
2279 argv[pw_arg] = "SUSPENDED";
2280 return 1;
2281 }
2282 maxlogins = hi->maxlogins ? hi->maxlogins : nickserv_conf.default_maxlogins;
2283 for (used = 0, other = hi->users; other; other = other->next_authed) {
2284 if (++used >= maxlogins) {
2285 send_message_type(4, user, cmd->parent->bot,
2286 handle_find_message(hi, "NSMSG_MAX_LOGINS"),
2287 maxlogins);
2288 argv[pw_arg] = "MAXLOGINS";
2289 return 1;
2290 }
2291 }
2292
2293 set_user_handle_info(user, hi, 1);
2294 if (nickserv_conf.email_required && !hi->email_addr)
2295 reply("NSMSG_PLEASE_SET_EMAIL");
2296 if (!is_secure_password(hi->handle, passwd, NULL))
2297 reply("NSMSG_WEAK_PASSWORD");
2298 if (hi->passwd[0] != '$')
2299 cryptpass(passwd, hi->passwd);
2300
2301 /* If a channel was waiting for this user to auth,
2302 * finish adding them */
2303 process_adduser_pending(user);
2304
2305 reply("NSMSG_AUTH_SUCCESS");
2306
2307
2308 /* Set +x if autohide is on */
2309 if(HANDLE_FLAGGED(hi, AUTOHIDE))
2310 irc_umode(user, "+x");
2311
2312 if(!IsOper(user)) /* If they arnt already opered.. */
2313 {
2314 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2315 if( nickserv_conf.auto_admin[0] && hi->opserv_level >= opserv_conf_admin_level())
2316 {
2317 irc_umode(user,nickserv_conf.auto_admin);
2318 reply("NSMSG_AUTO_OPER_ADMIN");
2319 }
2320 else if (nickserv_conf.auto_oper[0] && hi->opserv_level > 0)
2321 {
2322 irc_umode(user,nickserv_conf.auto_oper);
2323 reply("NSMSG_AUTO_OPER");
2324 }
2325 }
2326
2327 /* Wipe out the pass for the logs */
2328
2329 if (!hi->masks->used) {
2330 irc_in_addr_t ip;
2331 string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
2332 if (irc_in_addr_is_valid(user->ip) && irc_pton(&ip, NULL, user->hostname))
2333 string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_BYIP|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
2334 }
2335
2336 argv[pw_arg] = "****";
2337 return 1;
2338}
2339
2340static allowauth_func_t *allowauth_func_list;
2341static unsigned int allowauth_func_size = 0, allowauth_func_used = 0;
2342
2343void
2344reg_allowauth_func(allowauth_func_t func)
2345{
2346 if (allowauth_func_used == allowauth_func_size) {
2347 if (allowauth_func_size) {
2348 allowauth_func_size <<= 1;
2349 allowauth_func_list = realloc(allowauth_func_list, allowauth_func_size*sizeof(allowauth_func_t));
2350 } else {
2351 allowauth_func_size = 8;
2352 allowauth_func_list = malloc(allowauth_func_size*sizeof(allowauth_func_t));
2353 }
2354 }
2355 allowauth_func_list[allowauth_func_used++] = func;
2356}
2357
2358static NICKSERV_FUNC(cmd_allowauth)
2359{
2360 struct userNode *target;
2361 struct handle_info *hi;
2362 unsigned int n;
2363
2364 NICKSERV_MIN_PARMS(2);
2365 if (!(target = GetUserH(argv[1]))) {
2366 reply("MSG_NICK_UNKNOWN", argv[1]);
2367 return 0;
2368 }
2369 if (target->handle_info) {
2370 reply("NSMSG_USER_PREV_AUTH", target->nick);
2371 return 0;
2372 }
2373 if (IsStamped(target)) {
2374 /* Unauthenticated users might still have been stamped
2375 previously and could therefore have a hidden host;
2376 do not allow them to authenticate to an account. */
2377 reply("NSMSG_USER_PREV_STAMP", target->nick);
2378 return 0;
2379 }
2380 if (argc == 2)
2381 hi = NULL;
2382 else if (!(hi = get_handle_info(argv[2]))) {
2383 reply("MSG_HANDLE_UNKNOWN", argv[2]);
2384 return 0;
2385 }
2386 if (hi) {
2387 if (hi->opserv_level > user->handle_info->opserv_level) {
2388 reply("MSG_USER_OUTRANKED", hi->handle);
2389 return 0;
2390 }
2391 if (((hi->flags & (HI_FLAG_SUPPORT_HELPER|HI_FLAG_NETWORK_HELPER))
2392 || (hi->opserv_level > 0))
2393 && ((argc < 4) || irccasecmp(argv[3], "staff"))) {
2394 reply("NSMSG_ALLOWAUTH_STAFF", hi->handle);
2395 return 0;
2396 }
2397 dict_insert(nickserv_allow_auth_dict, target->nick, hi);
2398 reply("NSMSG_AUTH_ALLOWED", target->nick, hi->handle);
2399 send_message(target, nickserv, "NSMSG_AUTH_ALLOWED_MSG", hi->handle, hi->handle);
2400 if (nickserv_conf.email_enabled)
2401 send_message(target, nickserv, "NSMSG_AUTH_ALLOWED_EMAIL");
2402 } else {
2403 if (dict_remove(nickserv_allow_auth_dict, target->nick))
2404 reply("NSMSG_AUTH_NORMAL_ONLY", target->nick);
2405 else
2406 reply("NSMSG_AUTH_UNSPECIAL", target->nick);
2407 }
2408 for (n=0; n<allowauth_func_used; n++)
2409 allowauth_func_list[n](user, target, hi);
2410 return 1;
2411}
2412
2413static NICKSERV_FUNC(cmd_authcookie)
2414{
2415 struct handle_info *hi;
2416
2417 NICKSERV_MIN_PARMS(2);
2418 if (user->handle_info) {
2419 reply("NSMSG_ALREADY_AUTHED", user->handle_info->handle);
2420 return 0;
2421 }
2422 if (IsStamped(user)) {
2423 /* Unauthenticated users might still have been stamped
2424 previously and could therefore have a hidden host;
2425 do not allow them to authenticate to an account. */
2426 reply("NSMSG_STAMPED_AUTHCOOKIE");
2427 return 0;
2428 }
2429 if (!(hi = get_handle_info(argv[1]))) {
2430 reply("MSG_HANDLE_UNKNOWN", argv[1]);
2431 return 0;
2432 }
2433 if (!hi->email_addr) {
2434 reply("MSG_SET_EMAIL_ADDR");
2435 return 0;
2436 }
2437 nickserv_make_cookie(user, hi, ALLOWAUTH, NULL, 0);
2438 return 1;
2439}
2440
2441static NICKSERV_FUNC(cmd_delcookie)
2442{
2443 struct handle_info *hi;
2444
2445 hi = user->handle_info;
2446 if (!hi->cookie) {
2447 reply("NSMSG_NO_COOKIE");
2448 return 0;
2449 }
2450 switch (hi->cookie->type) {
2451 case ACTIVATION:
2452 case EMAIL_CHANGE:
2453 reply("NSMSG_MUST_TIME_OUT");
2454 break;
2455 default:
2456 nickserv_eat_cookie(hi->cookie);
2457 reply("NSMSG_ATE_COOKIE");
2458 break;
2459 }
2460 return 1;
2461}
2462
2463static NICKSERV_FUNC(cmd_odelcookie)
2464{
2465 struct handle_info *hi;
2466
2467 NICKSERV_MIN_PARMS(2);
2468
2469 if (!(hi = get_victim_oper(user, argv[1])))
2470 return 0;
2471
2472 if (!hi->cookie) {
2473 reply("NSMSG_NO_COOKIE_FOREIGN", hi->handle);
2474 return 0;
2475 }
2476
2477 switch (hi->cookie->type) {
2478 case ACTIVATION:
2479 safestrncpy(hi->passwd, hi->cookie->data, sizeof(hi->passwd));
2480 if (nickserv_conf.sync_log)
2481 SyncLog("ACCOUNTACC %s", hi->handle);
2482 break;
2483 case PASSWORD_CHANGE:
2484 safestrncpy(hi->passwd, hi->cookie->data, sizeof(hi->passwd));
2485 if (nickserv_conf.sync_log)
2486 SyncLog("PASSCHANGE %s %s", hi->handle, hi->passwd);
2487 break;
2488 case EMAIL_CHANGE:
2489 if (!hi->email_addr && nickserv_conf.sync_log) {
2490 if (nickserv_conf.sync_log)
2491 SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, hi->cookie->data, user->info);
2492 }
2493#ifdef WITH_LDAP
2494 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
2495 int rc;
2496 if((rc = ldap_do_modify(hi->handle, NULL, hi->cookie->data)) != LDAP_SUCCESS) {
2497 /* Falied to update email in ldap, but still
2498 * updated it here.. what should we do? */
2499 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc));
2500 } else {
2501 nickserv_set_email_addr(hi, hi->cookie->data);
2502 }
2503 }
2504 else {
2505 nickserv_set_email_addr(hi, hi->cookie->data);
2506 }
2507#else
2508 nickserv_set_email_addr(hi, hi->cookie->data);
2509#endif
2510 if (nickserv_conf.sync_log)
2511 SyncLog("EMAILCHANGE %s %s", hi->handle, hi->cookie->data);
2512 break;
2513 default:
2514 reply("NSMSG_BAD_COOKIE_TYPE", hi->cookie->type);
2515 log_module(NS_LOG, LOG_ERROR, "Bad cookie type %d for account %s.", hi->cookie->type, hi->handle);
2516 break;
2517 }
2518
2519 nickserv_eat_cookie(hi->cookie);
2520 reply("NSMSG_ATE_FOREIGN_COOKIE", hi->handle);
2521
2522 return 1;
2523}
2524
2525static NICKSERV_FUNC(cmd_resetpass)
2526{
2527 struct handle_info *hi;
2528 char crypted[MD5_CRYPT_LENGTH];
2529 int weblink;
2530
2531 NICKSERV_MIN_PARMS(3);
2532 if(argc >= 4 && !strcmp(argv[3], "WEBLINK"))
2533 weblink = 1;
2534 else
2535 weblink = 0;
2536 if (user->handle_info) {
2537 reply("NSMSG_ALREADY_AUTHED", user->handle_info->handle);
2538 return 0;
2539 }
2540 if (IsStamped(user)) {
2541 /* Unauthenticated users might still have been stamped
2542 previously and could therefore have a hidden host;
2543 do not allow them to activate an account. */
2544 reply("NSMSG_STAMPED_RESETPASS");
2545 return 0;
2546 }
2547 if (!(hi = get_handle_info(argv[1]))) {
2548 reply("MSG_HANDLE_UNKNOWN", argv[1]);
2549 return 0;
2550 }
2551 if (!hi->email_addr) {
2552 reply("MSG_SET_EMAIL_ADDR");
2553 return 0;
2554 }
2555 cryptpass(argv[2], crypted);
2556 argv[2] = "****";
2557 nickserv_make_cookie(user, hi, PASSWORD_CHANGE, crypted, weblink);
2558 return 1;
2559}
2560
2561static NICKSERV_FUNC(cmd_cookie)
2562{
2563 struct handle_info *hi;
2564 const char *cookie;
2565
2566 if ((argc == 2) && (hi = user->handle_info) && hi->cookie && (hi->cookie->type == EMAIL_CHANGE)) {
2567 cookie = argv[1];
2568 } else {
2569 NICKSERV_MIN_PARMS(3);
2570 if (!(hi = get_handle_info(argv[1]))) {
2571 reply("MSG_HANDLE_UNKNOWN", argv[1]);
2572 return 0;
2573 }
2574 cookie = argv[2];
2575 }
2576
2577 if (HANDLE_FLAGGED(hi, SUSPENDED)) {
2578 reply("NSMSG_HANDLE_SUSPENDED");
2579 return 0;
2580 }
2581
2582 if (!hi->cookie) {
2583 reply("NSMSG_NO_COOKIE");
2584 return 0;
2585 }
2586
2587 /* Check validity of operation before comparing cookie to
2588 * prohibit guessing by authed users. */
2589 if (user->handle_info
2590 && (hi->cookie->type != EMAIL_CHANGE)
2591 && (hi->cookie->type != PASSWORD_CHANGE)) {
2592 reply("NSMSG_CANNOT_COOKIE");
2593 return 0;
2594 }
2595
2596 if (strcmp(cookie, hi->cookie->cookie)) {
2597 reply("NSMSG_BAD_COOKIE");
2598 return 0;
2599 }
2600
2601 switch (hi->cookie->type) {
2602 case ACTIVATION:
2603#ifdef WITH_LDAP
2604 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
2605 int rc;
2606 if((rc = ldap_do_modify(hi->handle, hi->cookie->data, NULL)) != LDAP_SUCCESS) {
2607 /* Falied to update email in ldap, but still
2608 * updated it here.. what should we do? */
2609 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
2610 return 0;
2611 }
2612 }
2613#endif
2614 safestrncpy(hi->passwd, hi->cookie->data, sizeof(hi->passwd));
2615 set_user_handle_info(user, hi, 1);
2616 reply("NSMSG_HANDLE_ACTIVATED");
2617 if (nickserv_conf.sync_log)
2618 SyncLog("ACCOUNTACC %s", hi->handle);
2619 break;
2620 case PASSWORD_CHANGE:
2621#ifdef WITH_LDAP
2622 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
2623 int rc;
2624 if((rc = ldap_do_modify(hi->handle, hi->cookie->data, NULL)) != LDAP_SUCCESS) {
2625 /* Falied to update email in ldap, but still
2626 * updated it here.. what should we do? */
2627 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
2628 return 0;
2629 }
2630 }
2631#endif
2632 set_user_handle_info(user, hi, 1);
2633 safestrncpy(hi->passwd, hi->cookie->data, sizeof(hi->passwd));
2634 reply("NSMSG_PASSWORD_CHANGED");
2635 if (nickserv_conf.sync_log)
2636 SyncLog("PASSCHANGE %s %s", hi->handle, hi->passwd);
2637 break;
2638 case EMAIL_CHANGE:
2639#ifdef WITH_LDAP
2640 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
2641 int rc;
2642 if((rc = ldap_do_modify(hi->handle, NULL, hi->cookie->data)) != LDAP_SUCCESS) {
2643 /* Falied to update email in ldap, but still
2644 * updated it here.. what should we do? */
2645 reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc));
2646 return 0;
2647 }
2648 }
2649#endif
2650 if (!hi->email_addr && nickserv_conf.sync_log) {
2651 /*
2652 * This should only happen if an OREGISTER was sent. Require
2653 * email must be enabled! - SiRVulcaN
2654 */
2655 if (nickserv_conf.sync_log)
2656 SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, hi->cookie->data, user->info);
2657 }
2658
2659 nickserv_set_email_addr(hi, hi->cookie->data);
2660 reply("NSMSG_EMAIL_CHANGED");
2661 if (nickserv_conf.sync_log)
2662 SyncLog("EMAILCHANGE %s %s", hi->handle, hi->cookie->data);
2663 break;
2664 case ALLOWAUTH: {
2665 char *mask = generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT);
2666 set_user_handle_info(user, hi, 1);
2667 nickserv_addmask(user, hi, mask);
2668 reply("NSMSG_AUTH_SUCCESS");
2669 free(mask);
2670 break;
2671 }
2672 default:
2673 reply("NSMSG_BAD_COOKIE_TYPE", hi->cookie->type);
2674 log_module(NS_LOG, LOG_ERROR, "Bad cookie type %d for account %s.", hi->cookie->type, hi->handle);
2675 break;
2676 }
2677
2678 nickserv_eat_cookie(hi->cookie);
2679
2680 process_adduser_pending(user);
2681
2682 return 1;
2683}
2684
2685static NICKSERV_FUNC(cmd_oregnick) {
2686 const char *nick;
2687 struct handle_info *target;
2688 struct nick_info *ni;
2689
2690 NICKSERV_MIN_PARMS(3);
2691 if (!(target = modcmd_get_handle_info(user, argv[1])))
2692 return 0;
2693 nick = argv[2];
2694 if (!is_registerable_nick(nick)) {
2695 reply("NSMSG_BAD_NICK", nick);
2696 return 0;
2697 }
2698 ni = dict_find(nickserv_nick_dict, nick, NULL);
2699 if (ni) {
2700 reply("NSMSG_NICK_EXISTS", nick);
2701 return 0;
2702 }
2703 register_nick(nick, target);
2704 reply("NSMSG_OREGNICK_SUCCESS", nick, target->handle);
2705 return 1;
2706}
2707
2708static NICKSERV_FUNC(cmd_regnick) {
2709 unsigned n;
2710 struct nick_info *ni;
2711
2712 if (!is_registerable_nick(user->nick)) {
2713 reply("NSMSG_BAD_NICK", user->nick);
2714 return 0;
2715 }
2716 /* count their nicks, see if it's too many */
2717 for (n=0,ni=user->handle_info->nicks; ni; n++,ni=ni->next) ;
2718 if (n >= nickserv_conf.nicks_per_handle) {
2719 reply("NSMSG_TOO_MANY_NICKS");
2720 return 0;
2721 }
2722 ni = dict_find(nickserv_nick_dict, user->nick, NULL);
2723 if (ni) {
2724 reply("NSMSG_NICK_EXISTS", user->nick);
2725 return 0;
2726 }
2727 register_nick(user->nick, user->handle_info);
2728 reply("NSMSG_REGNICK_SUCCESS", user->nick);
2729 return 1;
2730}
2731
2732static NICKSERV_FUNC(cmd_pass)
2733{
2734 struct handle_info *hi;
2735 char *old_pass, *new_pass;
2736 char crypted[MD5_CRYPT_LENGTH+1];
2737#ifdef WITH_LDAP
2738 int ldap_result;
2739#endif
2740
2741 NICKSERV_MIN_PARMS(3);
2742 hi = user->handle_info;
2743 old_pass = argv[1];
2744 new_pass = argv[2];
2745 argv[2] = "****";
2746 if (!is_secure_password(hi->handle, new_pass, user)) return 0;
2747
2748#ifdef WITH_LDAP
2749 if(nickserv_conf.ldap_enable) {
2750 ldap_result = ldap_check_auth(hi->handle, old_pass);
2751 if(ldap_result != LDAP_SUCCESS) {
2752 if(ldap_result == LDAP_INVALID_CREDENTIALS)
2753 reply("NSMSG_PASSWORD_INVALID");
2754 else
2755 reply("NSMSG_LDAP_FAIL", ldap_err2string(ldap_result));
2756 return 0;
2757 }
2758 }else
2759#endif
2760 if (!checkpass(old_pass, hi->passwd)) {
2761 argv[1] = "BADPASS";
2762 reply("NSMSG_PASSWORD_INVALID");
2763 return 0;
2764 }
2765 cryptpass(new_pass, crypted);
2766#ifdef WITH_LDAP
2767 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
2768 int rc;
2769 if((rc = ldap_do_modify(hi->handle, crypted, NULL)) != LDAP_SUCCESS) {
2770 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
2771 return 0;
2772 }
2773 }
2774#endif
2775 //cryptpass(new_pass, hi->passwd);
2776 strcpy(hi->passwd, crypted);
2777 if (nickserv_conf.sync_log)
2778 SyncLog("PASSCHANGE %s %s", hi->handle, hi->passwd);
2779 argv[1] = "****";
2780 reply("NSMSG_PASS_SUCCESS");
2781 return 1;
2782}
2783
2784static int
2785nickserv_addmask(struct userNode *user, struct handle_info *hi, const char *mask)
2786{
2787 unsigned int i;
2788 char *new_mask = canonicalize_hostmask(strdup(mask));
2789 for (i=0; i<hi->masks->used; i++) {
2790 if (!irccasecmp(new_mask, hi->masks->list[i])) {
2791 send_message(user, nickserv, "NSMSG_ADDMASK_ALREADY", new_mask);
2792 free(new_mask);
2793 return 0;
2794 }
2795 }
2796 string_list_append(hi->masks, new_mask);
2797 send_message(user, nickserv, "NSMSG_ADDMASK_SUCCESS", new_mask);
2798 return 1;
2799}
2800
2801static NICKSERV_FUNC(cmd_addmask)
2802{
2803 if (argc < 2) {
2804 char *mask = generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT);
2805 int res = nickserv_addmask(user, user->handle_info, mask);
2806 free(mask);
2807 return res;
2808 } else {
2809 if (!is_gline(argv[1])) {
2810 reply("NSMSG_MASK_INVALID", argv[1]);
2811 return 0;
2812 }
2813 return nickserv_addmask(user, user->handle_info, argv[1]);
2814 }
2815}
2816
2817static NICKSERV_FUNC(cmd_oaddmask)
2818{
2819 struct handle_info *hi;
2820
2821 NICKSERV_MIN_PARMS(3);
2822 if (!(hi = get_victim_oper(user, argv[1])))
2823 return 0;
2824 return nickserv_addmask(user, hi, argv[2]);
2825}
2826
2827static int
2828nickserv_delmask(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, const char *del_mask, int force)
2829{
2830 unsigned int i;
2831 for (i=0; i<hi->masks->used; i++) {
2832 if (!strcmp(del_mask, hi->masks->list[i])) {
2833 char *old_mask = hi->masks->list[i];
2834 if (hi->masks->used == 1 && !force) {
2835 reply("NSMSG_DELMASK_NOTLAST");
2836 return 0;
2837 }
2838 hi->masks->list[i] = hi->masks->list[--hi->masks->used];
2839 reply("NSMSG_DELMASK_SUCCESS", old_mask);
2840 free(old_mask);
2841 return 1;
2842 }
2843 }
2844 reply("NSMSG_DELMASK_NOT_FOUND");
2845 return 0;
2846}
2847
2848static NICKSERV_FUNC(cmd_delmask)
2849{
2850 NICKSERV_MIN_PARMS(2);
2851 return nickserv_delmask(cmd, user, user->handle_info, argv[1], 0);
2852}
2853
2854static NICKSERV_FUNC(cmd_odelmask)
2855{
2856 struct handle_info *hi;
2857 NICKSERV_MIN_PARMS(3);
2858 if (!(hi = get_victim_oper(user, argv[1])))
2859 return 0;
2860 return nickserv_delmask(cmd, user, hi, argv[2], 1);
2861}
2862
2863int
2864nickserv_modify_handle_flags(struct userNode *user, struct userNode *bot, const char *str, unsigned long *padded, unsigned long *premoved) {
2865 unsigned int nn, add = 1, pos;
2866 unsigned long added, removed, flag;
2867
2868 for (added=removed=nn=0; str[nn]; nn++) {
2869 switch (str[nn]) {
2870 case '+': add = 1; break;
2871 case '-': add = 0; break;
2872 default:
2873 if (!(pos = handle_inverse_flags[(unsigned char)str[nn]])) {
2874 send_message(user, bot, "NSMSG_INVALID_FLAG", str[nn]);
2875 return 0;
2876 }
2877 if (user && (user->handle_info->opserv_level < flag_access_levels[pos-1])) {
2878 /* cheesy avoidance of looking up the flag name.. */
2879 send_message(user, bot, "NSMSG_FLAG_PRIVILEGED", str[nn]);
2880 return 0;
2881 }
2882 flag = 1 << (pos - 1);
2883 if (add)
2884 added |= flag, removed &= ~flag;
2885 else
2886 removed |= flag, added &= ~flag;
2887 break;
2888 }
2889 }
2890 *padded = added;
2891 *premoved = removed;
2892 return 1;
2893}
2894
2895static int
2896nickserv_apply_flags(struct userNode *user, struct handle_info *hi, const char *flags)
2897{
2898 unsigned long before, after, added, removed;
2899 struct userNode *uNode;
2900
2901 before = hi->flags & (HI_FLAG_SUPPORT_HELPER|HI_FLAG_NETWORK_HELPER);
2902 if (!nickserv_modify_handle_flags(user, nickserv, flags, &added, &removed))
2903 return 0;
2904 hi->flags = (hi->flags | added) & ~removed;
2905 after = hi->flags & (HI_FLAG_SUPPORT_HELPER|HI_FLAG_NETWORK_HELPER);
2906
2907 /* Strip helping flag if they're only a support helper and not
2908 * currently in #support. */
2909 if (HANDLE_FLAGGED(hi, HELPING) && (after == HI_FLAG_SUPPORT_HELPER)) {
2910 struct channelList *schannels;
2911 unsigned int ii;
2912 schannels = chanserv_support_channels();
2913 for (ii = 0; ii < schannels->used; ++ii)
2914 if (find_handle_in_channel(schannels->list[ii], hi, NULL))
2915 break;
2916 if (ii == schannels->used)
2917 HANDLE_CLEAR_FLAG(hi, HELPING);
2918 }
2919
2920 if (after && !before) {
2921 /* Add user to current helper list. */
2922 for (uNode = hi->users; uNode; uNode = uNode->next_authed)
2923 userList_append(&curr_helpers, uNode);
2924 } else if (!after && before) {
2925 /* Remove user from current helper list. */
2926 for (uNode = hi->users; uNode; uNode = uNode->next_authed)
2927 userList_remove(&curr_helpers, uNode);
2928 }
2929
2930 return 1;
2931}
2932
2933static void
2934set_list(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, int override)
2935{
2936 option_func_t *opt;
2937 unsigned int i;
2938 char *set_display[] = {
2939 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2940 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2941 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2942 };
2943
2944 reply("NSMSG_SETTING_LIST");
2945 reply("NSMSG_SETTING_LIST_HEADER");
2946
2947 /* Do this so options are presented in a consistent order. */
2948 for (i = 0; i < ArrayLength(set_display); ++i)
2949 if ((opt = dict_find(nickserv_opt_dict, set_display[i], NULL)))
2950 opt(cmd, user, hi, override, 0, NULL);
2951 reply("NSMSG_SETTING_LIST_END");
2952}
2953
2954static NICKSERV_FUNC(cmd_set)
2955{
2956 struct handle_info *hi;
2957 option_func_t *opt;
2958
2959 hi = user->handle_info;
2960 if (argc < 2) {
2961 set_list(cmd, user, hi, 0);
2962 return 1;
2963 }
2964 if (!(opt = dict_find(nickserv_opt_dict, argv[1], NULL))) {
2965 reply("NSMSG_INVALID_OPTION", argv[1]);
2966 return 0;
2967 }
2968 return opt(cmd, user, hi, 0, argc-1, argv+1);
2969}
2970
2971static NICKSERV_FUNC(cmd_oset)
2972{
2973 struct handle_info *hi;
2974 option_func_t *opt;
2975
2976 NICKSERV_MIN_PARMS(2);
2977
2978 if (!(hi = get_victim_oper(user, argv[1])))
2979 return 0;
2980
2981 if (argc < 3) {
2982 set_list(cmd, user, hi, 0);
2983 return 1;
2984 }
2985
2986 if (!(opt = dict_find(nickserv_opt_dict, argv[2], NULL))) {
2987 reply("NSMSG_INVALID_OPTION", argv[2]);
2988 return 0;
2989 }
2990
2991 return opt(cmd, user, hi, 1, argc-2, argv+2);
2992}
2993
2994static OPTION_FUNC(opt_info)
2995{
2996 const char *info;
2997 if (argc > 1) {
2998 if ((argv[1][0] == '*') && (argv[1][1] == 0)) {
2999 free(hi->infoline);
3000 hi->infoline = NULL;
3001 } else {
3002 hi->infoline = strdup(unsplit_string(argv+1, argc-1, NULL));
3003 }
3004 }
3005
3006 info = hi->infoline ? hi->infoline : user_find_message(user, "MSG_NONE");
3007 reply("NSMSG_SET_INFO", info);
3008 return 1;
3009}
3010
3011static OPTION_FUNC(opt_width)
3012{
3013 if (argc > 1)
3014 hi->screen_width = strtoul(argv[1], NULL, 0);
3015
3016 if ((hi->screen_width > 0) && (hi->screen_width < MIN_LINE_SIZE))
3017 hi->screen_width = MIN_LINE_SIZE;
3018 else if (hi->screen_width > MAX_LINE_SIZE)
3019 hi->screen_width = MAX_LINE_SIZE;
3020
3021 reply("NSMSG_SET_WIDTH", hi->screen_width);
3022 return 1;
3023}
3024
3025static OPTION_FUNC(opt_tablewidth)
3026{
3027 if (argc > 1)
3028 hi->table_width = strtoul(argv[1], NULL, 0);
3029
3030 if ((hi->table_width > 0) && (hi->table_width < MIN_LINE_SIZE))
3031 hi->table_width = MIN_LINE_SIZE;
3032 else if (hi->screen_width > MAX_LINE_SIZE)
3033 hi->table_width = MAX_LINE_SIZE;
3034
3035 reply("NSMSG_SET_TABLEWIDTH", hi->table_width);
3036 return 1;
3037}
3038
3039static OPTION_FUNC(opt_color)
3040{
3041 if (argc > 1) {
3042 if (enabled_string(argv[1]))
3043 HANDLE_SET_FLAG(hi, MIRC_COLOR);
3044 else if (disabled_string(argv[1]))
3045 HANDLE_CLEAR_FLAG(hi, MIRC_COLOR);
3046 else {
3047 reply("MSG_INVALID_BINARY", argv[1]);
3048 return 0;
3049 }
3050 }
3051
3052 reply("NSMSG_SET_COLOR", user_find_message(user, HANDLE_FLAGGED(hi, MIRC_COLOR) ? "MSG_ON" : "MSG_OFF"));
3053 return 1;
3054}
3055
3056static OPTION_FUNC(opt_privmsg)
3057{
3058 if (argc > 1) {
3059 if (enabled_string(argv[1]))
3060 HANDLE_SET_FLAG(hi, USE_PRIVMSG);
3061 else if (disabled_string(argv[1]))
3062 HANDLE_CLEAR_FLAG(hi, USE_PRIVMSG);
3063 else {
3064 reply("MSG_INVALID_BINARY", argv[1]);
3065 return 0;
3066 }
3067 }
3068
3069 reply("NSMSG_SET_PRIVMSG", user_find_message(user, HANDLE_FLAGGED(hi, USE_PRIVMSG) ? "MSG_ON" : "MSG_OFF"));
3070 return 1;
3071}
3072
3073static OPTION_FUNC(opt_autohide)
3074{
3075 if (argc > 1) {
3076 if (enabled_string(argv[1]))
3077 HANDLE_SET_FLAG(hi, AUTOHIDE);
3078 else if (disabled_string(argv[1]))
3079 HANDLE_CLEAR_FLAG(hi, AUTOHIDE);
3080 else {
3081 reply("MSG_INVALID_BINARY", argv[1]);
3082 return 0;
3083 }
3084 }
3085
3086 reply("NSMSG_SET_AUTOHIDE", user_find_message(user, HANDLE_FLAGGED(hi, AUTOHIDE) ? "MSG_ON" : "MSG_OFF"));
3087 return 1;
3088}
3089
3090static OPTION_FUNC(opt_style)
3091{
3092 char *style;
3093
3094 if (argc > 1) {
3095 if (!irccasecmp(argv[1], "Clean"))
3096 hi->userlist_style = HI_STYLE_CLEAN;
3097 else if (!irccasecmp(argv[1], "Advanced"))
3098 hi->userlist_style = HI_STYLE_ADVANCED;
3099 else if (!irccasecmp(argv[1], "Classic"))
3100 hi->userlist_style = HI_STYLE_CLASSIC;
3101 else /* Default to normal */
3102 hi->userlist_style = HI_STYLE_NORMAL;
3103 } /* TODO: give error if unknow style is chosen */
3104
3105 switch (hi->userlist_style) {
3106 case HI_STYLE_ADVANCED:
3107 style = "Advanced";
3108 break;
3109 case HI_STYLE_CLASSIC:
3110 style = "Classic";
3111 break;
3112 case HI_STYLE_CLEAN:
3113 style = "Clean";
3114 break;
3115 case HI_STYLE_NORMAL:
3116 default:
3117 style = "Normal";
3118 }
3119
3120 reply("NSMSG_SET_STYLE", style);
3121 return 1;
3122}
3123
3124static OPTION_FUNC(opt_announcements)
3125{
3126 const char *choice;
3127
3128 if (argc > 1) {
3129 if (enabled_string(argv[1]))
3130 hi->announcements = 'y';
3131 else if (disabled_string(argv[1]))
3132 hi->announcements = 'n';
3133 else if (!strcmp(argv[1], "?") || !irccasecmp(argv[1], "default"))
3134 hi->announcements = '?';
3135 else {
3136 reply("NSMSG_INVALID_ANNOUNCE", argv[1]);
3137 return 0;
3138 }
3139 }
3140
3141 switch (hi->announcements) {
3142 case 'y': choice = user_find_message(user, "MSG_ON"); break;
3143 case 'n': choice = user_find_message(user, "MSG_OFF"); break;
3144 case '?': choice = "default"; break;
3145 default: choice = "unknown"; break;
3146 }
3147 reply("NSMSG_SET_ANNOUNCEMENTS", choice);
3148 return 1;
3149}
3150
3151static OPTION_FUNC(opt_password)
3152{
3153 char crypted[MD5_CRYPT_LENGTH+1];
3154 if(argc < 2) {
3155 return 0;
3156 }
3157 if (!override) {
3158 reply("NSMSG_USE_CMD_PASS");
3159 return 0;
3160 }
3161
3162 cryptpass(argv[1], crypted);
3163#ifdef WITH_LDAP
3164 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
3165 int rc;
3166 if((rc = ldap_do_modify(hi->handle, crypted, NULL)) != LDAP_SUCCESS) {
3167 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
3168 return 0;
3169 }
3170 }
3171#endif
3172 strcpy(hi->passwd, crypted);
3173 if (nickserv_conf.sync_log)
3174 SyncLog("PASSCHANGE %s %s", hi->handle, hi->passwd);
3175
3176 reply("NSMSG_SET_PASSWORD", "***");
3177 return 1;
3178}
3179
3180static OPTION_FUNC(opt_flags)
3181{
3182 char flags[33];
3183 unsigned int ii, flen;
3184
3185 if (!override) {
3186 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3187 return 0;
3188 }
3189
3190 if (argc > 1)
3191 nickserv_apply_flags(user, hi, argv[1]);
3192
3193 for (ii = flen = 0; handle_flags[ii]; ii++)
3194 if (hi->flags & (1 << ii))
3195 flags[flen++] = handle_flags[ii];
3196 flags[flen] = '\0';
3197 if (hi->flags)
3198 reply("NSMSG_SET_FLAGS", flags);
3199 else
3200 reply("NSMSG_SET_FLAGS", user_find_message(user, "MSG_NONE"));
3201 return 1;
3202}
3203
3204static OPTION_FUNC(opt_email)
3205{
3206 if (argc > 1) {
3207 const char *str;
3208 if (!valid_email(argv[1])) {
3209 reply("NSMSG_BAD_EMAIL_ADDR");
3210 return 0;
3211 }
3212 if ((str = mail_prohibited_address(argv[1]))) {
3213 reply("NSMSG_EMAIL_PROHIBITED", argv[1], str);
3214 return 0;
3215 }
3216 if (hi->email_addr && !irccasecmp(hi->email_addr, argv[1]))
3217 reply("NSMSG_EMAIL_SAME");
3218 else if (!override)
3219 nickserv_make_cookie(user, hi, EMAIL_CHANGE, argv[1], 0);
3220 else {
3221#ifdef WITH_LDAP
3222 if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) {
3223 int rc;
3224 if((rc = ldap_do_modify(hi->handle, NULL, argv[1])) != LDAP_SUCCESS) {
3225 reply("NSMSG_LDAP_FAIL", ldap_err2string(rc));
3226 return 0;
3227 }
3228 }
3229#endif
3230 nickserv_set_email_addr(hi, argv[1]);
3231 if (hi->cookie)
3232 nickserv_eat_cookie(hi->cookie);
3233 reply("NSMSG_SET_EMAIL", visible_email_addr(user, hi));
3234 }
3235 } else
3236 reply("NSMSG_SET_EMAIL", visible_email_addr(user, hi));
3237 return 1;
3238}
3239
3240static OPTION_FUNC(opt_maxlogins)
3241{
3242 unsigned char maxlogins;
3243 if (argc > 1) {
3244 maxlogins = strtoul(argv[1], NULL, 0);
3245 if ((maxlogins > nickserv_conf.hard_maxlogins) && !override) {
3246 reply("NSMSG_BAD_MAX_LOGINS", nickserv_conf.hard_maxlogins);
3247 return 0;
3248 }
3249 hi->maxlogins = maxlogins;
3250 }
3251 maxlogins = hi->maxlogins ? hi->maxlogins : nickserv_conf.default_maxlogins;
3252 reply("NSMSG_SET_MAXLOGINS", maxlogins);
3253 return 1;
3254}
3255
3256static OPTION_FUNC(opt_advanced)
3257{
3258 if (argc > 1) {
3259 if (enabled_string(argv[1]))
3260 HANDLE_SET_FLAG(hi, ADVANCED);
3261 else if (disabled_string(argv[1]))
3262 HANDLE_CLEAR_FLAG(hi, ADVANCED);
3263 else {
3264 reply("MSG_INVALID_BINARY", argv[1]);
3265 return 0;
3266 }
3267 }
3268
3269 reply("NSMSG_SET_ADVANCED", user_find_message(user, HANDLE_FLAGGED(hi, ADVANCED) ? "MSG_ON" : "MSG_OFF"));
3270 return 1;
3271}
3272
3273static OPTION_FUNC(opt_language)
3274{
3275 struct language *lang;
3276 if (argc > 1) {
3277 lang = language_find(argv[1]);
3278 if (irccasecmp(lang->name, argv[1]))
3279 reply("NSMSG_LANGUAGE_NOT_FOUND", argv[1], lang->name);
3280 hi->language = lang;
3281 }
3282 reply("NSMSG_SET_LANGUAGE", hi->language->name);
3283 return 1;
3284}
3285
3286static OPTION_FUNC(opt_karma)
3287{
3288 if (!override) {
3289 send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]);
3290 return 0;
3291 }
3292
3293 if (argc > 1) {
3294 if (argv[1][0] == '+' && isdigit(argv[1][1])) {
3295 hi->karma += strtoul(argv[1] + 1, NULL, 10);
3296 } else if (argv[1][0] == '-' && isdigit(argv[1][1])) {
3297 hi->karma -= strtoul(argv[1] + 1, NULL, 10);
3298 } else {
3299 send_message(user, nickserv, "NSMSG_INVALID_KARMA", argv[1]);
3300 }
3301 }
3302
3303 send_message(user, nickserv, "NSMSG_SET_KARMA", hi->karma);
3304 return 1;
3305}
3306
3307/* Called from opserv from cmd_access */
3308int
3309oper_try_set_access(struct userNode *user, struct userNode *bot, struct handle_info *target, unsigned int new_level) {
3310 if (!oper_has_access(user, bot, nickserv_conf.modoper_level, 0))
3311 return 0;
3312 if ((user->handle_info->opserv_level < target->opserv_level)
3313 || ((user->handle_info->opserv_level == target->opserv_level)
3314 && (user->handle_info->opserv_level < 1000))) {
3315 send_message(user, bot, "MSG_USER_OUTRANKED", target->handle);
3316 return 0;
3317 }
3318 if ((user->handle_info->opserv_level < new_level)
3319 || ((user->handle_info->opserv_level == new_level)
3320 && (user->handle_info->opserv_level < 1000))) {
3321 send_message(user, bot, "NSMSG_OPSERV_LEVEL_BAD");
3322 return 0;
3323 }
3324 if (user->handle_info == target) {
3325 send_message(user, bot, "MSG_STUPID_ACCESS_CHANGE");
3326 return 0;
3327 }
3328#ifdef WITH_LDAP
3329 if(nickserv_conf.ldap_enable && *(nickserv_conf.ldap_oper_group_dn) && *(nickserv_conf.ldap_admin_dn)) {
3330 int rc;
3331 if(new_level > nickserv_conf.ldap_oper_group_level)
3332 rc = ldap_add2group(target->handle, nickserv_conf.ldap_oper_group_dn);
3333 else
3334 rc = ldap_delfromgroup(target->handle, nickserv_conf.ldap_oper_group_dn);
3335 if(rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS && rc != LDAP_NO_SUCH_ATTRIBUTE) {
3336 send_message(user, bot, "NSMSG_LDAP_FAIL", ldap_err2string(rc));
3337 return 0;
3338 }
3339 }
3340#endif
3341 if (target->opserv_level == new_level)
3342 return 0;
3343 log_module(NS_LOG, LOG_INFO, "Account %s setting oper level for account %s to %d (from %d).",
3344 user->handle_info->handle, target->handle, new_level, target->opserv_level);
3345 target->opserv_level = new_level;
3346 return 1;
3347}
3348
3349static OPTION_FUNC(opt_level)
3350{
3351 int res;
3352
3353 if (!override) {
3354 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3355 return 0;
3356 }
3357
3358 res = (argc > 1) ? oper_try_set_access(user, nickserv, hi, strtoul(argv[1], NULL, 0)) : 0;
3359 reply("NSMSG_SET_LEVEL", hi->opserv_level);
3360 return res;
3361}
3362
3363static OPTION_FUNC(opt_epithet)
3364{
3365 if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_epithet_level, 0)) {
3366 char *epithet;
3367 struct userNode *target, *next_un;
3368
3369 if (!override) {
3370 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3371 return 0;
3372 }
3373
3374 epithet = unsplit_string(argv+1, argc-1, NULL);
3375
3376 if (hi->epithet)
3377 free(hi->epithet);
3378 if ((epithet[0] == '*') && !epithet[1])
3379 hi->epithet = NULL;
3380 else
3381 hi->epithet = strdup(epithet);
3382
3383 for (target = hi->users; target; target = next_un) {
3384 irc_swhois(nickserv, target, hi->epithet);
3385
3386 next_un = target->next_authed;
3387 }
3388 }
3389
3390 if (hi->epithet)
3391 reply("NSMSG_SET_EPITHET", hi->epithet);
3392 else
3393 reply("NSMSG_SET_EPITHET", user_find_message(user, "MSG_NONE"));
3394 return 1;
3395}
3396
3397static OPTION_FUNC(opt_title)
3398{
3399 char *title;
3400 const char *none;
3401 char *sptr;
3402
3403 if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_title_level, 0)) {
3404 if (!override) {
3405 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3406 return 0;
3407 }
3408
3409 title = argv[1];
3410 if(!strcmp(title, "*")) {
3411 free(hi->fakehost);
3412 hi->fakehost = NULL;
3413 }
3414 else {
3415 if (strchr(title, '.')) {
3416 reply("NSMSG_TITLE_INVALID");
3417 return 0;
3418 }
3419 /* Alphanumeric titles only. */
3420 for(sptr = title; *sptr; sptr++) {
3421 if(!isalnum(*sptr) && *sptr != '-') {
3422 reply("NSMSG_TITLE_INVALID");
3423 return 0;
3424 }
3425 }
3426 if ((strlen(user->handle_info->handle) + strlen(title) +
3427 strlen(nickserv_conf.titlehost_suffix) + 2) > HOSTLEN) {
3428 reply("NSMSG_TITLE_TRUNCATED");
3429 return 0;
3430 }
3431 free(hi->fakehost);
3432 hi->fakehost = malloc(strlen(title)+2);
3433 hi->fakehost[0] = '.';
3434 strcpy(hi->fakehost+1, title);
3435 }
3436 apply_fakehost(hi);
3437 } else if (hi->fakehost && (hi->fakehost[0] == '.'))
3438 title = hi->fakehost + 1;
3439 else {
3440 /* If theres no title set then the default title will therefore
3441 be the first part of hidden_host in x3.conf, so for
3442 consistency with opt_fakehost we will print this here.
3443 This isnt actually used in P10, its just handled to keep from crashing... */
3444 char *hs, *hidden_suffix, *rest;
3445
3446 hs = conf_get_data("server/hidden_host", RECDB_QSTRING);
3447 hidden_suffix = strdup(hs);
3448
3449 /* Yes we do this twice */
3450 if((rest = strchr(hidden_suffix, '.')))
3451 {
3452 *rest = '\0';
3453 title = hidden_suffix;
3454 }
3455 else
3456 {
3457 /* A lame default if someone configured hidden_host to something lame */
3458 title = strdup("users");
3459 free(hidden_suffix);
3460 }
3461
3462 }
3463
3464 if (!title)
3465 none = user_find_message(user, "MSG_NONE");
3466 send_message(user, nickserv, "NSMSG_SET_TITLE", title ? title : none);
3467 return 1;
3468}
3469
3470int
3471check_vhost(char *vhost, struct userNode *user, struct svccmd *cmd)
3472{
3473 unsigned int y;
3474
3475 // check for a dot in the vhost
3476 if(strchr(vhost, '.') == NULL) {
3477 reply("NSMSG_NOT_VALID_FAKEHOST_DOT", vhost);
3478 return 0;
3479 }
3480
3481 // check for a @ in the vhost
3482 if(strchr(vhost, '@') != NULL) {
3483 reply("NSMSG_NOT_VALID_FAKEHOST_AT", vhost);
3484 return 0;
3485 }
3486
3487 // check for denied words, inspired by monk at paki.sex
3488 for(y = 0; y < nickserv_conf.denied_fakehost_words->used; y++) {
3489 if(strstr(vhost, nickserv_conf.denied_fakehost_words->list[y]) != NULL) {
3490 reply("NSMSG_DENIED_FAKEHOST_WORD", vhost, nickserv_conf.denied_fakehost_words->list[y]);
3491 return 0;
3492 }
3493 }
3494
3495 // check for ircu's HOSTLEN length.
3496 if(strlen(vhost) >= HOSTLEN) {
3497 reply("NSMSG_NOT_VALID_FAKEHOST_LEN", vhost);
3498 return 0;
3499 }
3500
3501 /* This can be handled by the regex now if desired.
3502 if (vhost[strspn(vhost, "0123456789.")]) {
3503 hostname = vhost + strlen(vhost);
3504 for (depth = 1; depth && (hostname > vhost); depth--) {
3505 hostname--;
3506 while ((hostname > vhost) && (*hostname != '.')) hostname--;
3507 }
3508
3509 if (*hostname == '.') hostname++; * advance past last dot we saw *
3510 if(strlen(hostname) > 4) {
3511 reply("NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost);
3512 return 0;
3513 }
3514 }
3515 */
3516 /* test either regex or as valid handle */
3517 if (nickserv_conf.valid_fakehost_regex_set) {
3518 int err = regexec(&nickserv_conf.valid_fakehost_regex, vhost, 0, 0, 0);
3519 if (err) {
3520 char buff[256];
3521 buff[regerror(err, &nickserv_conf.valid_fakehost_regex, buff, sizeof(buff))] = 0;
3522 log_module(NS_LOG, LOG_INFO, "regexec error: %s (%d)", buff, err);
3523 }
3524 if(err == REG_NOMATCH) {
3525 reply("NSMSG_NOT_VALID_FAKEHOST_REGEX", vhost);
3526 return 0;
3527 }
3528 }
3529
3530
3531 return 1;
3532}
3533
3534static OPTION_FUNC(opt_fakehost)
3535{
3536 const char *fake;
3537
3538 if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_fakehost_level, 0)) {
3539 if (!override) {
3540 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3541 return 0;
3542 }
3543
3544 fake = argv[1];
3545 if ((strlen(fake) > HOSTLEN) || (fake[0] == '.')) {
3546 reply("NSMSG_FAKEHOST_INVALID", HOSTLEN);
3547 return 0;
3548 }
3549 if (!strcmp(fake, "*")) {
3550 if(hi->fakehost) {
3551 free(hi->fakehost);
3552 hi->fakehost = NULL;
3553 }
3554 }
3555 else if (!check_vhost(argv[1], user, cmd)) {
3556 /* check_vhost takes care of error reply */
3557 return 0;
3558 }
3559 else {
3560 if(hi->fakehost)
3561 free(hi->fakehost);
3562 hi->fakehost = strdup(fake);
3563 }
3564 apply_fakehost(hi);
3565 fake = hi->fakehost;
3566 } else
3567 fake = generate_fakehost(hi);
3568
3569 /* Tell them we set the host */
3570 if (!fake)
3571 fake = user_find_message(user, "MSG_NONE");
3572 reply("NSMSG_SET_FAKEHOST", fake);
3573 return 1;
3574}
3575
3576static OPTION_FUNC(opt_note)
3577{
3578 if (!override) {
3579 reply("MSG_SETTING_PRIVILEGED", argv[0]);
3580 return 0;
3581 }
3582
3583 if (argc > 1) {
3584 char *text = unsplit_string(argv + 1, argc - 1, NULL);
3585
3586 if (hi->note)
3587 free(hi->note);
3588
3589 if ((text[0] == '*') && !text[1])
3590 hi->note = NULL;
3591 else {
3592 if (!(hi->note = nickserv_add_note(user->handle_info->handle, now, text)))
3593 hi->note = NULL;
3594 }
3595 }
3596
3597 reply("NSMSG_SET_NOTE", hi->note ? hi->note->note : user_find_message(user, "MSG_NONE"));
3598 return 1;
3599}
3600
3601static NICKSERV_FUNC(cmd_reclaim)
3602{
3603 struct handle_info *hi;
3604 struct nick_info *ni;
3605 struct userNode *victim;
3606
3607 NICKSERV_MIN_PARMS(2);
3608 hi = user->handle_info;
3609 ni = dict_find(nickserv_nick_dict, argv[1], 0);
3610 if (!ni) {
3611 reply("NSMSG_UNKNOWN_NICK", argv[1]);
3612 return 0;
3613 }
3614 if (ni->owner != user->handle_info) {
3615 reply("NSMSG_NOT_YOUR_NICK", ni->nick);
3616 return 0;
3617 }
3618 victim = GetUserH(ni->nick);
3619 if (!victim) {
3620 reply("MSG_NICK_UNKNOWN", ni->nick);
3621 return 0;
3622 }
3623 if (victim == user) {
3624 reply("NSMSG_NICK_USER_YOU");
3625 return 0;
3626 }
3627 nickserv_reclaim(victim, ni, nickserv_conf.reclaim_action);
3628 switch (nickserv_conf.reclaim_action) {
3629 case RECLAIM_NONE: reply("NSMSG_RECLAIMED_NONE"); break;
3630 case RECLAIM_WARN: reply("NSMSG_RECLAIMED_WARN", victim->nick); break;
3631 case RECLAIM_SVSNICK: reply("NSMSG_RECLAIMED_SVSNICK", victim->nick); break;
3632 case RECLAIM_KILL: reply("NSMSG_RECLAIMED_KILL", victim->nick); break;
3633 }
3634 return 1;
3635}
3636
3637static NICKSERV_FUNC(cmd_unregnick)
3638{
3639 const char *nick;
3640 struct handle_info *hi;
3641 struct nick_info *ni;
3642
3643 hi = user->handle_info;
3644 nick = (argc < 2) ? user->nick : (const char*)argv[1];
3645 ni = dict_find(nickserv_nick_dict, nick, NULL);
3646 if (!ni) {
3647 reply("NSMSG_UNKNOWN_NICK", nick);
3648 return 0;
3649 }
3650 if (hi != ni->owner) {
3651 reply("NSMSG_NOT_YOUR_NICK", nick);
3652 return 0;
3653 }
3654 reply("NSMSG_UNREGNICK_SUCCESS", ni->nick);
3655 delete_nick(ni);
3656 return 1;
3657}
3658
3659static NICKSERV_FUNC(cmd_ounregnick)
3660{
3661 struct nick_info *ni;
3662
3663 NICKSERV_MIN_PARMS(2);
3664 if (!(ni = get_nick_info(argv[1]))) {
3665 reply("NSMSG_NICK_NOT_REGISTERED", argv[1]);
3666 return 0;
3667 }
3668 if (!oper_outranks(user, ni->owner))
3669 return 0;
3670 reply("NSMSG_UNREGNICK_SUCCESS", ni->nick);
3671 delete_nick(ni);
3672 return 1;
3673}
3674
3675static NICKSERV_FUNC(cmd_unregister)
3676{
3677 struct handle_info *hi;
3678 char *passwd;
3679
3680 NICKSERV_MIN_PARMS(2);
3681 hi = user->handle_info;
3682 passwd = argv[1];
3683 argv[1] = "****";
3684 if (checkpass(passwd, hi->passwd)) {
3685 if(nickserv_unregister_handle(hi, user, cmd->parent->bot))
3686 return 1;
3687 else
3688 return 0;
3689 } else {
3690 log_module(NS_LOG, LOG_INFO, "Account '%s' tried to unregister with the wrong password.", hi->handle);
3691 reply("NSMSG_PASSWORD_INVALID");
3692 return 0;
3693 }
3694}
3695
3696static NICKSERV_FUNC(cmd_ounregister)
3697{
3698 struct handle_info *hi;
3699 char reason[MAXLEN];
3700 int force;
3701
3702 NICKSERV_MIN_PARMS(2);
3703 if (!(hi = get_victim_oper(user, argv[1])))
3704 return 0;
3705
3706 if (HANDLE_FLAGGED(hi, NODELETE)) {
3707 reply("NSMSG_UNREGISTER_NODELETE", hi->handle);
3708 return 0;
3709 }
3710
3711 force = IsOper(user) && (argc > 2) && !irccasecmp(argv[2], "force");
3712 if (!force &&
3713 ((hi->flags & nickserv_conf.ounregister_flags)
3714 || hi->users
3715 || (hi->last_quit_host[0] && ((unsigned)(now - hi->lastseen) < nickserv_conf.ounregister_inactive)))) {
3716 reply((IsOper(user) ? "NSMSG_UNREGISTER_MUST_FORCE" : "NSMSG_UNREGISTER_CANNOT_FORCE"), hi->handle);
3717 return 0;
3718 }
3719 snprintf(reason, sizeof(reason), "%s unregistered account %s.", user->handle_info->handle, hi->handle);
3720 global_message(MESSAGE_RECIPIENT_STAFF, reason);
3721 if(nickserv_unregister_handle(hi, user, cmd->parent->bot))
3722 return 1;
3723 else
3724 return 0;
3725}
3726
3727static NICKSERV_FUNC(cmd_status)
3728{
3729 if (nickserv_conf.disable_nicks) {
3730 reply("NSMSG_GLOBAL_STATS_NONICK",
3731 dict_size(nickserv_handle_dict));
3732 } else {
3733 if (user->handle_info) {
3734 int cnt=0;
3735 struct nick_info *ni;
3736 for (ni=user->handle_info->nicks; ni; ni=ni->next) cnt++;
3737 reply("NSMSG_HANDLE_STATS", cnt);
3738 } else {
3739 reply("NSMSG_HANDLE_NONE");
3740 }
3741 reply("NSMSG_GLOBAL_STATS",
3742 dict_size(nickserv_handle_dict),
3743 dict_size(nickserv_nick_dict));
3744 }
3745 return 1;
3746}
3747
3748static NICKSERV_FUNC(cmd_ghost)
3749{
3750 struct userNode *target;
3751 char reason[MAXLEN];
3752
3753 NICKSERV_MIN_PARMS(2);
3754 if (!(target = GetUserH(argv[1]))) {
3755 reply("MSG_NICK_UNKNOWN", argv[1]);
3756 return 0;
3757 }
3758 if (target == user) {
3759 reply("NSMSG_CANNOT_GHOST_SELF");
3760 return 0;
3761 }
3762 if (!target->handle_info || (target->handle_info != user->handle_info)) {
3763 reply("NSMSG_CANNOT_GHOST_USER", target->nick);
3764 return 0;
3765 }
3766 snprintf(reason, sizeof(reason), "Ghost kill on account %s (requested by %s).", target->handle_info->handle, user->nick);
3767 DelUser(target, nickserv, 1, reason);
3768 reply("NSMSG_GHOST_KILLED", argv[1]);
3769 return 1;
3770}
3771
3772static NICKSERV_FUNC(cmd_vacation)
3773{
3774 HANDLE_SET_FLAG(user->handle_info, FROZEN);
3775 reply("NSMSG_ON_VACATION");
3776 return 1;
3777}
3778
3779static int
3780nickserv_saxdb_write(struct saxdb_context *ctx) {
3781 dict_iterator_t it;
3782 struct handle_info *hi;
3783 char flags[33];
3784
3785 for (it = dict_first(nickserv_handle_dict); it; it = iter_next(it)) {
3786 hi = iter_data(it);
3787 saxdb_start_record(ctx, iter_key(it), 0);
3788 if (hi->announcements != '?') {
3789 flags[0] = hi->announcements;
3790 flags[1] = 0;
3791 saxdb_write_string(ctx, KEY_ANNOUNCEMENTS, flags);
3792 }
3793 if (hi->cookie) {
3794 struct handle_cookie *cookie = hi->cookie;
3795 char *type;
3796
3797 switch (cookie->type) {
3798 case ACTIVATION: type = KEY_ACTIVATION; break;
3799 case PASSWORD_CHANGE: type = KEY_PASSWORD_CHANGE; break;
3800 case EMAIL_CHANGE: type = KEY_EMAIL_CHANGE; break;
3801 case ALLOWAUTH: type = KEY_ALLOWAUTH; break;
3802 default: type = NULL; break;
3803 }
3804 if (type) {
3805 saxdb_start_record(ctx, KEY_COOKIE, 0);
3806 saxdb_write_string(ctx, KEY_COOKIE_TYPE, type);
3807 saxdb_write_int(ctx, KEY_COOKIE_EXPIRES, cookie->expires);
3808 if (cookie->data)
3809 saxdb_write_string(ctx, KEY_COOKIE_DATA, cookie->data);
3810 saxdb_write_string(ctx, KEY_COOKIE, cookie->cookie);
3811 saxdb_end_record(ctx);
3812 }
3813 }
3814 if (hi->email_addr)
3815 saxdb_write_string(ctx, KEY_EMAIL_ADDR, hi->email_addr);
3816 if (hi->epithet)
3817 saxdb_write_string(ctx, KEY_EPITHET, hi->epithet);
3818 if (hi->note) {
3819 saxdb_start_record(ctx, KEY_NOTE_NOTE, 0);
3820 saxdb_write_string(ctx, KEY_NOTE_SETTER, hi->note->setter);
3821 saxdb_write_int(ctx, KEY_NOTE_DATE, hi->note->date);
3822 saxdb_write_string(ctx, KEY_NOTE_NOTE, hi->note->note);
3823 saxdb_end_record(ctx);
3824 }
3825
3826 if (hi->fakehost)
3827 saxdb_write_string(ctx, KEY_FAKEHOST, hi->fakehost);
3828 if (hi->flags) {
3829 int ii, flen;
3830
3831 for (ii=flen=0; handle_flags[ii]; ++ii)
3832 if (hi->flags & (1 << ii))
3833 flags[flen++] = handle_flags[ii];
3834 flags[flen] = 0;
3835 saxdb_write_string(ctx, KEY_FLAGS, flags);
3836 }
3837 if (hi->infoline)
3838 saxdb_write_string(ctx, KEY_INFO, hi->infoline);
3839 if (hi->last_quit_host[0])
3840 saxdb_write_string(ctx, KEY_LAST_QUIT_HOST, hi->last_quit_host);
3841 saxdb_write_int(ctx, KEY_LAST_SEEN, hi->lastseen);
3842 if (hi->karma != 0)
3843 saxdb_write_sint(ctx, KEY_KARMA, hi->karma);
3844 if (hi->masks->used)
3845 saxdb_write_string_list(ctx, KEY_MASKS, hi->masks);
3846 if (hi->ignores->used)
3847 saxdb_write_string_list(ctx, KEY_IGNORES, hi->ignores);
3848 if (hi->maxlogins)
3849 saxdb_write_int(ctx, KEY_MAXLOGINS, hi->maxlogins);
3850 if (hi->nicks) {
3851 struct string_list *slist;
3852 struct nick_info *ni;
3853
3854 slist = alloc_string_list(nickserv_conf.nicks_per_handle);
3855 for (ni = hi->nicks; ni; ni = ni->next) string_list_append(slist, ni->nick);
3856 saxdb_write_string_list(ctx, KEY_NICKS, slist);
3857 free(slist->list);
3858 free(slist);
3859 }
3860 if (hi->opserv_level)
3861 saxdb_write_int(ctx, KEY_OPSERV_LEVEL, hi->opserv_level);
3862 if (hi->language != lang_C)
3863 saxdb_write_string(ctx, KEY_LANGUAGE, hi->language->name);
3864 saxdb_write_string(ctx, KEY_PASSWD, hi->passwd);
3865 saxdb_write_int(ctx, KEY_REGISTER_ON, hi->registered);
3866 if (hi->screen_width)
3867 saxdb_write_int(ctx, KEY_SCREEN_WIDTH, hi->screen_width);
3868 if (hi->table_width)
3869 saxdb_write_int(ctx, KEY_TABLE_WIDTH, hi->table_width);
3870 flags[0] = hi->userlist_style;
3871 flags[1] = 0;
3872 saxdb_write_string(ctx, KEY_USERLIST_STYLE, flags);
3873 saxdb_end_record(ctx);
3874 }
3875
3876 return 0;
3877}
3878
3879static handle_merge_func_t *handle_merge_func_list;
3880static unsigned int handle_merge_func_size = 0, handle_merge_func_used = 0;
3881
3882void
3883reg_handle_merge_func(handle_merge_func_t func)
3884{
3885 if (handle_merge_func_used == handle_merge_func_size) {
3886 if (handle_merge_func_size) {
3887 handle_merge_func_size <<= 1;
3888 handle_merge_func_list = realloc(handle_merge_func_list, handle_merge_func_size*sizeof(handle_merge_func_t));
3889 } else {
3890 handle_merge_func_size = 8;
3891 handle_merge_func_list = malloc(handle_merge_func_size*sizeof(handle_merge_func_t));
3892 }
3893 }
3894 handle_merge_func_list[handle_merge_func_used++] = func;
3895}
3896
3897static NICKSERV_FUNC(cmd_merge)
3898{
3899 struct handle_info *hi_from, *hi_to;
3900 struct userNode *last_user;
3901 struct userData *cList, *cListNext;
3902 unsigned int ii, jj, n;
3903
3904 NICKSERV_MIN_PARMS(3);
3905
3906 if (!(hi_from = get_victim_oper(user, argv[1])))
3907 return 0;
3908 if (!(hi_to = get_victim_oper(user, argv[2])))
3909 return 0;
3910 if (hi_to == hi_from) {
3911 reply("NSMSG_CANNOT_MERGE_SELF", hi_to->handle);
3912 return 0;
3913 }
3914
3915 for (n=0; n<handle_merge_func_used; n++)
3916 handle_merge_func_list[n](user, hi_to, hi_from);
3917
3918 /* Append "from" handle's nicks to "to" handle's nick list. */
3919 if (hi_to->nicks) {
3920 struct nick_info *last_ni;
3921 for (last_ni=hi_to->nicks; last_ni->next; last_ni=last_ni->next) ;
3922 last_ni->next = hi_from->nicks;
3923 }
3924 while (hi_from->nicks) {
3925 hi_from->nicks->owner = hi_to;
3926 hi_from->nicks = hi_from->nicks->next;
3927 }
3928
3929 /* Merge the hostmasks. */
3930 for (ii=0; ii<hi_from->masks->used; ii++) {
3931 char *mask = hi_from->masks->list[ii];
3932 for (jj=0; jj<hi_to->masks->used; jj++)
3933 if (match_ircglobs(hi_to->masks->list[jj], mask))
3934 break;
3935 if (jj==hi_to->masks->used) /* Nothing from the "to" handle covered this mask, so add it. */
3936 string_list_append(hi_to->masks, strdup(mask));
3937 }
3938
3939 /* Merge the ignores. */
3940 for (ii=0; ii<hi_from->ignores->used; ii++) {
3941 char *ignore = hi_from->ignores->list[ii];
3942 for (jj=0; jj<hi_to->ignores->used; jj++)
3943 if (match_ircglobs(hi_to->ignores->list[jj], ignore))
3944 break;
3945 if (jj==hi_to->ignores->used) /* Nothing from the "to" handle covered this mask, so add it. */
3946 string_list_append(hi_to->ignores, strdup(ignore));
3947 }
3948
3949 /* Merge the lists of authed users. */
3950 if (hi_to->users) {
3951 for (last_user=hi_to->users; last_user->next_authed; last_user=last_user->next_authed) ;
3952 last_user->next_authed = hi_from->users;
3953 } else {
3954 hi_to->users = hi_from->users;
3955 }
3956 /* Repoint the old "from" handle's users. */
3957 for (last_user=hi_from->users; last_user; last_user=last_user->next_authed) {
3958 last_user->handle_info = hi_to;
3959 }
3960 hi_from->users = NULL;
3961
3962 /* Merge channel userlists. */
3963 for (cList=hi_from->channels; cList; cList=cListNext) {
3964 struct userData *cList2;
3965 cListNext = cList->u_next;
3966 for (cList2=hi_to->channels; cList2; cList2=cList2->u_next)
3967 if (cList->channel == cList2->channel)
3968 break;
3969 if (cList2 && (cList2->access >= cList->access)) {
3970 log_module(NS_LOG, LOG_INFO, "Merge: %s had only %d access in %s (versus %d for %s)", hi_from->handle, cList->access, cList->channel->channel->name, cList2->access, hi_to->handle);
3971 /* keep cList2 in hi_to; remove cList from hi_from */
3972 del_channel_user(cList, 1);
3973 } else {
3974 if (cList2) {
3975 log_module(NS_LOG, LOG_INFO, "Merge: %s had only %d access in %s (versus %d for %s)", hi_to->handle, cList2->access, cList->channel->channel->name, cList->access, hi_from->handle);
3976 /* remove the lower-ranking cList2 from hi_to */
3977 del_channel_user(cList2, 1);
3978 } else {
3979 log_module(NS_LOG, LOG_INFO, "Merge: %s had no access in %s", hi_to->handle, cList->channel->channel->name);
3980 }
3981 /* cList needs to be moved from hi_from to hi_to */
3982 cList->handle = hi_to;
3983 /* Remove from linked list for hi_from */
3984 assert(!cList->u_prev);
3985 hi_from->channels = cList->u_next;
3986 if (cList->u_next)
3987 cList->u_next->u_prev = cList->u_prev;
3988 /* Add to linked list for hi_to */
3989 cList->u_prev = NULL;
3990 cList->u_next = hi_to->channels;
3991 if (hi_to->channels)
3992 hi_to->channels->u_prev = cList;
3993 hi_to->channels = cList;
3994 }
3995 }
3996
3997 /* Do they get an OpServ level promotion? */
3998 if (hi_from->opserv_level > hi_to->opserv_level)
3999 hi_to->opserv_level = hi_from->opserv_level;
4000
4001 /* What about last seen time? */
4002 if (hi_from->lastseen > hi_to->lastseen)
4003 hi_to->lastseen = hi_from->lastseen;
4004
4005 /* New karma is the sum of the two original karmas. */
4006 hi_to->karma += hi_from->karma;
4007
4008 /* Does a fakehost carry over? (This intentionally doesn't set it
4009 * for users previously attached to hi_to. They'll just have to
4010 * reconnect.)
4011 */
4012 if (hi_from->fakehost && !hi_to->fakehost)
4013 hi_to->fakehost = strdup(hi_from->fakehost);
4014
4015 /* Notify of success. */
4016 reply("NSMSG_HANDLES_MERGED", hi_from->handle, hi_to->handle);
4017 global_message_args(MESSAGE_RECIPIENT_OPERS, "NSMSG_ACCOUNT_MERGED", user->nick,
4018 user->handle_info->handle, hi_from->handle, hi_to->handle);
4019
4020 /* Unregister the "from" handle. */
4021 nickserv_unregister_handle(hi_from, NULL, cmd->parent->bot);
4022 /* TODO: fix it so that if the ldap delete in nickserv_unregister_handle fails,
4023 * the process isn't completed.
4024 */
4025
4026 return 1;
4027}
4028
4029struct nickserv_discrim {
4030 unsigned long flags_on, flags_off;
4031 time_t min_registered, max_registered;
4032 time_t lastseen;
4033 unsigned int limit;
4034 int min_level, max_level;
4035 int min_karma, max_karma;
4036 enum { SUBSET, EXACT, SUPERSET, LASTQUIT } hostmask_type;
4037 const char *nickmask;
4038 const char *hostmask;
4039 const char *handlemask;
4040 const char *emailmask;
4041#ifdef WITH_LDAP
4042 unsigned int inldap;
4043#endif
4044};
4045
4046typedef void (*discrim_search_func)(struct userNode *source, struct handle_info *hi);
4047
4048struct discrim_apply_info {
4049 struct nickserv_discrim *discrim;
4050 discrim_search_func func;
4051 struct userNode *source;
4052 unsigned int matched;
4053};
4054
4055static struct nickserv_discrim *
4056nickserv_discrim_create(struct svccmd *cmd, struct userNode *user, unsigned int argc, char *argv[])
4057{
4058 unsigned int i;
4059 struct nickserv_discrim *discrim;
4060
4061 discrim = malloc(sizeof(*discrim));
4062 memset(discrim, 0, sizeof(*discrim));
4063 discrim->min_level = 0;
4064 discrim->max_level = INT_MAX;
4065 discrim->limit = 50;
4066 discrim->min_registered = 0;
4067 discrim->max_registered = INT_MAX;
4068 discrim->lastseen = LONG_MAX;
4069 discrim->min_karma = INT_MIN;
4070 discrim->max_karma = INT_MAX;
4071#ifdef WITH_LDAP
4072 discrim->inldap = 2;
4073#endif
4074
4075 for (i=0; i<argc; i++) {
4076 if (i == argc - 1) {
4077 reply("MSG_MISSING_PARAMS", argv[i]);
4078 goto fail;
4079 }
4080 if (!irccasecmp(argv[i], "limit")) {
4081 discrim->limit = strtoul(argv[++i], NULL, 0);
4082 } else if (!irccasecmp(argv[i], "flags")) {
4083 nickserv_modify_handle_flags(user, nickserv, argv[++i], &discrim->flags_on, &discrim->flags_off);
4084 } else if (!irccasecmp(argv[i], "registered")) {
4085 const char *cmp = argv[++i];
4086 if (cmp[0] == '<') {
4087 if (cmp[1] == '=') {
4088 discrim->min_registered = now - ParseInterval(cmp+2);
4089 } else {
4090 discrim->min_registered = now - ParseInterval(cmp+1) + 1;
4091 }
4092 } else if (cmp[0] == '=') {
4093 discrim->min_registered = discrim->max_registered = now - ParseInterval(cmp+1);
4094 } else if (cmp[0] == '>') {
4095 if (cmp[1] == '=') {
4096 discrim->max_registered = now - ParseInterval(cmp+2);
4097 } else {
4098 discrim->max_registered = now - ParseInterval(cmp+1) - 1;
4099 }
4100 } else {
4101 reply("MSG_INVALID_CRITERIA", cmp);
4102 }
4103 } else if (!irccasecmp(argv[i], "seen")) {
4104 discrim->lastseen = now - ParseInterval(argv[++i]);
4105 } else if (!nickserv_conf.disable_nicks && !irccasecmp(argv[i], "nickmask")) {
4106 discrim->nickmask = argv[++i];
4107 } else if (!irccasecmp(argv[i], "hostmask")) {
4108 i++;
4109 if (!irccasecmp(argv[i], "exact")) {
4110 if (i == argc - 1) {
4111 reply("MSG_MISSING_PARAMS", argv[i]);
4112 goto fail;
4113 }
4114 discrim->hostmask_type = EXACT;
4115 } else if (!irccasecmp(argv[i], "subset")) {
4116 if (i == argc - 1) {
4117 reply("MSG_MISSING_PARAMS", argv[i]);
4118 goto fail;
4119 }
4120 discrim->hostmask_type = SUBSET;
4121 } else if (!irccasecmp(argv[i], "superset")) {
4122 if (i == argc - 1) {
4123 reply("MSG_MISSING_PARAMS", argv[i]);
4124 goto fail;
4125 }
4126 discrim->hostmask_type = SUPERSET;
4127 } else if (!irccasecmp(argv[i], "lastquit") || !irccasecmp(argv[i], "lastauth")) {
4128 if (i == argc - 1) {
4129 reply("MSG_MISSING_PARAMS", argv[i]);
4130 goto fail;
4131 }
4132 discrim->hostmask_type = LASTQUIT;
4133 } else {
4134 i--;
4135 discrim->hostmask_type = SUPERSET;
4136 }
4137 discrim->hostmask = argv[++i];
4138 } else if (!irccasecmp(argv[i], "handlemask") || !irccasecmp(argv[i], "accountmask") || !irccasecmp(argv[i], "account")) {
4139 if (!irccasecmp(argv[++i], "*")) {
4140 discrim->handlemask = 0;
4141 } else {
4142 discrim->handlemask = argv[i];
4143 }
4144 } else if (!irccasecmp(argv[i], "email")) {
4145 if (user->handle_info->opserv_level < nickserv_conf.email_search_level) {
4146 reply("MSG_NO_SEARCH_ACCESS", "email");
4147 goto fail;
4148 } else if (!irccasecmp(argv[++i], "*")) {
4149 discrim->emailmask = 0;
4150 } else {
4151 discrim->emailmask = argv[i];
4152 }
4153 } else if (!irccasecmp(argv[i], "access")) {
4154 const char *cmp = argv[++i];
4155 if (cmp[0] == '<') {
4156 if (discrim->min_level == 0) discrim->min_level = 1;
4157 if (cmp[1] == '=') {
4158 discrim->max_level = strtoul(cmp+2, NULL, 0);
4159 } else {
4160 discrim->max_level = strtoul(cmp+1, NULL, 0) - 1;
4161 }
4162 } else if (cmp[0] == '=') {
4163 discrim->min_level = discrim->max_level = strtoul(cmp+1, NULL, 0);
4164 } else if (cmp[0] == '>') {
4165 if (cmp[1] == '=') {
4166 discrim->min_level = strtoul(cmp+2, NULL, 0);
4167 } else {
4168 discrim->min_level = strtoul(cmp+1, NULL, 0) + 1;
4169 }
4170 } else {
4171 reply("MSG_INVALID_CRITERIA", cmp);
4172 }
4173 } else if (!irccasecmp(argv[i], "karma")) {
4174 const char *cmp = argv[++i];
4175 if (cmp[0] == '<') {
4176 if (cmp[1] == '=') {
4177 discrim->max_karma = strtoul(cmp+2, NULL, 0);
4178 } else {
4179 discrim->max_karma = strtoul(cmp+1, NULL, 0) - 1;
4180 }
4181 } else if (cmp[0] == '=') {
4182 discrim->min_karma = discrim->max_karma = strtoul(cmp+1, NULL, 0);
4183 } else if (cmp[0] == '>') {
4184 if (cmp[1] == '=') {
4185 discrim->min_karma = strtoul(cmp+2, NULL, 0);
4186 } else {
4187 discrim->min_karma = strtoul(cmp+1, NULL, 0) + 1;
4188 }
4189 } else {
4190 send_message(user, nickserv, "MSG_INVALID_CRITERIA", cmp);
4191 }
4192#ifdef WITH_LDAP
4193 } else if (nickserv_conf.ldap_enable && !irccasecmp(argv[i], "inldap")) {
4194 i++;
4195 if(true_string(argv[i])) {
4196 discrim->inldap = 1;
4197 }
4198 else if (false_string(argv[i])) {
4199 discrim->inldap = 0;
4200 }
4201 else {
4202 reply("MSG_INVALID_BINARY", argv[i]);
4203 }
4204#endif
4205 } else {
4206 reply("MSG_INVALID_CRITERIA", argv[i]);
4207 goto fail;
4208 }
4209 }
4210 return discrim;
4211 fail:
4212 free(discrim);
4213 return NULL;
4214}
4215
4216static int
4217nickserv_discrim_match(struct nickserv_discrim *discrim, struct handle_info *hi)
4218{
4219 if (((discrim->flags_on & hi->flags) != discrim->flags_on)
4220 || (discrim->flags_off & hi->flags)
4221 || (discrim->min_registered > hi->registered)
4222 || (discrim->max_registered < hi->registered)
4223 || (discrim->lastseen < (hi->users?now:hi->lastseen))
4224 || (discrim->handlemask && !match_ircglob(hi->handle, discrim->handlemask))
4225 || (discrim->emailmask && (!hi->email_addr || !match_ircglob(hi->email_addr, discrim->emailmask)))
4226 || (discrim->min_level > hi->opserv_level)
4227 || (discrim->max_level < hi->opserv_level)
4228 || (discrim->min_karma > hi->karma)
4229 || (discrim->max_karma < hi->karma)
4230 ) {
4231 return 0;
4232 }
4233 if (discrim->hostmask) {
4234 unsigned int i;
4235 for (i=0; i<hi->masks->used; i++) {
4236 const char *mask = hi->masks->list[i];
4237 if ((discrim->hostmask_type == SUBSET)
4238 && (match_ircglobs(discrim->hostmask, mask))) break;
4239 else if ((discrim->hostmask_type == EXACT)
4240 && !irccasecmp(discrim->hostmask, mask)) break;
4241 else if ((discrim->hostmask_type == SUPERSET)
4242 && (match_ircglobs(mask, discrim->hostmask))) break;
4243 else if ((discrim->hostmask_type == LASTQUIT)
4244 && (match_ircglobs(discrim->hostmask, hi->last_quit_host))) break;
4245 }
4246 if (i==hi->masks->used) return 0;
4247 }
4248 if (discrim->nickmask) {
4249 struct nick_info *nick = hi->nicks;
4250 while (nick) {
4251 if (match_ircglob(nick->nick, discrim->nickmask)) break;
4252 nick = nick->next;
4253 }
4254 if (!nick) return 0;
4255 }
4256#ifdef WITH_LDAP
4257 if(nickserv_conf.ldap_enable && discrim->inldap != 2) {
4258 int rc;
4259 rc = ldap_get_user_info(hi->handle, NULL);
4260 if(discrim->inldap == 1 && rc != LDAP_SUCCESS)
4261 return 0;
4262 if(discrim->inldap == 0 && rc == LDAP_SUCCESS)
4263 return 0;
4264 }
4265
4266#endif
4267 return 1;
4268}
4269
4270static unsigned int
4271nickserv_discrim_search(struct nickserv_discrim *discrim, discrim_search_func dsf, struct userNode *source)
4272{
4273 dict_iterator_t it, next;
4274 unsigned int matched;
4275
4276 for (it = dict_first(nickserv_handle_dict), matched = 0;
4277 it && (matched < discrim->limit);
4278 it = next) {
4279 next = iter_next(it);
4280 if (nickserv_discrim_match(discrim, iter_data(it))) {
4281 dsf(source, iter_data(it));
4282 matched++;
4283 }
4284 }
4285 return matched;
4286}
4287
4288static void
4289search_print_func(struct userNode *source, struct handle_info *match)
4290{
4291 send_message(source, nickserv, "NSMSG_SEARCH_MATCH", match->handle);
4292}
4293
4294static void
4295search_count_func(UNUSED_ARG(struct userNode *source), UNUSED_ARG(struct handle_info *match))
4296{
4297}
4298
4299static void
4300search_unregister_func (struct userNode *source, struct handle_info *match)
4301{
4302 if (oper_has_access(source, nickserv, match->opserv_level, 0))
4303 nickserv_unregister_handle(match, source, nickserv); // XXX nickserv hard coded
4304}
4305
4306#ifdef WITH_LDAP
4307static void
4308search_add2ldap_func (struct userNode *source, struct handle_info *match)
4309{
4310 int rc;
4311 if(match->email_addr && match->passwd && match->handle) {
4312 rc = ldap_do_add(match->handle, match->passwd, match->email_addr);
4313 if(rc != LDAP_SUCCESS) {
4314 send_message(source, nickserv, "NSMSG_LDAP_FAIL_ADD", match->handle, ldap_err2string(rc));
4315 }
4316 }
4317}
4318#endif
4319
4320static int
4321nickserv_sort_accounts_by_access(const void *a, const void *b)
4322{
4323 const struct handle_info *hi_a = *(const struct handle_info**)a;
4324 const struct handle_info *hi_b = *(const struct handle_info**)b;
4325 if (hi_a->opserv_level != hi_b->opserv_level)
4326 return hi_b->opserv_level - hi_a->opserv_level;
4327 return irccasecmp(hi_a->handle, hi_b->handle);
4328}
4329
4330void
4331nickserv_show_oper_accounts(struct userNode *user, struct svccmd *cmd)
4332{
4333 struct handle_info_list hil;
4334 struct helpfile_table tbl;
4335 unsigned int ii;
4336 dict_iterator_t it;
4337 const char **ary;
4338
4339 memset(&hil, 0, sizeof(hil));
4340 for (it = dict_first(nickserv_handle_dict); it; it = iter_next(it)) {
4341 struct handle_info *hi = iter_data(it);
4342 if (hi->opserv_level)
4343 handle_info_list_append(&hil, hi);
4344 }
4345 qsort(hil.list, hil.used, sizeof(hil.list[0]), nickserv_sort_accounts_by_access);
4346 tbl.length = hil.used + 1;
4347 tbl.width = 2;
4348 tbl.flags = TABLE_NO_FREE | TABLE_REPEAT_ROWS | TABLE_REPEAT_HEADERS;
4349 tbl.contents = malloc(tbl.length * sizeof(tbl.contents[0]));
4350 tbl.contents[0] = ary = malloc(tbl.width * sizeof(ary[0]));
4351 ary[0] = "Account";
4352 ary[1] = "Level";
4353 for (ii = 0; ii < hil.used; ) {
4354 ary = malloc(tbl.width * sizeof(ary[0]));
4355 ary[0] = hil.list[ii]->handle;
4356 ary[1] = strtab(hil.list[ii]->opserv_level);
4357 tbl.contents[++ii] = ary;
4358 }
4359 table_send(cmd->parent->bot, user->nick, 0, NULL, tbl);
4360 /*reply("MSG_MATCH_COUNT", hil.used); */
4361 for (ii = 0; ii < hil.used; ii++)
4362 free(tbl.contents[ii]);
4363 free(tbl.contents);
4364 free(hil.list);
4365}
4366
4367static NICKSERV_FUNC(cmd_search)
4368{
4369 struct nickserv_discrim *discrim;
4370 discrim_search_func action;
4371 struct svccmd *subcmd;
4372 unsigned int matches;
4373 char buf[MAXLEN];
4374
4375 NICKSERV_MIN_PARMS(3);
4376 sprintf(buf, "search %s", argv[1]);
4377 subcmd = dict_find(nickserv_service->commands, buf, NULL);
4378 if (!irccasecmp(argv[1], "print"))
4379 action = search_print_func;
4380 else if (!irccasecmp(argv[1], "count"))
4381 action = search_count_func;
4382 else if (!irccasecmp(argv[1], "unregister"))
4383 action = search_unregister_func;
4384#ifdef WITH_LDAP
4385 else if (nickserv_conf.ldap_enable && !irccasecmp(argv[1], "add2ldap"))
4386 action = search_add2ldap_func;
4387#endif
4388 else {
4389 reply("NSMSG_INVALID_ACTION", argv[1]);
4390 return 0;
4391 }
4392
4393 if (subcmd && !svccmd_can_invoke(user, nickserv, subcmd, NULL, SVCCMD_NOISY))
4394 return 0;
4395
4396 discrim = nickserv_discrim_create(cmd, user, argc-2, argv+2);
4397 if (!discrim)
4398 return 0;
4399
4400 if (action == search_print_func)
4401 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
4402 else if (action == search_count_func)
4403 discrim->limit = INT_MAX;
4404
4405 matches = nickserv_discrim_search(discrim, action, user);
4406
4407 if (matches)
4408 reply("MSG_MATCH_COUNT", matches);
4409 else
4410 reply("MSG_NO_MATCHES");
4411
4412 free(discrim);
4413 return 0;
4414}
4415
4416static MODCMD_FUNC(cmd_checkpass)
4417{
4418 struct handle_info *hi;
4419
4420 NICKSERV_MIN_PARMS(3);
4421 if (!(hi = get_handle_info(argv[1]))) {
4422 reply("MSG_HANDLE_UNKNOWN", argv[1]);
4423 return 0;
4424 }
4425 if (checkpass(argv[2], hi->passwd))
4426 reply("CHECKPASS_YES");
4427 else
4428 reply("CHECKPASS_NO");
4429 argv[2] = "****";
4430 return 1;
4431}
4432
4433static MODCMD_FUNC(cmd_checkemail)
4434{
4435 struct handle_info *hi;
4436
4437 NICKSERV_MIN_PARMS(3);
4438 if (!(hi = modcmd_get_handle_info(user, argv[1]))) {
4439 return 0;
4440 }
4441 if (!hi->email_addr)
4442 reply("CHECKEMAIL_NOT_SET");
4443 else if (!irccasecmp(argv[2], hi->email_addr))
4444 reply("CHECKEMAIL_YES");
4445 else
4446 reply("CHECKEMAIL_NO");
4447 return 1;
4448}
4449
4450static void
4451nickserv_db_read_handle(char *handle, dict_t obj)
4452{
4453 const char *str;
4454 struct string_list *masks, *slist, *ignores;
4455 struct handle_info *hi;
4456 struct userNode *authed_users;
4457 struct userData *channel_list;
4458 unsigned long int id;
4459 unsigned int ii;
4460 dict_t subdb;
4461 char *setter, *note;
4462 time_t date;
4463
4464 str = database_get_data(obj, KEY_ID, RECDB_QSTRING);
4465 id = str ? strtoul(str, NULL, 0) : 0;
4466 str = database_get_data(obj, KEY_PASSWD, RECDB_QSTRING);
4467 if (!str) {
4468 log_module(NS_LOG, LOG_WARNING, "did not find a password for %s -- skipping user.", handle);
4469 return;
4470 }
4471 if ((hi = get_handle_info(handle))) {
4472 authed_users = hi->users;
4473 channel_list = hi->channels;
4474 hi->users = NULL;
4475 hi->channels = NULL;
4476 dict_remove(nickserv_handle_dict, hi->handle);
4477 } else {
4478 authed_users = NULL;
4479 channel_list = NULL;
4480 }
4481 if(nickserv_conf.force_handles_lowercase)
4482 irc_strtolower(handle);
4483 hi = register_handle(handle, str, id);
4484 if (authed_users) {
4485 hi->users = authed_users;
4486 while (authed_users) {
4487 authed_users->handle_info = hi;
4488 authed_users = authed_users->next_authed;
4489 }
4490 }
4491 hi->channels = channel_list;
4492 masks = database_get_data(obj, KEY_MASKS, RECDB_STRING_LIST);
4493 hi->masks = masks ? string_list_copy(masks) : alloc_string_list(1);
4494 ignores = database_get_data(obj, KEY_IGNORES, RECDB_STRING_LIST);
4495 hi->ignores = ignores ? string_list_copy(ignores) : alloc_string_list(1);
4496 str = database_get_data(obj, KEY_MAXLOGINS, RECDB_QSTRING);
4497 hi->maxlogins = str ? strtoul(str, NULL, 0) : 0;
4498 str = database_get_data(obj, KEY_LANGUAGE, RECDB_QSTRING);
4499 hi->language = language_find(str ? str : "C");
4500 str = database_get_data(obj, KEY_OPSERV_LEVEL, RECDB_QSTRING);
4501 hi->opserv_level = str ? strtoul(str, NULL, 0) : 0;
4502 str = database_get_data(obj, KEY_INFO, RECDB_QSTRING);
4503 if (str)
4504 hi->infoline = strdup(str);
4505 str = database_get_data(obj, KEY_REGISTER_ON, RECDB_QSTRING);
4506 hi->registered = str ? (time_t)strtoul(str, NULL, 0) : now;
4507 str = database_get_data(obj, KEY_LAST_SEEN, RECDB_QSTRING);
4508 hi->lastseen = str ? (time_t)strtoul(str, NULL, 0) : hi->registered;
4509 str = database_get_data(obj, KEY_KARMA, RECDB_QSTRING);
4510 hi->karma = str ? strtoul(str, NULL, 0) : 0;
4511 /* We want to read the nicks even if disable_nicks is set. This is so
4512 * that we don't lose the nick data entirely. */
4513 slist = database_get_data(obj, KEY_NICKS, RECDB_STRING_LIST);
4514 if (slist) {
4515 for (ii=0; ii<slist->used; ii++)
4516 register_nick(slist->list[ii], hi);
4517 }
4518 str = database_get_data(obj, KEY_FLAGS, RECDB_QSTRING);
4519 if (str) {
4520 for (ii=0; str[ii]; ii++)
4521 hi->flags |= 1 << (handle_inverse_flags[(unsigned char)str[ii]] - 1);
4522 }
4523 str = database_get_data(obj, KEY_USERLIST_STYLE, RECDB_QSTRING);
4524 hi->userlist_style = str ? str[0] : HI_DEFAULT_STYLE;
4525 str = database_get_data(obj, KEY_ANNOUNCEMENTS, RECDB_QSTRING);
4526 hi->announcements = str ? str[0] : '?';
4527 str = database_get_data(obj, KEY_SCREEN_WIDTH, RECDB_QSTRING);
4528 hi->screen_width = str ? strtoul(str, NULL, 0) : 0;
4529 str = database_get_data(obj, KEY_TABLE_WIDTH, RECDB_QSTRING);
4530 hi->table_width = str ? strtoul(str, NULL, 0) : 0;
4531 str = database_get_data(obj, KEY_LAST_QUIT_HOST, RECDB_QSTRING);
4532 if (!str)
4533 str = database_get_data(obj, KEY_LAST_AUTHED_HOST, RECDB_QSTRING);
4534 if (str)
4535 safestrncpy(hi->last_quit_host, str, sizeof(hi->last_quit_host));
4536 str = database_get_data(obj, KEY_EMAIL_ADDR, RECDB_QSTRING);
4537 if (str)
4538 nickserv_set_email_addr(hi, str);
4539 str = database_get_data(obj, KEY_EPITHET, RECDB_QSTRING);
4540 if (str)
4541 hi->epithet = strdup(str);
4542 subdb = database_get_data(obj, KEY_NOTE_NOTE, RECDB_OBJECT);
4543 if (subdb) {
4544 setter = database_get_data(subdb, KEY_NOTE_SETTER, RECDB_QSTRING);
4545 str = database_get_data(subdb, KEY_NOTE_DATE, RECDB_QSTRING);
4546 date = str ? (time_t)strtoul(str, NULL, 0) : now;
4547 note = database_get_data(subdb, KEY_NOTE_NOTE, RECDB_QSTRING);
4548 if (setter && date && note)
4549 {
4550 if (!(hi->note = nickserv_add_note(setter, date, note)))
4551 hi->note = NULL;
4552 }
4553 }
4554
4555 str = database_get_data(obj, KEY_FAKEHOST, RECDB_QSTRING);
4556 if (str)
4557 hi->fakehost = strdup(str);
4558
4559 subdb = database_get_data(obj, KEY_COOKIE, RECDB_OBJECT);
4560 if (subdb) {
4561 const char *data, *type, *expires, *cookie_str;
4562 struct handle_cookie *cookie;
4563
4564 cookie = calloc(1, sizeof(*cookie));
4565 type = database_get_data(subdb, KEY_COOKIE_TYPE, RECDB_QSTRING);
4566 data = database_get_data(subdb, KEY_COOKIE_DATA, RECDB_QSTRING);
4567 expires = database_get_data(subdb, KEY_COOKIE_EXPIRES, RECDB_QSTRING);
4568 cookie_str = database_get_data(subdb, KEY_COOKIE, RECDB_QSTRING);
4569 if (!type || !expires || !cookie_str) {
4570 log_module(NS_LOG, LOG_ERROR, "Missing field(s) from cookie for account %s; dropping cookie.", hi->handle);
4571 goto cookie_out;
4572 }
4573 if (!irccasecmp(type, KEY_ACTIVATION))
4574 cookie->type = ACTIVATION;
4575 else if (!irccasecmp(type, KEY_PASSWORD_CHANGE))
4576 cookie->type = PASSWORD_CHANGE;
4577 else if (!irccasecmp(type, KEY_EMAIL_CHANGE))
4578 cookie->type = EMAIL_CHANGE;
4579 else if (!irccasecmp(type, KEY_ALLOWAUTH))
4580 cookie->type = ALLOWAUTH;
4581 else {
4582 log_module(NS_LOG, LOG_ERROR, "Invalid cookie type %s for account %s; dropping cookie.", type, handle);
4583 goto cookie_out;
4584 }
4585 cookie->expires = strtoul(expires, NULL, 0);
4586 if (cookie->expires < now)
4587 goto cookie_out;
4588 if (data)
4589 cookie->data = strdup(data);
4590 safestrncpy(cookie->cookie, cookie_str, sizeof(cookie->cookie));
4591 cookie->hi = hi;
4592 cookie_out:
4593 if (cookie->hi)
4594 nickserv_bake_cookie(cookie);
4595 else
4596 nickserv_free_cookie(cookie);
4597 }
4598}
4599
4600static int
4601nickserv_saxdb_read(dict_t db) {
4602 dict_iterator_t it;
4603 struct record_data *rd;
4604 char *handle;
4605
4606 for (it=dict_first(db); it; it=iter_next(it)) {
4607 rd = iter_data(it);
4608 handle = strdup(iter_key(it));
4609 nickserv_db_read_handle(handle, rd->d.object);
4610 free(handle);
4611 }
4612 return 0;
4613}
4614
4615static NICKSERV_FUNC(cmd_mergedb)
4616{
4617 struct timeval start, stop;
4618 dict_t db;
4619
4620 NICKSERV_MIN_PARMS(2);
4621 gettimeofday(&start, NULL);
4622 if (!(db = parse_database(argv[1]))) {
4623 reply("NSMSG_DB_UNREADABLE", argv[1]);
4624 return 0;
4625 }
4626 nickserv_saxdb_read(db);
4627 free_database(db);
4628 gettimeofday(&stop, NULL);
4629 stop.tv_sec -= start.tv_sec;
4630 stop.tv_usec -= start.tv_usec;
4631 if (stop.tv_usec < 0) {
4632 stop.tv_sec -= 1;
4633 stop.tv_usec += 1000000;
4634 }
4635 reply("NSMSG_DB_MERGED", argv[1], stop.tv_sec, stop.tv_usec/1000);
4636 return 1;
4637}
4638
4639static void
4640expire_handles(UNUSED_ARG(void *data))
4641{
4642 dict_iterator_t it, next;
4643 time_t expiry;
4644 struct handle_info *hi;
4645
4646 for (it=dict_first(nickserv_handle_dict); it; it=next) {
4647 next = iter_next(it);
4648 hi = iter_data(it);
4649 if ((hi->opserv_level > 0)
4650 || hi->users
4651 || HANDLE_FLAGGED(hi, FROZEN)
4652 || HANDLE_FLAGGED(hi, NODELETE)) {
4653 continue;
4654 }
4655 expiry = hi->channels ? nickserv_conf.handle_expire_delay : nickserv_conf.nochan_handle_expire_delay;
4656 if ((now - hi->lastseen) > expiry) {
4657 log_module(NS_LOG, LOG_INFO, "Expiring account %s for inactivity.", hi->handle);
4658 nickserv_unregister_handle(hi, NULL, NULL);
4659 }
4660 }
4661
4662 if (nickserv_conf.handle_expire_frequency)
4663 timeq_add(now + nickserv_conf.handle_expire_frequency, expire_handles, NULL);
4664}
4665
4666static void
4667nickserv_load_dict(const char *fname)
4668{
4669 FILE *file;
4670 char line[128];
4671 if (!(file = fopen(fname, "r"))) {
4672 log_module(NS_LOG, LOG_ERROR, "Unable to open dictionary file %s: %s", fname, strerror(errno));
4673 return;
4674 }
4675 while (fgets(line, sizeof(line), file)) {
4676 if (!line[0])
4677 continue;
4678 if (line[strlen(line)-1] == '\n')
4679 line[strlen(line)-1] = 0;
4680 dict_insert(nickserv_conf.weak_password_dict, strdup(line), NULL);
4681 }
4682 fclose(file);
4683 log_module(NS_LOG, LOG_INFO, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf.weak_password_dict));
4684}
4685
4686static enum reclaim_action
4687reclaim_action_from_string(const char *str) {
4688 if (!str)
4689 return RECLAIM_NONE;
4690 else if (!irccasecmp(str, "warn"))
4691 return RECLAIM_WARN;
4692 else if (!irccasecmp(str, "svsnick"))
4693 return RECLAIM_SVSNICK;
4694 else if (!irccasecmp(str, "kill"))
4695 return RECLAIM_KILL;
4696 else
4697 return RECLAIM_NONE;
4698}
4699
4700static void
4701nickserv_conf_read(void)
4702{
4703 dict_t conf_node, child;
4704 const char *str;
4705 dict_iterator_t it;
4706 struct string_list *strlist;
4707
4708 if (!(conf_node = conf_get_data(NICKSERV_CONF_NAME, RECDB_OBJECT))) {
4709 log_module(NS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME);
4710 return;
4711 }
4712 str = database_get_data(conf_node, KEY_VALID_HANDLE_REGEX, RECDB_QSTRING);
4713 if (!str)
4714 str = database_get_data(conf_node, KEY_VALID_ACCOUNT_REGEX, RECDB_QSTRING);
4715 if (nickserv_conf.valid_handle_regex_set)
4716 regfree(&nickserv_conf.valid_handle_regex);
4717 if (str) {
4718 int err = regcomp(&nickserv_conf.valid_handle_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
4719 nickserv_conf.valid_handle_regex_set = !err;
4720 if (err) log_module(NS_LOG, LOG_ERROR, "Bad valid_account_regex (error %d)", err);
4721 } else {
4722 nickserv_conf.valid_handle_regex_set = 0;
4723 }
4724 str = database_get_data(conf_node, KEY_VALID_NICK_REGEX, RECDB_QSTRING);
4725 if (nickserv_conf.valid_nick_regex_set)
4726 regfree(&nickserv_conf.valid_nick_regex);
4727 if (str) {
4728 int err = regcomp(&nickserv_conf.valid_nick_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
4729 nickserv_conf.valid_nick_regex_set = !err;
4730 if (err) log_module(NS_LOG, LOG_ERROR, "Bad valid_nick_regex (error %d)", err);
4731 } else {
4732 nickserv_conf.valid_nick_regex_set = 0;
4733 }
4734 str = database_get_data(conf_node, KEY_VALID_FAKEHOST_REGEX, RECDB_QSTRING);
4735 if (nickserv_conf.valid_fakehost_regex_set)
4736 regfree(&nickserv_conf.valid_fakehost_regex);
4737 if (str) {
4738 int err = regcomp(&nickserv_conf.valid_fakehost_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
4739 nickserv_conf.valid_fakehost_regex_set = !err;
4740 if (err) log_module(NS_LOG, LOG_ERROR, "Bad valid_fakehost_regex (error %d)", err);
4741 } else {
4742 nickserv_conf.valid_fakehost_regex_set = 0;
4743 }
4744 str = database_get_data(conf_node, KEY_NICKS_PER_HANDLE, RECDB_QSTRING);
4745 if (!str)
4746 str = database_get_data(conf_node, KEY_NICKS_PER_ACCOUNT, RECDB_QSTRING);
4747 nickserv_conf.nicks_per_handle = str ? strtoul(str, NULL, 0) : 4;
4748 str = database_get_data(conf_node, KEY_DISABLE_NICKS, RECDB_QSTRING);
4749 nickserv_conf.disable_nicks = str ? strtoul(str, NULL, 0) : 0;
4750 str = database_get_data(conf_node, KEY_DEFAULT_HOSTMASK, RECDB_QSTRING);
4751 nickserv_conf.default_hostmask = str ? !disabled_string(str) : 0;
4752 str = database_get_data(conf_node, KEY_PASSWORD_MIN_LENGTH, RECDB_QSTRING);
4753 nickserv_conf.password_min_length = str ? strtoul(str, NULL, 0) : 0;
4754 str = database_get_data(conf_node, KEY_PASSWORD_MIN_DIGITS, RECDB_QSTRING);
4755 nickserv_conf.password_min_digits = str ? strtoul(str, NULL, 0) : 0;
4756 str = database_get_data(conf_node, KEY_PASSWORD_MIN_UPPER, RECDB_QSTRING);
4757 nickserv_conf.password_min_upper = str ? strtoul(str, NULL, 0) : 0;
4758 str = database_get_data(conf_node, KEY_PASSWORD_MIN_LOWER, RECDB_QSTRING);
4759 nickserv_conf.password_min_lower = str ? strtoul(str, NULL, 0) : 0;
4760 str = database_get_data(conf_node, KEY_DB_BACKUP_FREQ, RECDB_QSTRING);
4761 nickserv_conf.db_backup_frequency = str ? ParseInterval(str) : 7200;
4762 str = database_get_data(conf_node, KEY_MODOPER_LEVEL, RECDB_QSTRING);
4763 nickserv_conf.modoper_level = str ? strtoul(str, NULL, 0) : 900;
4764 str = database_get_data(conf_node, KEY_SET_EPITHET_LEVEL, RECDB_QSTRING);
4765 nickserv_conf.set_epithet_level = str ? strtoul(str, NULL, 0) : 1;
4766 str = database_get_data(conf_node, KEY_SET_TITLE_LEVEL, RECDB_QSTRING);
4767 nickserv_conf.set_title_level = str ? strtoul(str, NULL, 0) : 900;
4768 str = database_get_data(conf_node, KEY_SET_FAKEHOST_LEVEL, RECDB_QSTRING);
4769 nickserv_conf.set_fakehost_level = str ? strtoul(str, NULL, 0) : 1000;
4770 str = database_get_data(conf_node, KEY_HANDLE_EXPIRE_FREQ, RECDB_QSTRING);
4771 if (!str)
4772 str = database_get_data(conf_node, KEY_ACCOUNT_EXPIRE_FREQ, RECDB_QSTRING);
4773 nickserv_conf.handle_expire_frequency = str ? ParseInterval(str) : 86400;
4774 str = database_get_data(conf_node, KEY_HANDLE_EXPIRE_DELAY, RECDB_QSTRING);
4775 if (!str)
4776 str = database_get_data(conf_node, KEY_ACCOUNT_EXPIRE_DELAY, RECDB_QSTRING);
4777 nickserv_conf.handle_expire_delay = str ? ParseInterval(str) : 86400*30;
4778 str = database_get_data(conf_node, KEY_NOCHAN_HANDLE_EXPIRE_DELAY, RECDB_QSTRING);
4779 if (!str)
4780 str = database_get_data(conf_node, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY, RECDB_QSTRING);
4781 nickserv_conf.nochan_handle_expire_delay = str ? ParseInterval(str) : 86400*15;
4782 str = database_get_data(conf_node, "warn_clone_auth", RECDB_QSTRING);
4783 nickserv_conf.warn_clone_auth = str ? !disabled_string(str) : 1;
4784 str = database_get_data(conf_node, "default_maxlogins", RECDB_QSTRING);
4785 nickserv_conf.default_maxlogins = str ? strtoul(str, NULL, 0) : 2;
4786 str = database_get_data(conf_node, "hard_maxlogins", RECDB_QSTRING);
4787 str = database_get_data(conf_node, KEY_OUNREGISTER_INACTIVE, RECDB_QSTRING);
4788 nickserv_conf.ounregister_inactive = str ? ParseInterval(str) : 86400*28;
4789 str = database_get_data(conf_node, KEY_OUNREGISTER_FLAGS, RECDB_QSTRING);
4790 if (!str)
4791 str = "ShgsfnHbu";
4792 nickserv_conf.ounregister_flags = 0;
4793 while(*str) {
4794 unsigned int pos = handle_inverse_flags[(unsigned char)*str];
4795 str++;
4796 if(pos)
4797 nickserv_conf.ounregister_flags |= 1 << (pos - 1);
4798 }
4799 nickserv_conf.hard_maxlogins = str ? strtoul(str, NULL, 0) : 10;
4800 if (!nickserv_conf.disable_nicks) {
4801 str = database_get_data(conf_node, "reclaim_action", RECDB_QSTRING);
4802 nickserv_conf.reclaim_action = str ? reclaim_action_from_string(str) : RECLAIM_NONE;
4803 str = database_get_data(conf_node, "warn_nick_owned", RECDB_QSTRING);
4804 nickserv_conf.warn_nick_owned = str ? enabled_string(str) : 0;
4805 str = database_get_data(conf_node, "auto_reclaim_action", RECDB_QSTRING);
4806 nickserv_conf.auto_reclaim_action = str ? reclaim_action_from_string(str) : RECLAIM_NONE;
4807 str = database_get_data(conf_node, "auto_reclaim_delay", RECDB_QSTRING);
4808 nickserv_conf.auto_reclaim_delay = str ? ParseInterval(str) : 0;
4809 }
4810 child = database_get_data(conf_node, KEY_FLAG_LEVELS, RECDB_OBJECT);
4811 for (it=dict_first(child); it; it=iter_next(it)) {
4812 const char *key = iter_key(it), *value;
4813 unsigned char flag;
4814 int pos;
4815
4816 if (!strncasecmp(key, "uc_", 3))
4817 flag = toupper(key[3]);
4818 else if (!strncasecmp(key, "lc_", 3))
4819 flag = tolower(key[3]);
4820 else
4821 flag = key[0];
4822
4823 if ((pos = handle_inverse_flags[flag])) {
4824 value = GET_RECORD_QSTRING((struct record_data*)iter_data(it));
4825 flag_access_levels[pos - 1] = strtoul(value, NULL, 0);
4826 }
4827 }
4828 if (nickserv_conf.weak_password_dict)
4829 dict_delete(nickserv_conf.weak_password_dict);
4830 nickserv_conf.weak_password_dict = dict_new();
4831 dict_set_free_keys(nickserv_conf.weak_password_dict, free);
4832 dict_insert(nickserv_conf.weak_password_dict, strdup("password"), NULL);
4833 dict_insert(nickserv_conf.weak_password_dict, strdup("<password>"), NULL);
4834 str = database_get_data(conf_node, KEY_DICT_FILE, RECDB_QSTRING);
4835 if (str)
4836 nickserv_load_dict(str);
4837 str = database_get_data(conf_node, KEY_NICK, RECDB_QSTRING);
4838 if (nickserv && str)
4839 NickChange(nickserv, str, 0);
4840 str = database_get_data(conf_node, KEY_AUTOGAG_ENABLED, RECDB_QSTRING);
4841 nickserv_conf.autogag_enabled = str ? strtoul(str, NULL, 0) : 1;
4842 str = database_get_data(conf_node, KEY_AUTOGAG_DURATION, RECDB_QSTRING);
4843 nickserv_conf.autogag_duration = str ? ParseInterval(str) : 1800;
4844 str = database_get_data(conf_node, KEY_EMAIL_VISIBLE_LEVEL, RECDB_QSTRING);
4845 nickserv_conf.email_visible_level = str ? strtoul(str, NULL, 0) : 800;
4846 str = database_get_data(conf_node, KEY_EMAIL_ENABLED, RECDB_QSTRING);
4847 nickserv_conf.email_enabled = str ? enabled_string(str) : 0;
4848 str = database_get_data(conf_node, KEY_SYNC_LOG, RECDB_QSTRING);
4849 nickserv_conf.sync_log = str ? enabled_string(str) : 0;
4850 str = database_get_data(conf_node, KEY_COOKIE_TIMEOUT, RECDB_QSTRING);
4851 nickserv_conf.cookie_timeout = str ? ParseInterval(str) : 24*3600;
4852 str = database_get_data(conf_node, KEY_EMAIL_REQUIRED, RECDB_QSTRING);
4853 nickserv_conf.email_required = (nickserv_conf.email_enabled && str) ? enabled_string(str) : 0;
4854 str = database_get_data(conf_node, KEY_ACCOUNTS_PER_EMAIL, RECDB_QSTRING);
4855 nickserv_conf.handles_per_email = str ? strtoul(str, NULL, 0) : 1;
4856 str = database_get_data(conf_node, KEY_EMAIL_SEARCH_LEVEL, RECDB_QSTRING);
4857 nickserv_conf.email_search_level = str ? strtoul(str, NULL, 0) : 600;
4858 str = database_get_data(conf_node, KEY_TITLEHOST_SUFFIX, RECDB_QSTRING);
4859 nickserv_conf.titlehost_suffix = str ? str : "example.net";
4860
4861 free_string_list(nickserv_conf.denied_fakehost_words);
4862 strlist = database_get_data(conf_node, KEY_DENIED_FAKEHOST_WORDS, RECDB_STRING_LIST);
4863 if(strlist)
4864 strlist = string_list_copy(strlist);
4865 else {
4866 strlist = alloc_string_list(4);
4867 string_list_append(strlist, strdup("sex"));
4868 string_list_append(strlist, strdup("fuck"));
4869 }
4870 nickserv_conf.denied_fakehost_words = strlist;
4871
4872 str = database_get_data(conf_node, KEY_DEFAULT_STYLE, RECDB_QSTRING);
4873 nickserv_conf.default_style = str ? str[0] : HI_DEFAULT_STYLE;
4874
4875 str = database_get_data(conf_node, KEY_AUTO_OPER, RECDB_QSTRING);
4876 nickserv_conf.auto_oper = str ? str : "";
4877
4878 str = database_get_data(conf_node, KEY_AUTO_ADMIN, RECDB_QSTRING);
4879 nickserv_conf.auto_admin = str ? str : "";
4880
4881 str = conf_get_data("server/network", RECDB_QSTRING);
4882 nickserv_conf.network_name = str ? str : "some IRC network";
4883 if (!nickserv_conf.auth_policer_params) {
4884 nickserv_conf.auth_policer_params = policer_params_new();
4885 policer_params_set(nickserv_conf.auth_policer_params, "size", "5");
4886 policer_params_set(nickserv_conf.auth_policer_params, "drain-rate", "0.05");
4887 }
4888 child = database_get_data(conf_node, KEY_AUTH_POLICER, RECDB_OBJECT);
4889 for (it=dict_first(child); it; it=iter_next(it))
4890 set_policer_param(iter_key(it), iter_data(it), nickserv_conf.auth_policer_params);
4891
4892 str = database_get_data(conf_node, KEY_LDAP_ENABLE, RECDB_QSTRING);
4893 nickserv_conf.ldap_enable = str ? strtoul(str, NULL, 0) : 0;
4894
4895 str = database_get_data(conf_node, KEY_FORCE_HANDLES_LOWERCASE, RECDB_QSTRING);
4896 nickserv_conf.force_handles_lowercase = str ? strtol(str, NULL, 0) : 0;
4897
4898#ifndef WITH_LDAP
4899 if(nickserv_conf.ldap_enable > 0) {
4900 /* ldap is enabled but not compiled in - error out */
4901 log_module(MAIN_LOG, LOG_ERROR, "ldap is enabled in config, but not compiled in!");
4902 nickserv_conf.ldap_enable = 0;
4903 sleep(5);
4904 }
4905#endif
4906
4907#ifdef WITH_LDAP
4908 str = database_get_data(conf_node, KEY_LDAP_URI, RECDB_QSTRING);
4909 nickserv_conf.ldap_uri = str ? str : "";
4910
4911 str = database_get_data(conf_node, KEY_LDAP_BASE, RECDB_QSTRING);
4912 nickserv_conf.ldap_base = str ? str : "";
4913
4914 str = database_get_data(conf_node, KEY_LDAP_DN_FMT, RECDB_QSTRING);
4915 nickserv_conf.ldap_dn_fmt = str ? str : "";
4916
4917 str = database_get_data(conf_node, KEY_LDAP_VERSION, RECDB_QSTRING);
4918 nickserv_conf.ldap_version = str ? strtoul(str, NULL, 0) : 3;
4919
4920 str = database_get_data(conf_node, KEY_LDAP_AUTOCREATE, RECDB_QSTRING);
4921 nickserv_conf.ldap_autocreate = str ? strtoul(str, NULL, 0) : 0;
4922
4923 str = database_get_data(conf_node, KEY_LDAP_TIMEOUT, RECDB_QSTRING);
4924 nickserv_conf.ldap_timeout = str ? strtoul(str, NULL, 0) : 5;
4925
4926 str = database_get_data(conf_node, KEY_LDAP_ADMIN_DN, RECDB_QSTRING);
4927 nickserv_conf.ldap_admin_dn = str ? str : "";
4928
4929 str = database_get_data(conf_node, KEY_LDAP_ADMIN_PASS, RECDB_QSTRING);
4930 nickserv_conf.ldap_admin_pass = str ? str : "";
4931
4932 str = database_get_data(conf_node, KEY_LDAP_FIELD_ACCOUNT, RECDB_QSTRING);
4933 nickserv_conf.ldap_field_account = str ? str : "";
4934
4935 str = database_get_data(conf_node, KEY_LDAP_FIELD_PASSWORD, RECDB_QSTRING);
4936 nickserv_conf.ldap_field_password = str ? str : "";
4937
4938 str = database_get_data(conf_node, KEY_LDAP_FIELD_EMAIL, RECDB_QSTRING);
4939 nickserv_conf.ldap_field_email = str ? str : "";
4940
4941 str = database_get_data(conf_node, KEY_LDAP_OPER_GROUP_DN, RECDB_QSTRING);
4942 nickserv_conf.ldap_oper_group_dn = str ? str : "";
4943
4944 str = database_get_data(conf_node, KEY_LDAP_OPER_GROUP_LEVEL, RECDB_QSTRING);
4945 nickserv_conf.ldap_oper_group_level = str ? strtoul(str, NULL, 0) : 99;
4946
4947 str = database_get_data(conf_node, KEY_LDAP_FIELD_GROUP_MEMBER, RECDB_QSTRING);
4948 nickserv_conf.ldap_field_group_member = str ? str : "";
4949
4950 free_string_list(nickserv_conf.ldap_object_classes);
4951 strlist = database_get_data(conf_node, KEY_LDAP_OBJECT_CLASSES, RECDB_STRING_LIST);
4952 if(strlist)
4953 strlist = string_list_copy(strlist);
4954 else {
4955 strlist = alloc_string_list(4);
4956 string_list_append(strlist, strdup("top"));
4957 }
4958 nickserv_conf.ldap_object_classes = strlist;
4959
4960#endif
4961
4962}
4963
4964static void
4965nickserv_reclaim(struct userNode *user, struct nick_info *ni, enum reclaim_action action) {
4966 const char *msg;
4967 char newnick[NICKLEN+1];
4968
4969 assert(user);
4970 assert(ni);
4971 switch (action) {
4972 case RECLAIM_NONE:
4973 /* do nothing */
4974 break;
4975 case RECLAIM_WARN:
4976 send_message(user, nickserv, "NSMSG_RECLAIM_WARN", ni->nick, ni->owner->handle);
4977 break;
4978 case RECLAIM_SVSNICK:
4979 do {
4980 snprintf(newnick, sizeof(newnick), "Guest%d", rand()%10000);
4981 } while (GetUserH(newnick));
4982 irc_svsnick(nickserv, user, newnick);
4983 break;
4984 case RECLAIM_KILL:
4985 msg = user_find_message(user, "NSMSG_RECLAIM_KILL");
4986 DelUser(user, nickserv, 1, msg);
4987 break;
4988 }
4989}
4990
4991static void
4992nickserv_reclaim_p(void *data) {
4993 struct userNode *user = data;
4994 struct nick_info *ni = get_nick_info(user->nick);
4995 if (ni)
4996 nickserv_reclaim(user, ni, nickserv_conf.auto_reclaim_action);
4997}
4998
4999static int
5000check_user_nick(struct userNode *user) {
5001 struct nick_info *ni;
5002 user->modes &= ~FLAGS_REGNICK;
5003 if (!(ni = get_nick_info(user->nick)))
5004 return 0;
5005 if (user->handle_info == ni->owner) {
5006 user->modes |= FLAGS_REGNICK;
5007 irc_regnick(user);
5008 return 0;
5009 }
5010 if (nickserv_conf.warn_nick_owned)
5011 send_message(user, nickserv, "NSMSG_RECLAIM_WARN", ni->nick, ni->owner->handle);
5012 if (nickserv_conf.auto_reclaim_action == RECLAIM_NONE)
5013 return 0;
5014 if (nickserv_conf.auto_reclaim_delay)
5015 timeq_add(now + nickserv_conf.auto_reclaim_delay, nickserv_reclaim_p, user);
5016 else
5017 nickserv_reclaim(user, ni, nickserv_conf.auto_reclaim_action);
5018
5019 return 0;
5020}
5021
5022void
5023handle_account(struct userNode *user, const char *stamp)
5024{
5025 struct handle_info *hi;
5026 char *colon;
5027
5028#ifdef WITH_PROTOCOL_P10
5029 time_t timestamp = 0;
5030
5031 colon = strchr(stamp, ':');
5032 if(colon && colon[1])
5033 {
5034 *colon = 0;
5035 timestamp = atoi(colon+1);
5036 }
5037 hi = dict_find(nickserv_handle_dict, stamp, NULL);
5038 if(hi && timestamp && hi->registered != timestamp)
5039 {
5040 log_module(MAIN_LOG, LOG_WARNING, "%s using account %s but timestamp does not match %s is not %s.", user->nick, stamp, ctime(&timestamp),
5041ctime(&hi->registered));
5042 return;
5043 }
5044#else
5045 hi = dict_find(nickserv_id_dict, stamp, NULL);
5046 log_module(MAIN_LOG, LOG_WARNING, "Using non-P10 code in accounts, not tested at all!");
5047#endif
5048
5049 if (hi) {
5050 if (HANDLE_FLAGGED(hi, SUSPENDED)) {
5051 return;
5052 }
5053 set_user_handle_info(user, hi, 0);
5054 } else {
5055 log_module(MAIN_LOG, LOG_WARNING, "%s had unknown account stamp %s.", user->nick, stamp);
5056 }
5057}
5058
5059void
5060handle_nick_change(struct userNode *user, const char *old_nick)
5061{
5062 struct handle_info *hi;
5063
5064 if ((hi = dict_find(nickserv_allow_auth_dict, old_nick, 0))) {
5065 dict_remove(nickserv_allow_auth_dict, old_nick);
5066 dict_insert(nickserv_allow_auth_dict, user->nick, hi);
5067 }
5068 timeq_del(0, nickserv_reclaim_p, user, TIMEQ_IGNORE_WHEN);
5069 check_user_nick(user);
5070}
5071
5072void
5073nickserv_remove_user(struct userNode *user, UNUSED_ARG(struct userNode *killer), UNUSED_ARG(const char *why))
5074{
5075 dict_remove(nickserv_allow_auth_dict, user->nick);
5076 timeq_del(0, nickserv_reclaim_p, user, TIMEQ_IGNORE_WHEN);
5077 set_user_handle_info(user, NULL, 0);
5078}
5079
5080static struct modcmd *
5081nickserv_define_func(const char *name, modcmd_func_t func, int min_level, int must_auth, int must_be_qualified)
5082{
5083 if (min_level > 0) {
5084 char buf[16];
5085 sprintf(buf, "%u", min_level);
5086 if (must_be_qualified) {
5087 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), "level", buf, "flags", "+qualified,+loghostmask", NULL);
5088 } else {
5089 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), "level", buf, NULL);
5090 }
5091 } else if (min_level == 0) {
5092 if (must_be_qualified) {
5093 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), "flags", "+helping", NULL);
5094 } else {
5095 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), "flags", "+helping", NULL);
5096 }
5097 } else {
5098 if (must_be_qualified) {
5099 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), "flags", "+qualified,+loghostmask", NULL);
5100 } else {
5101 return modcmd_register(nickserv_module, name, func, 1, (must_auth ? MODCMD_REQUIRE_AUTHED : 0), NULL);
5102 }
5103 }
5104}
5105
5106static void
5107nickserv_db_cleanup(void)
5108{
5109 unreg_del_user_func(nickserv_remove_user);
5110 userList_clean(&curr_helpers);
5111 policer_params_delete(nickserv_conf.auth_policer_params);
5112 dict_delete(nickserv_handle_dict);
5113 dict_delete(nickserv_nick_dict);
5114 dict_delete(nickserv_opt_dict);
5115 dict_delete(nickserv_allow_auth_dict);
5116 dict_delete(nickserv_email_dict);
5117 dict_delete(nickserv_id_dict);
5118 dict_delete(nickserv_conf.weak_password_dict);
5119 free(auth_func_list);
5120 free(unreg_func_list);
5121 free(rf_list);
5122 free(allowauth_func_list);
5123 free(handle_merge_func_list);
5124 free(failpw_func_list);
5125 if (nickserv_conf.valid_handle_regex_set)
5126 regfree(&nickserv_conf.valid_handle_regex);
5127 if (nickserv_conf.valid_nick_regex_set)
5128 regfree(&nickserv_conf.valid_nick_regex);
5129}
5130
5131void handle_loc_auth_oper(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle)) {
5132 if (!*nickserv_conf.auto_oper || !user->handle_info)
5133 return;
5134
5135 if (!IsOper(user)) {
5136 if (*nickserv_conf.auto_admin && user->handle_info->opserv_level >= opserv_conf_admin_level()) {
5137 irc_umode(user, nickserv_conf.auto_admin);
5138 irc_sno(0x1, "%s (%s@%s) is now an IRC Administrator",
5139 user->nick, user->ident, user->hostname);
5140 } else if (*nickserv_conf.auto_oper && user->handle_info->opserv_level) {
5141 irc_umode(user, nickserv_conf.auto_oper);
5142 irc_sno(0x1, "%s (%s@%s) is now an IRC Operator",
5143 user->nick, user->ident, user->hostname);
5144 }
5145 }
5146}
5147
5148void
5149init_nickserv(const char *nick)
5150{
5151 struct chanNode *chan;
5152 unsigned int i;
5153 NS_LOG = log_register_type("NickServ", "file:nickserv.log");
5154 reg_new_user_func(check_user_nick);
5155 reg_nick_change_func(handle_nick_change);
5156 reg_del_user_func(nickserv_remove_user);
5157 reg_account_func(handle_account);
5158 reg_auth_func(handle_loc_auth_oper);
5159
5160 /* set up handle_inverse_flags */
5161 memset(handle_inverse_flags, 0, sizeof(handle_inverse_flags));
5162 for (i=0; handle_flags[i]; i++) {
5163 handle_inverse_flags[(unsigned char)handle_flags[i]] = i + 1;
5164 flag_access_levels[i] = 0;
5165 }
5166
5167 conf_register_reload(nickserv_conf_read);
5168 nickserv_opt_dict = dict_new();
5169 nickserv_email_dict = dict_new();
5170
5171 dict_set_free_keys(nickserv_email_dict, free);
5172 dict_set_free_data(nickserv_email_dict, nickserv_free_email_addr);
5173
5174 nickserv_module = module_register("NickServ", NS_LOG, "nickserv.help", NULL);
5175/* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
5176 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
5177 * a big pain to disable since its nolonger in the config file. ) -Rubin
5178 */
5179 modcmd_register(nickserv_module, "AUTH", cmd_auth, 2, MODCMD_KEEP_BOUND, "flags", "+loghostmask", NULL);
5180 nickserv_define_func("ALLOWAUTH", cmd_allowauth, 0, 1, 0);
5181 nickserv_define_func("REGISTER", cmd_register, -1, 0, 0);
5182 nickserv_define_func("OREGISTER", cmd_oregister, 0, 1, 0);
5183 nickserv_define_func("UNREGISTER", cmd_unregister, -1, 1, 0);
5184 nickserv_define_func("OUNREGISTER", cmd_ounregister, 0, 1, 0);
5185 nickserv_define_func("ADDMASK", cmd_addmask, -1, 1, 0);
5186 nickserv_define_func("OADDMASK", cmd_oaddmask, 0, 1, 0);
5187 nickserv_define_func("DELMASK", cmd_delmask, -1, 1, 0);
5188 nickserv_define_func("ODELMASK", cmd_odelmask, 0, 1, 0);
5189 nickserv_define_func("PASS", cmd_pass, -1, 1, 0);
5190 nickserv_define_func("SET", cmd_set, -1, 1, 0);
5191 nickserv_define_func("OSET", cmd_oset, 0, 1, 0);
5192 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo, -1, 0, 0);
5193 nickserv_define_func("USERINFO", cmd_userinfo, -1, 1, 0);
5194 nickserv_define_func("RENAME", cmd_rename_handle, -1, 1, 0);
5195 nickserv_define_func("VACATION", cmd_vacation, -1, 1, 0);
5196 nickserv_define_func("MERGE", cmd_merge, 750, 1, 0);
5197 if (!nickserv_conf.disable_nicks) {
5198 /* nick management commands */
5199 nickserv_define_func("REGNICK", cmd_regnick, -1, 1, 0);
5200 nickserv_define_func("OREGNICK", cmd_oregnick, 0, 1, 0);
5201 nickserv_define_func("UNREGNICK", cmd_unregnick, -1, 1, 0);
5202 nickserv_define_func("OUNREGNICK", cmd_ounregnick, 0, 1, 0);
5203 nickserv_define_func("NICKINFO", cmd_nickinfo, -1, 1, 0);
5204 nickserv_define_func("RECLAIM", cmd_reclaim, -1, 1, 0);
5205 }
5206 if (nickserv_conf.email_enabled) {
5207 nickserv_define_func("AUTHCOOKIE", cmd_authcookie, -1, 0, 0);
5208 nickserv_define_func("RESETPASS", cmd_resetpass, -1, 0, 0);
5209 nickserv_define_func("COOKIE", cmd_cookie, -1, 0, 0);
5210 nickserv_define_func("DELCOOKIE", cmd_delcookie, -1, 1, 0);
5211 nickserv_define_func("ODELCOOKIE", cmd_odelcookie, 0, 1, 0);
5212 dict_insert(nickserv_opt_dict, "EMAIL", opt_email);
5213 }
5214 nickserv_define_func("GHOST", cmd_ghost, -1, 1, 0);
5215 /* ignore commands */
5216 nickserv_define_func("ADDIGNORE", cmd_addignore, -1, 1, 0);
5217 nickserv_define_func("OADDIGNORE", cmd_oaddignore, 0, 1, 0);
5218 nickserv_define_func("DELIGNORE", cmd_delignore, -1, 1, 0);
5219 nickserv_define_func("ODELIGNORE", cmd_odelignore, 0, 1, 0);
5220 /* miscellaneous commands */
5221 nickserv_define_func("STATUS", cmd_status, -1, 0, 0);
5222 nickserv_define_func("SEARCH", cmd_search, 100, 1, 0);
5223 nickserv_define_func("SEARCH UNREGISTER", NULL, 800, 1, 0);
5224 nickserv_define_func("MERGEDB", cmd_mergedb, 999, 1, 0);
5225 nickserv_define_func("CHECKPASS", cmd_checkpass, 601, 1, 0);
5226 nickserv_define_func("CHECKEMAIL", cmd_checkemail, 0, 1, 0);
5227 /* other options */
5228 dict_insert(nickserv_opt_dict, "INFO", opt_info);
5229 dict_insert(nickserv_opt_dict, "WIDTH", opt_width);
5230 dict_insert(nickserv_opt_dict, "TABLEWIDTH", opt_tablewidth);
5231 dict_insert(nickserv_opt_dict, "COLOR", opt_color);
5232 dict_insert(nickserv_opt_dict, "PRIVMSG", opt_privmsg);
5233 dict_insert(nickserv_opt_dict, "AUTOHIDE", opt_autohide);
5234 dict_insert(nickserv_opt_dict, "STYLE", opt_style);
5235 dict_insert(nickserv_opt_dict, "PASS", opt_password);
5236 dict_insert(nickserv_opt_dict, "PASSWORD", opt_password);
5237 dict_insert(nickserv_opt_dict, "FLAGS", opt_flags);
5238 dict_insert(nickserv_opt_dict, "ACCESS", opt_level);
5239 dict_insert(nickserv_opt_dict, "LEVEL", opt_level);
5240 dict_insert(nickserv_opt_dict, "EPITHET", opt_epithet);
5241 dict_insert(nickserv_opt_dict, "NOTE", opt_note);
5242 if (nickserv_conf.titlehost_suffix) {
5243 dict_insert(nickserv_opt_dict, "TITLE", opt_title);
5244 dict_insert(nickserv_opt_dict, "FAKEHOST", opt_fakehost);
5245 }
5246 dict_insert(nickserv_opt_dict, "ANNOUNCEMENTS", opt_announcements);
5247 dict_insert(nickserv_opt_dict, "MAXLOGINS", opt_maxlogins);
5248 dict_insert(nickserv_opt_dict, "ADVANCED", opt_advanced);
5249 dict_insert(nickserv_opt_dict, "LANGUAGE", opt_language);
5250 dict_insert(nickserv_opt_dict, "KARMA", opt_karma);
5251
5252 nickserv_handle_dict = dict_new();
5253 dict_set_free_keys(nickserv_handle_dict, free);
5254 dict_set_free_data(nickserv_handle_dict, free_handle_info);
5255
5256 nickserv_id_dict = dict_new();
5257 dict_set_free_keys(nickserv_id_dict, free);
5258
5259 nickserv_nick_dict = dict_new();
5260 dict_set_free_data(nickserv_nick_dict, free);
5261
5262 nickserv_allow_auth_dict = dict_new();
5263
5264 userList_init(&curr_helpers);
5265
5266 if (nick) {
5267 const char *modes = conf_get_data("services/nickserv/modes", RECDB_QSTRING);
5268 nickserv = AddLocalUser(nick, nick, NULL, "Nick Services", modes);
5269 nickserv_service = service_register(nickserv);
5270 }
5271 saxdb_register("NickServ", nickserv_saxdb_read, nickserv_saxdb_write);
5272 reg_exit_func(nickserv_db_cleanup);
5273 if(nickserv_conf.handle_expire_frequency)
5274 timeq_add(now + nickserv_conf.handle_expire_frequency, expire_handles, NULL);
5275
5276 if(autojoin_channels && nickserv) {
5277 for (i = 0; i < autojoin_channels->used; i++) {
5278 chan = AddChannel(autojoin_channels->list[i], now, "+nt", NULL, NULL);
5279 AddChannelUser(nickserv, chan)->modes |= MODE_CHANOP;
5280 }
5281 }
5282#ifdef WITH_LDAP
5283 ldap_do_init(nickserv_conf);
5284#endif
5285
5286 message_register_table(msgtab);
5287}