1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * srvx 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 2 of the License, or
9 * (at your option) any later version.
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.
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.
25 #include "opserv.h" /* for gag_create(), opserv_bad_channel() */
34 #define NICKSERV_CONF_NAME "services/nickserv"
36 #define KEY_DISABLE_NICKS "disable_nicks"
37 #define KEY_DEFAULT_HOSTMASK "default_hostmask"
38 #define KEY_NICKS_PER_HANDLE "nicks_per_handle"
39 #define KEY_NICKS_PER_ACCOUNT "nicks_per_account"
40 #define KEY_PASSWORD_MIN_LENGTH "password_min_length"
41 #define KEY_PASSWORD_MIN_DIGITS "password_min_digits"
42 #define KEY_PASSWORD_MIN_UPPER "password_min_upper"
43 #define KEY_PASSWORD_MIN_LOWER "password_min_lower"
44 #define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
45 #define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
46 #define KEY_VALID_NICK_REGEX "valid_nick_regex"
47 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
48 #define KEY_MODOPER_LEVEL "modoper_level"
49 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
50 #define KEY_SET_TITLE_LEVEL "set_title_level"
51 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
52 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
53 #define KEY_FLAG_LEVELS "flag_levels"
54 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
55 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
56 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
57 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
58 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
59 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
60 #define KEY_DICT_FILE "dict_file"
61 #define KEY_NICK "nick"
62 #define KEY_LANGUAGE "language"
63 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
64 #define KEY_AUTOGAG_DURATION "autogag_duration"
65 #define KEY_AUTH_POLICER "auth_policer"
66 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
67 #define KEY_EMAIL_ENABLED "email_enabled"
68 #define KEY_EMAIL_REQUIRED "email_required"
69 #define KEY_SYNC_LOG "sync_log"
70 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
71 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
72 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
75 #define KEY_PASSWD "passwd"
76 #define KEY_NICKS "nicks"
77 #define KEY_MASKS "masks"
78 #define KEY_OPSERV_LEVEL "opserv_level"
79 #define KEY_FLAGS "flags"
80 #define KEY_REGISTER_ON "register"
81 #define KEY_LAST_SEEN "lastseen"
82 #define KEY_INFO "info"
83 #define KEY_USERLIST_STYLE "user_style"
84 #define KEY_SCREEN_WIDTH "screen_width"
85 #define KEY_LAST_AUTHED_HOST "last_authed_host"
86 #define KEY_LAST_QUIT_HOST "last_quit_host"
87 #define KEY_EMAIL_ADDR "email_addr"
88 #define KEY_COOKIE "cookie"
89 #define KEY_COOKIE_DATA "data"
90 #define KEY_COOKIE_TYPE "type"
91 #define KEY_COOKIE_EXPIRES "expires"
92 #define KEY_ACTIVATION "activation"
93 #define KEY_PASSWORD_CHANGE "password change"
94 #define KEY_EMAIL_CHANGE "email change"
95 #define KEY_ALLOWAUTH "allowauth"
96 #define KEY_EPITHET "epithet"
97 #define KEY_TABLE_WIDTH "table_width"
98 #define KEY_ANNOUNCEMENTS "announcements"
99 #define KEY_MAXLOGINS "maxlogins"
100 #define KEY_FAKEHOST "fakehost"
102 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
104 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
105 #define OPTION_FUNC(NAME) int NAME(struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
106 typedef OPTION_FUNC(option_func_t
);
108 DEFINE_LIST(handle_info_list
, struct handle_info
*);
110 #define NICKSERV_MIN_PARMS(N) do { \
112 reply("MSG_MISSING_PARAMS", argv[0]); \
113 svccmd_send_help_brief(user, nickserv, cmd); \
117 struct userNode
*nickserv
;
118 struct userList curr_helpers
;
119 const char *handle_flags
= HANDLE_FLAGS
;
121 static struct module *nickserv_module
;
122 static struct service
*nickserv_service
;
123 static struct log_type
*NS_LOG
;
124 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
125 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
126 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
127 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
128 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
129 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
130 static char handle_inverse_flags
[256];
131 static unsigned int flag_access_levels
[32];
132 static const struct message_entry msgtab
[] = {
133 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
134 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu charactors or less."},
135 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
136 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
137 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
138 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
139 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
140 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
141 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
142 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
143 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
144 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
145 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
146 { "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." },
147 { "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." },
148 { "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." },
149 { "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." },
150 { "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." },
151 { "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." },
152 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
153 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
154 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
155 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
156 { "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." },
157 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
158 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
159 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
160 { "NSMSG_EMAIL_OVERUSED", "There are already the maximum number of accounts associated with that email address." },
161 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
162 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
163 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
164 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
165 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
166 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
167 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
168 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
169 { "NSMSG_REGISTER_BAD_NICKMASK", "Could not recognize $b%s$b as either a current nick or a hostmask." },
170 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
171 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
172 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
173 { "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)" },
174 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
175 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
176 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
177 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
178 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
179 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
180 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
181 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
182 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
183 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
184 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
185 { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
186 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
187 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
188 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
189 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
190 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
191 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
192 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
193 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
194 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
195 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
196 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
197 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
198 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
199 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
200 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
201 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
202 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
203 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
204 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
205 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
206 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
207 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
208 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
209 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
210 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
211 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
212 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
213 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
214 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
215 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
216 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
217 { "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)." },
218 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
219 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
220 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
221 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
222 { "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." },
223 { "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." },
224 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
225 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
226 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
227 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
228 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
229 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
230 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
231 { "NSMSG_PASS_SUCCESS", "Password changed." },
232 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
233 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
234 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
235 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
236 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
237 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
238 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
239 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
240 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
241 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
242 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
243 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
244 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
245 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
246 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
247 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
248 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
249 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
250 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
251 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
252 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
253 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
254 { "NSMSG_NO_ACCESS", "Access denied." },
255 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
256 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
257 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
258 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
259 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
260 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
261 { "NSMSG_BAD_HANDLE", "Account $b%s$b not registered because it is in use by a network service, is too long, or contains invalid characters." },
262 { "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." },
263 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
264 { "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." },
265 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
266 { "NSMSG_SEARCH_MATCH", "Match: %s" },
267 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
268 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
269 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
270 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
271 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
272 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
273 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
274 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
275 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
276 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
277 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
278 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
279 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
280 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
281 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
282 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
283 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
284 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
285 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
286 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
287 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
288 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
289 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
290 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
291 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
292 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
293 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
294 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
295 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
296 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
297 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
298 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
299 { "NSEMAIL_ACTIVATION_BODY",
300 "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"
302 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
303 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
304 "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"
305 "/msg %3$s@%4$s AUTH %5$s your-password\n"
306 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
307 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
309 "If you did NOT request this account, you do not need to do anything.\n"
310 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
311 { "NSEMAIL_ACTIVATION_BODY_WEB",
312 "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"
314 "To verify your email address and complete the account registration, visit the following URL:\n"
315 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
317 "If you did NOT request this account, you do not need to do anything.\n"
318 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
319 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
320 { "NSEMAIL_PASSWORD_CHANGE_BODY",
321 "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"
322 "To complete the password change, log on to %1$s and type the following command:\n"
323 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
324 "If you did NOT request your password to be changed, you do not need to do anything.\n"
325 "Please contact the %1$s staff if you have questions." },
326 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
327 "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"
328 "To complete the password change, click the following URL:\n"
329 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
330 "If you did NOT request your password to be changed, you do not need to do anything.\n"
331 "Please contact the %1$s staff if you have questions." },
332 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
333 #ifdef stupid_verify_old_email
334 { "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." },
335 { "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." },
337 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
338 { "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." },
339 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
340 { "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." },
341 { "CHECKPASS_YES", "Yes." },
342 { "CHECKPASS_NO", "No." },
346 enum reclaim_action
{
352 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
353 static void nickserv_reclaim_p(void *data
);
356 unsigned int disable_nicks
: 1;
357 unsigned int valid_handle_regex_set
: 1;
358 unsigned int valid_nick_regex_set
: 1;
359 unsigned int autogag_enabled
: 1;
360 unsigned int email_enabled
: 1;
361 unsigned int email_required
: 1;
362 unsigned int default_hostmask
: 1;
363 unsigned int warn_nick_owned
: 1;
364 unsigned int warn_clone_auth
: 1;
365 unsigned int sync_log
: 1;
366 unsigned long nicks_per_handle
;
367 unsigned long password_min_length
;
368 unsigned long password_min_digits
;
369 unsigned long password_min_upper
;
370 unsigned long password_min_lower
;
371 unsigned long db_backup_frequency
;
372 unsigned long handle_expire_frequency
;
373 unsigned long autogag_duration
;
374 unsigned long email_visible_level
;
375 unsigned long cookie_timeout
;
376 unsigned long handle_expire_delay
;
377 unsigned long nochan_handle_expire_delay
;
378 unsigned long modoper_level
;
379 unsigned long set_epithet_level
;
380 unsigned long set_title_level
;
381 unsigned long set_fakehost_level
;
382 unsigned long handles_per_email
;
383 unsigned long email_search_level
;
384 const char *network_name
;
385 const char *titlehost_suffix
;
386 regex_t valid_handle_regex
;
387 regex_t valid_nick_regex
;
388 dict_t weak_password_dict
;
389 struct policer_params
*auth_policer_params
;
390 enum reclaim_action reclaim_action
;
391 enum reclaim_action auto_reclaim_action
;
392 unsigned long auto_reclaim_delay
;
393 unsigned char default_maxlogins
;
394 unsigned char hard_maxlogins
;
397 /* We have 2^32 unique account IDs to use. */
398 unsigned long int highest_id
= 0;
401 canonicalize_hostmask(char *mask
)
403 char *out
= mask
, *temp
;
404 if ((temp
= strchr(mask
, '!'))) {
406 while (*temp
) *out
++ = *temp
++;
412 static struct handle_info
*
413 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
415 struct handle_info
*hi
;
417 #ifdef WITH_PROTOCOL_BAHAMUT
418 char id_base64
[IDLEN
+ 1];
421 /* Assign a unique account ID to the account; note that 0 is
422 an invalid account ID. 1 is therefore the first account ID. */
424 id
= 1 + highest_id
++;
426 /* Note: highest_id is and must always be the highest ID. */
427 if(id
> highest_id
) {
431 inttobase64(id_base64
, id
, IDLEN
);
433 /* Make sure an account with the same ID doesn't exist. If a
434 duplicate is found, log some details and assign a new one.
435 This should be impossible, but it never hurts to expect it. */
436 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
437 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
443 hi
= calloc(1, sizeof(*hi
));
444 hi
->userlist_style
= HI_DEFAULT_STYLE
;
445 hi
->announcements
= '?';
446 hi
->handle
= strdup(handle
);
447 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
449 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
451 #ifdef WITH_PROTOCOL_BAHAMUT
453 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
460 register_nick(const char *nick
, struct handle_info
*owner
)
462 struct nick_info
*ni
;
463 ni
= malloc(sizeof(struct nick_info
));
464 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
466 ni
->next
= owner
->nicks
;
468 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
472 delete_nick(struct nick_info
*ni
)
474 struct nick_info
*last
, *next
;
475 struct userNode
*user
;
476 /* Check to see if we should mark a user as unregistered. */
477 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
478 user
->modes
&= ~FLAGS_REGNICK
;
481 /* Remove ni from the nick_info linked list. */
482 if (ni
== ni
->owner
->nicks
) {
483 ni
->owner
->nicks
= ni
->next
;
485 last
= ni
->owner
->nicks
;
491 last
->next
= next
->next
;
493 dict_remove(nickserv_nick_dict
, ni
->nick
);
496 static unreg_func_t
*unreg_func_list
;
497 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
500 reg_unreg_func(unreg_func_t func
)
502 if (unreg_func_used
== unreg_func_size
) {
503 if (unreg_func_size
) {
504 unreg_func_size
<<= 1;
505 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
508 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
511 unreg_func_list
[unreg_func_used
++] = func
;
515 nickserv_free_cookie(void *data
)
517 struct handle_cookie
*cookie
= data
;
518 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
519 if (cookie
->data
) free(cookie
->data
);
524 free_handle_info(void *vhi
)
526 struct handle_info
*hi
= vhi
;
528 #ifdef WITH_PROTOCOL_BAHAMUT
531 inttobase64(id
, hi
->id
, IDLEN
);
532 dict_remove(nickserv_id_dict
, id
);
535 free_string_list(hi
->masks
);
539 delete_nick(hi
->nicks
);
544 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
545 nickserv_free_cookie(hi
->cookie
);
547 if (hi
->email_addr
) {
548 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
549 handle_info_list_remove(hil
, hi
);
551 dict_remove(nickserv_email_dict
, hi
->email_addr
);
556 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
559 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
)
563 for (n
=0; n
<unreg_func_used
; n
++)
564 unreg_func_list
[n
](notify
, hi
);
566 set_user_handle_info(hi
->users
, NULL
, 0);
568 if (nickserv_conf
.disable_nicks
)
569 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
571 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
574 if (nickserv_conf
.sync_log
)
575 SyncLog("UNREGISTER %s", hi
->handle
);
577 dict_remove(nickserv_handle_dict
, hi
->handle
);
581 get_handle_info(const char *handle
)
583 return dict_find(nickserv_handle_dict
, handle
, 0);
587 get_nick_info(const char *nick
)
589 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
593 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
598 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
599 mn
= channel
->members
.list
[nn
];
600 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
607 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
608 if (!user
->handle_info
) {
610 send_message(user
, bot
, "MSG_AUTHENTICATE");
614 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
616 send_message(user
, bot
, "NSMSG_NO_ACCESS");
620 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
622 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
626 if (user
->handle_info
->opserv_level
< min_level
) {
628 send_message(user
, bot
, "NSMSG_NO_ACCESS");
636 is_valid_handle(const char *handle
)
638 struct userNode
*user
;
639 /* cant register a juped nick/service nick as handle, to prevent confusion */
640 user
= GetUserH(handle
);
641 if (user
&& IsLocal(user
))
643 /* check against maximum length */
644 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
646 /* for consistency, only allow account names that could be nicks */
647 if (!is_valid_nick(handle
))
649 /* disallow account names that look like bad words */
650 if (opserv_bad_channel(handle
))
652 /* test either regex or containing all valid chars */
653 if (nickserv_conf
.valid_handle_regex_set
) {
654 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
657 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
658 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
662 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
667 is_registerable_nick(const char *nick
)
669 /* make sure it could be used as an account name */
670 if (!is_valid_handle(nick
))
673 if (strlen(nick
) > NICKLEN
)
675 /* test either regex or as valid handle */
676 if (nickserv_conf
.valid_nick_regex_set
) {
677 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
680 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
681 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
689 is_valid_email_addr(const char *email
)
691 return strchr(email
, '@') != NULL
;
695 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
697 if (hi
->email_addr
) {
698 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
699 return hi
->email_addr
;
709 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
711 struct handle_info
*hi
;
712 struct userNode
*target
;
716 if (!(hi
= get_handle_info(++name
))) {
717 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
722 if (!(target
= GetUserH(name
))) {
723 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
726 if (IsLocal(target
)) {
727 if (IsService(target
))
728 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
730 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
733 if (!(hi
= target
->handle_info
)) {
734 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
742 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
743 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
745 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
746 if ((user
->handle_info
->opserv_level
== 1000)
747 || (user
->handle_info
== hi
)
748 || ((user
->handle_info
->opserv_level
== 0)
749 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
750 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
754 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
758 static struct handle_info
*
759 get_victim_oper(struct userNode
*user
, const char *target
)
761 struct handle_info
*hi
;
762 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
764 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
765 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
768 return oper_outranks(user
, hi
) ? hi
: NULL
;
772 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
776 /* If no hostmasks on the account, allow it. */
777 if (!hi
->masks
->used
)
779 /* If any hostmask matches, allow it. */
780 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
781 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
783 /* If they are allowauthed to this account, allow it (removing the aa). */
784 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
785 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
788 /* The user is not allowed to use this account. */
793 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
796 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
798 if (len
< nickserv_conf
.password_min_length
) {
800 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
803 if (!irccasecmp(pass
, handle
)) {
805 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
808 dict_find(nickserv_conf
.weak_password_dict
, pass
, &i
);
811 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
814 for (i
=0; i
<len
; i
++) {
815 if (isdigit(pass
[i
]))
817 if (isupper(pass
[i
]))
819 if (islower(pass
[i
]))
822 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
823 || (cnt_upper
< nickserv_conf
.password_min_upper
)
824 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
826 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
832 static auth_func_t
*auth_func_list
;
833 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
836 reg_auth_func(auth_func_t func
)
838 if (auth_func_used
== auth_func_size
) {
839 if (auth_func_size
) {
840 auth_func_size
<<= 1;
841 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
844 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
847 auth_func_list
[auth_func_used
++] = func
;
850 static handle_rename_func_t
*rf_list
;
851 static unsigned int rf_list_size
, rf_list_used
;
854 reg_handle_rename_func(handle_rename_func_t func
)
856 if (rf_list_used
== rf_list_size
) {
859 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
862 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
865 rf_list
[rf_list_used
++] = func
;
869 generate_fakehost(struct handle_info
*handle
)
871 extern const char *hidden_host_suffix
;
872 static char buffer
[HOSTLEN
+1];
874 if (!handle
->fakehost
) {
875 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
877 } else if (handle
->fakehost
[0] == '.') {
878 /* A leading dot indicates the stored value is actually a title. */
879 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
882 return handle
->fakehost
;
886 apply_fakehost(struct handle_info
*handle
)
888 struct userNode
*target
;
893 fake
= generate_fakehost(handle
);
894 for (target
= handle
->users
; target
; target
= target
->next_authed
)
895 assign_fakehost(target
, fake
, 1);
899 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
902 struct handle_info
*old_info
;
904 /* This can happen if somebody uses COOKIE while authed, or if
905 * they re-auth to their current handle (which is silly, but users
907 if (user
->handle_info
== hi
)
910 if (user
->handle_info
) {
911 struct userNode
*other
;
914 userList_remove(&curr_helpers
, user
);
916 /* remove from next_authed linked list */
917 if (user
->handle_info
->users
== user
) {
918 user
->handle_info
->users
= user
->next_authed
;
920 for (other
= user
->handle_info
->users
;
921 other
->next_authed
!= user
;
922 other
= other
->next_authed
) ;
923 other
->next_authed
= user
->next_authed
;
925 /* if nobody left on old handle, and they're not an oper, remove !god */
926 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
927 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
928 /* record them as being last seen at this time */
929 user
->handle_info
->lastseen
= now
;
930 /* and record their hostmask */
931 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
933 old_info
= user
->handle_info
;
934 user
->handle_info
= hi
;
935 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
936 HANDLE_CLEAR_FLAG(hi
, HELPING
);
937 for (n
=0; n
<auth_func_used
; n
++)
938 auth_func_list
[n
](user
, old_info
);
940 struct nick_info
*ni
;
942 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
943 if (nickserv_conf
.warn_clone_auth
) {
944 struct userNode
*other
;
945 for (other
= hi
->users
; other
; other
= other
->next_authed
)
946 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
948 user
->next_authed
= hi
->users
;
952 userList_append(&curr_helpers
, user
);
954 if (hi
->fakehost
|| old_info
)
958 #ifdef WITH_PROTOCOL_BAHAMUT
959 /* Stamp users with their account ID. */
961 inttobase64(id
, hi
->id
, IDLEN
);
962 #elif WITH_PROTOCOL_P10
963 /* Stamp users with their account name. */
964 char *id
= hi
->handle
;
966 const char *id
= "???";
968 if (!nickserv_conf
.disable_nicks
) {
969 struct nick_info
*ni
;
970 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
971 if (!irccasecmp(user
->nick
, ni
->nick
)) {
972 user
->modes
|= FLAGS_REGNICK
;
977 StampUser(user
, id
, hi
->registered
);
980 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
981 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
983 /* We cannot clear the user's account ID, unfortunately. */
984 user
->next_authed
= NULL
;
988 static struct handle_info
*
989 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
991 struct handle_info
*hi
;
992 struct nick_info
*ni
;
993 char crypted
[MD5_CRYPT_LENGTH
];
995 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
996 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1000 if(strlen(handle
) > 15)
1002 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1006 if (!is_secure_password(handle
, passwd
, user
))
1009 cryptpass(passwd
, crypted
);
1010 hi
= register_handle(handle
, crypted
, 0);
1011 hi
->masks
= alloc_string_list(1);
1013 hi
->language
= lang_C
;
1014 hi
->registered
= now
;
1016 hi
->flags
= HI_DEFAULT_FLAGS
;
1017 if (settee
&& !no_auth
)
1018 set_user_handle_info(settee
, hi
, 1);
1021 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1022 else if (nickserv_conf
.disable_nicks
)
1023 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1024 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1025 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1027 register_nick(user
->nick
, hi
);
1028 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1030 if (settee
&& (user
!= settee
))
1031 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1036 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1038 cookie
->hi
->cookie
= cookie
;
1039 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1042 /* Contributed by the great sneep of afternet ;) */
1043 /* Since this gets used in a URL, we want to avoid stuff that confuses
1044 * email clients such as ] and ?. a-z, 0-9 only.
1046 void genpass(char *str
, int len
)
1051 for(i
= 0; i
< len
; i
++)
1055 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1056 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1064 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1066 struct handle_cookie
*cookie
;
1067 char subject
[128], body
[4096], *misc
;
1068 const char *netname
, *fmt
;
1072 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1076 cookie
= calloc(1, sizeof(*cookie
));
1078 cookie
->type
= type
;
1079 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1081 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1082 /* Adding dedicated password gen function for more control -Rubin */
1083 genpass(cookie
->cookie
, 10);
1085 *inttobase64(cookie->cookie, rand(), 5);
1086 *inttobase64(cookie->cookie+5, rand(), 5);
1089 netname
= nickserv_conf
.network_name
;
1092 switch (cookie
->type
) {
1094 hi
->passwd
[0] = 0; /* invalidate password */
1095 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1096 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1097 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1100 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1102 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1104 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1107 case PASSWORD_CHANGE
:
1108 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1109 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1110 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1112 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1114 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1115 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1118 misc
= hi
->email_addr
;
1119 hi
->email_addr
= cookie
->data
;
1120 #ifdef stupid_verify_old_email
1122 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1123 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1124 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1125 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1126 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1127 sendmail(nickserv
, hi
, subject
, body
, 1);
1128 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1129 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1132 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1133 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1134 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1135 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1136 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1137 sendmail(nickserv
, hi
, subject
, body
, 1);
1139 #ifdef stupid_verify_old_email
1142 hi
->email_addr
= misc
;
1145 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1146 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1147 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1148 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1149 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1152 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1156 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1157 nickserv_bake_cookie(cookie
);
1161 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1163 cookie
->hi
->cookie
= NULL
;
1164 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1165 nickserv_free_cookie(cookie
);
1169 nickserv_free_email_addr(void *data
)
1171 handle_info_list_clean(data
);
1176 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1178 struct handle_info_list
*hil
;
1179 /* Remove from old handle_info_list ... */
1180 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1181 handle_info_list_remove(hil
, hi
);
1182 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1183 hi
->email_addr
= NULL
;
1185 /* Add to the new list.. */
1186 if (new_email_addr
) {
1187 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1188 hil
= calloc(1, sizeof(*hil
));
1189 hil
->tag
= strdup(new_email_addr
);
1190 handle_info_list_init(hil
);
1191 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1193 handle_info_list_append(hil
, hi
);
1194 hi
->email_addr
= hil
->tag
;
1198 static NICKSERV_FUNC(cmd_register
)
1200 struct handle_info
*hi
;
1201 const char *email_addr
, *password
;
1202 char syncpass
[MD5_CRYPT_LENGTH
];
1203 int no_auth
, weblink
;
1205 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1206 /* Require the first handle registered to belong to someone +o. */
1207 reply("NSMSG_REQUIRE_OPER");
1211 if (user
->handle_info
) {
1212 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1216 if (IsRegistering(user
)) {
1217 reply("NSMSG_ALREADY_REGISTERING");
1221 if (IsStamped(user
)) {
1222 /* Unauthenticated users might still have been stamped
1223 previously and could therefore have a hidden host;
1224 do not allow them to register a new account. */
1225 reply("NSMSG_STAMPED_REGISTER");
1229 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1231 if (!is_valid_handle(argv
[1])) {
1232 reply("NSMSG_BAD_HANDLE", argv
[1]);
1237 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1238 struct handle_info_list
*hil
;
1241 /* Remember email address. */
1242 email_addr
= argv
[3];
1244 /* Check that the email address looks valid.. */
1245 if (!is_valid_email_addr(email_addr
)) {
1246 reply("NSMSG_BAD_EMAIL_ADDR");
1250 /* .. and that we are allowed to send to it. */
1251 if ((str
= sendmail_prohibited_address(email_addr
))) {
1252 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1256 /* If we do email verify, make sure we don't spam the address. */
1257 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1259 for (nn
=0; nn
<hil
->used
; nn
++) {
1260 if (hil
->list
[nn
]->cookie
) {
1261 reply("NSMSG_EMAIL_UNACTIVATED");
1265 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1266 reply("NSMSG_EMAIL_OVERUSED");
1279 /* Webregister hack - send URL instead of IRC cookie
1282 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1286 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1288 /* Add any masks they should get. */
1289 if (nickserv_conf
.default_hostmask
) {
1290 string_list_append(hi
->masks
, strdup("*@*"));
1292 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1293 if (user
->ip
.s_addr
&& user
->hostname
[strspn(user
->hostname
, "0123456789.")])
1294 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1297 /* If they're the first to register, give them level 1000. */
1298 if (dict_size(nickserv_handle_dict
) == 1) {
1299 hi
->opserv_level
= 1000;
1300 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1303 /* Set their email address. */
1305 nickserv_set_email_addr(hi
, email_addr
);
1307 /* If they need to do email verification, tell them. */
1309 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1311 /* Set registering flag.. */
1312 user
->modes
|= FLAGS_REGISTERING
;
1314 if (nickserv_conf
.sync_log
) {
1315 cryptpass(password
, syncpass
);
1317 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1318 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1321 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1323 process_adduser_pending(user
);
1328 static NICKSERV_FUNC(cmd_oregister
)
1331 struct userNode
*settee
;
1332 struct handle_info
*hi
;
1334 NICKSERV_MIN_PARMS(4);
1336 if (!is_valid_handle(argv
[1])) {
1337 reply("NSMSG_BAD_HANDLE", argv
[1]);
1341 if (strchr(argv
[3], '@')) {
1342 mask
= canonicalize_hostmask(strdup(argv
[3]));
1344 settee
= GetUserH(argv
[4]);
1346 reply("MSG_NICK_UNKNOWN", argv
[4]);
1353 } else if ((settee
= GetUserH(argv
[3]))) {
1354 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1356 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1359 if (settee
&& settee
->handle_info
) {
1360 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1364 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1368 string_list_append(hi
->masks
, mask
);
1372 static NICKSERV_FUNC(cmd_handleinfo
)
1375 unsigned int i
, pos
=0, herelen
;
1376 struct userNode
*target
, *next_un
;
1377 struct handle_info
*hi
;
1378 const char *nsmsg_none
;
1381 if (!(hi
= user
->handle_info
)) {
1382 reply("NSMSG_MUST_AUTH");
1385 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1389 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1390 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1392 #ifdef WITH_PROTOCOL_BAHAMUT
1393 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1395 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1398 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1399 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1401 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1404 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1405 if (HANDLE_FLAGGED(hi
, FROZEN
))
1406 reply("NSMSG_HANDLEINFO_VACATION");
1408 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1409 struct do_not_register
*dnr
;
1410 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1411 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1412 if (!oper_outranks(user
, hi
))
1414 } else if (hi
!= user
->handle_info
) {
1415 reply("NSMSG_HANDLEINFO_END");
1419 if (nickserv_conf
.email_enabled
)
1420 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1424 switch (hi
->cookie
->type
) {
1425 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1426 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1427 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1428 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1429 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1435 unsigned long flen
= 1;
1436 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1438 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1439 if (hi
->flags
& 1 << i
)
1440 flags
[flen
++] = handle_flags
[i
];
1442 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1444 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1447 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1448 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1449 || (hi
->opserv_level
> 0)) {
1450 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1454 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1456 if (hi
->last_quit_host
[0])
1457 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1459 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1461 if (nickserv_conf
.disable_nicks
) {
1462 /* nicks disabled; don't show anything about registered nicks */
1463 } else if (hi
->nicks
) {
1464 struct nick_info
*ni
, *next_ni
;
1465 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1466 herelen
= strlen(ni
->nick
);
1467 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1469 goto print_nicks_buff
;
1473 memcpy(buff
+pos
, ni
->nick
, herelen
);
1474 pos
+= herelen
; buff
[pos
++] = ' ';
1478 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1483 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1486 if (hi
->masks
->used
) {
1487 for (i
=0; i
< hi
->masks
->used
; i
++) {
1488 herelen
= strlen(hi
->masks
->list
[i
]);
1489 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1491 goto print_mask_buff
;
1493 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1494 pos
+= herelen
; buff
[pos
++] = ' ';
1495 if (i
+1 == hi
->masks
->used
) {
1498 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1503 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1507 struct userData
*channel
, *next
;
1510 for (channel
= hi
->channels
; channel
; channel
= next
) {
1511 next
= channel
->u_next
;
1512 name
= channel
->channel
->channel
->name
;
1513 herelen
= strlen(name
);
1514 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1516 goto print_chans_buff
;
1518 if (IsUserSuspended(channel
))
1520 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1524 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1529 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1532 for (target
= hi
->users
; target
; target
= next_un
) {
1533 herelen
= strlen(target
->nick
);
1534 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1536 goto print_cnick_buff
;
1538 next_un
= target
->next_authed
;
1540 memcpy(buff
+pos
, target
->nick
, herelen
);
1541 pos
+= herelen
; buff
[pos
++] = ' ';
1545 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1550 reply("NSMSG_HANDLEINFO_END");
1554 static NICKSERV_FUNC(cmd_userinfo
)
1556 struct userNode
*target
;
1558 NICKSERV_MIN_PARMS(2);
1559 if (!(target
= GetUserH(argv
[1]))) {
1560 reply("MSG_NICK_UNKNOWN", argv
[1]);
1563 if (target
->handle_info
)
1564 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1566 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1570 static NICKSERV_FUNC(cmd_nickinfo
)
1572 struct nick_info
*ni
;
1574 NICKSERV_MIN_PARMS(2);
1575 if (!(ni
= get_nick_info(argv
[1]))) {
1576 reply("MSG_NICK_UNKNOWN", argv
[1]);
1579 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1583 static NICKSERV_FUNC(cmd_rename_handle
)
1585 struct handle_info
*hi
;
1586 char msgbuf
[MAXLEN
], *old_handle
;
1589 NICKSERV_MIN_PARMS(3);
1590 if (!(hi
= get_victim_oper(user
, argv
[1])))
1592 if (!is_valid_handle(argv
[2])) {
1593 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1596 if (get_handle_info(argv
[2])) {
1597 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1600 if(strlen(argv
[2]) > 15)
1602 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1606 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1607 hi
->handle
= strdup(argv
[2]);
1608 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1609 for (nn
=0; nn
<rf_list_used
; nn
++)
1610 rf_list
[nn
](hi
, old_handle
);
1611 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1612 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1613 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1618 static failpw_func_t
*failpw_func_list
;
1619 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1622 reg_failpw_func(failpw_func_t func
)
1624 if (failpw_func_used
== failpw_func_size
) {
1625 if (failpw_func_size
) {
1626 failpw_func_size
<<= 1;
1627 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1629 failpw_func_size
= 8;
1630 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1633 failpw_func_list
[failpw_func_used
++] = func
;
1637 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1639 * called by nefariouses enhanced AC login-on-connect code
1642 struct handle_info
*loc_auth(char *handle
, char *password
)
1644 int pw_arg
, used
, maxlogins
;
1647 struct handle_info
*hi
;
1648 struct userNode
*other
;
1650 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1656 /* We don't know the users hostname, or anything because they
1657 * havn't registered yet. So we can only allow LOC if your
1658 * account has *@* as a hostmask.
1660 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1662 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1671 /* Responses from here on look up the language used by the handle they asked about. */
1672 if (!checkpass(password
, hi
->passwd
)) {
1675 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1678 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1679 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1680 if (++used
>= maxlogins
) {
1687 static NICKSERV_FUNC(cmd_auth
)
1689 int pw_arg
, used
, maxlogins
;
1690 struct handle_info
*hi
;
1692 struct userNode
*other
;
1694 if (user
->handle_info
) {
1695 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1698 if (IsStamped(user
)) {
1699 /* Unauthenticated users might still have been stamped
1700 previously and could therefore have a hidden host;
1701 do not allow them to authenticate. */
1702 reply("NSMSG_STAMPED_AUTH");
1706 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1708 } else if (argc
== 2) {
1709 if (nickserv_conf
.disable_nicks
) {
1710 if (!(hi
= get_handle_info(user
->nick
))) {
1711 reply("NSMSG_HANDLE_NOT_FOUND");
1715 /* try to look up their handle from their nick */
1716 struct nick_info
*ni
;
1717 ni
= get_nick_info(user
->nick
);
1719 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1726 reply("MSG_MISSING_PARAMS", argv
[0]);
1727 svccmd_send_help(user
, nickserv
, cmd
);
1731 reply("NSMSG_HANDLE_NOT_FOUND");
1734 /* Responses from here on look up the language used by the handle they asked about. */
1735 passwd
= argv
[pw_arg
];
1736 if (!valid_user_for(user
, hi
)) {
1737 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1738 send_message_type(4, user
, cmd
->parent
->bot
,
1739 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1742 send_message_type(4, user
, cmd
->parent
->bot
,
1743 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1745 argv
[pw_arg
] = "BADMASK";
1748 if (!checkpass(passwd
, hi
->passwd
)) {
1750 send_message_type(4, user
, cmd
->parent
->bot
,
1751 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1752 argv
[pw_arg
] = "BADPASS";
1753 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1754 if (nickserv_conf
.autogag_enabled
) {
1755 if (!user
->auth_policer
.params
) {
1756 user
->auth_policer
.last_req
= now
;
1757 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1759 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1761 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1762 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1763 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1765 argv
[pw_arg
] = "GAGGED";
1770 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1771 send_message_type(4, user
, cmd
->parent
->bot
,
1772 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1773 argv
[pw_arg
] = "SUSPENDED";
1776 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1777 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1778 if (++used
>= maxlogins
) {
1779 send_message_type(4, user
, cmd
->parent
->bot
,
1780 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1782 argv
[pw_arg
] = "MAXLOGINS";
1787 set_user_handle_info(user
, hi
, 1);
1788 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1789 reply("NSMSG_PLEASE_SET_EMAIL");
1790 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1791 reply("NSMSG_WEAK_PASSWORD");
1792 if (hi
->passwd
[0] != '$')
1793 cryptpass(passwd
, hi
->passwd
);
1794 reply("NSMSG_AUTH_SUCCESS");
1796 process_adduser_pending(user
);
1797 argv
[pw_arg
] = "****";
1801 static allowauth_func_t
*allowauth_func_list
;
1802 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
1805 reg_allowauth_func(allowauth_func_t func
)
1807 if (allowauth_func_used
== allowauth_func_size
) {
1808 if (allowauth_func_size
) {
1809 allowauth_func_size
<<= 1;
1810 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
1812 allowauth_func_size
= 8;
1813 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
1816 allowauth_func_list
[allowauth_func_used
++] = func
;
1819 static NICKSERV_FUNC(cmd_allowauth
)
1821 struct userNode
*target
;
1822 struct handle_info
*hi
;
1825 NICKSERV_MIN_PARMS(2);
1826 if (!(target
= GetUserH(argv
[1]))) {
1827 reply("MSG_NICK_UNKNOWN", argv
[1]);
1830 if (target
->handle_info
) {
1831 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
1834 if (IsStamped(target
)) {
1835 /* Unauthenticated users might still have been stamped
1836 previously and could therefore have a hidden host;
1837 do not allow them to authenticate to an account. */
1838 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
1843 else if (!(hi
= get_handle_info(argv
[2]))) {
1844 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
1848 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
1849 reply("MSG_USER_OUTRANKED", hi
->handle
);
1852 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
1853 || (hi
->opserv_level
> 0))
1854 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
1855 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
1858 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
1859 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
1860 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
1861 if (nickserv_conf
.email_enabled
)
1862 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
1864 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
1865 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
1867 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
1869 for (n
=0; n
<allowauth_func_used
; n
++)
1870 allowauth_func_list
[n
](user
, target
, hi
);
1874 static NICKSERV_FUNC(cmd_authcookie
)
1876 struct handle_info
*hi
;
1878 NICKSERV_MIN_PARMS(2);
1879 if (user
->handle_info
) {
1880 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1883 if (IsStamped(user
)) {
1884 /* Unauthenticated users might still have been stamped
1885 previously and could therefore have a hidden host;
1886 do not allow them to authenticate to an account. */
1887 reply("NSMSG_STAMPED_AUTHCOOKIE");
1890 if (!(hi
= get_handle_info(argv
[1]))) {
1891 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1894 if (!hi
->email_addr
) {
1895 reply("MSG_SET_EMAIL_ADDR");
1898 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
1902 static NICKSERV_FUNC(cmd_delcookie
)
1904 struct handle_info
*hi
;
1906 hi
= user
->handle_info
;
1908 reply("NSMSG_NO_COOKIE");
1911 switch (hi
->cookie
->type
) {
1914 reply("NSMSG_MUST_TIME_OUT");
1917 nickserv_eat_cookie(hi
->cookie
);
1918 reply("NSMSG_ATE_COOKIE");
1924 static NICKSERV_FUNC(cmd_odelcookie
)
1926 struct handle_info
*hi
;
1928 NICKSERV_MIN_PARMS(2);
1930 if (!(hi
= get_victim_oper(user
, argv
[1])))
1934 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
1938 nickserv_eat_cookie(hi
->cookie
);
1939 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
1944 static NICKSERV_FUNC(cmd_resetpass
)
1946 struct handle_info
*hi
;
1947 char crypted
[MD5_CRYPT_LENGTH
];
1950 NICKSERV_MIN_PARMS(3);
1951 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
1955 if (user
->handle_info
) {
1956 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1959 if (IsStamped(user
)) {
1960 /* Unauthenticated users might still have been stamped
1961 previously and could therefore have a hidden host;
1962 do not allow them to activate an account. */
1963 reply("NSMSG_STAMPED_RESETPASS");
1966 if (!(hi
= get_handle_info(argv
[1]))) {
1967 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1970 if (!hi
->email_addr
) {
1971 reply("MSG_SET_EMAIL_ADDR");
1974 cryptpass(argv
[2], crypted
);
1976 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
1980 static NICKSERV_FUNC(cmd_cookie
)
1982 struct handle_info
*hi
;
1985 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
1988 NICKSERV_MIN_PARMS(3);
1989 if (!(hi
= get_handle_info(argv
[1]))) {
1990 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1996 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1997 reply("NSMSG_HANDLE_SUSPENDED");
2002 reply("NSMSG_NO_COOKIE");
2006 /* Check validity of operation before comparing cookie to
2007 * prohibit guessing by authed users. */
2008 if (user
->handle_info
2009 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2010 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2011 reply("NSMSG_CANNOT_COOKIE");
2015 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2016 reply("NSMSG_BAD_COOKIE");
2020 switch (hi
->cookie
->type
) {
2022 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2023 set_user_handle_info(user
, hi
, 1);
2024 reply("NSMSG_HANDLE_ACTIVATED");
2025 if (nickserv_conf
.sync_log
)
2026 SyncLog("ACCOUNTACC %s", hi
->handle
);
2028 case PASSWORD_CHANGE
:
2029 set_user_handle_info(user
, hi
, 1);
2030 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2031 reply("NSMSG_PASSWORD_CHANGED");
2032 if (nickserv_conf
.sync_log
)
2033 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2036 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2038 * This should only happen if an OREGISTER was sent. Require
2039 * email must be enabled! - SiRVulcaN
2041 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2043 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2044 reply("NSMSG_EMAIL_CHANGED");
2045 if (nickserv_conf
.sync_log
)
2046 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2049 set_user_handle_info(user
, hi
, 1);
2050 reply("NSMSG_AUTH_SUCCESS");
2053 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2054 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2058 nickserv_eat_cookie(hi
->cookie
);
2063 static NICKSERV_FUNC(cmd_oregnick
) {
2065 struct handle_info
*target
;
2066 struct nick_info
*ni
;
2068 NICKSERV_MIN_PARMS(3);
2069 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2072 if (!is_registerable_nick(nick
)) {
2073 reply("NSMSG_BAD_NICK", nick
);
2076 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2078 reply("NSMSG_NICK_EXISTS", nick
);
2081 register_nick(nick
, target
);
2082 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2086 static NICKSERV_FUNC(cmd_regnick
) {
2088 struct nick_info
*ni
;
2090 if (!is_registerable_nick(user
->nick
)) {
2091 reply("NSMSG_BAD_NICK", user
->nick
);
2094 /* count their nicks, see if it's too many */
2095 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2096 if (n
>= nickserv_conf
.nicks_per_handle
) {
2097 reply("NSMSG_TOO_MANY_NICKS");
2100 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2102 reply("NSMSG_NICK_EXISTS", user
->nick
);
2105 register_nick(user
->nick
, user
->handle_info
);
2106 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2110 static NICKSERV_FUNC(cmd_pass
)
2112 struct handle_info
*hi
;
2113 const char *old_pass
, *new_pass
;
2115 NICKSERV_MIN_PARMS(3);
2116 hi
= user
->handle_info
;
2120 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2121 if (!checkpass(old_pass
, hi
->passwd
)) {
2122 argv
[1] = "BADPASS";
2123 reply("NSMSG_PASSWORD_INVALID");
2126 cryptpass(new_pass
, hi
->passwd
);
2127 if (nickserv_conf
.sync_log
)
2128 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2130 reply("NSMSG_PASS_SUCCESS");
2135 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2138 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2139 for (i
=0; i
<hi
->masks
->used
; i
++) {
2140 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2141 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2146 string_list_append(hi
->masks
, new_mask
);
2147 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2151 static NICKSERV_FUNC(cmd_addmask
)
2154 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2155 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2159 if (!is_gline(argv
[1])) {
2160 reply("NSMSG_MASK_INVALID", argv
[1]);
2163 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2167 static NICKSERV_FUNC(cmd_oaddmask
)
2169 struct handle_info
*hi
;
2171 NICKSERV_MIN_PARMS(3);
2172 if (!(hi
= get_victim_oper(user
, argv
[1])))
2174 return nickserv_addmask(user
, hi
, argv
[2]);
2178 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2181 for (i
=0; i
<hi
->masks
->used
; i
++) {
2182 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2183 char *old_mask
= hi
->masks
->list
[i
];
2184 if (hi
->masks
->used
== 1) {
2185 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2188 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2189 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2194 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2198 static NICKSERV_FUNC(cmd_delmask
)
2200 NICKSERV_MIN_PARMS(2);
2201 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2204 static NICKSERV_FUNC(cmd_odelmask
)
2206 struct handle_info
*hi
;
2207 NICKSERV_MIN_PARMS(3);
2208 if (!(hi
= get_victim_oper(user
, argv
[1])))
2210 return nickserv_delmask(user
, hi
, argv
[2]);
2214 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2215 unsigned int nn
, add
= 1, pos
;
2216 unsigned long added
, removed
, flag
;
2218 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2220 case '+': add
= 1; break;
2221 case '-': add
= 0; break;
2223 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2224 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2227 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2228 /* cheesy avoidance of looking up the flag name.. */
2229 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2232 flag
= 1 << (pos
- 1);
2234 added
|= flag
, removed
&= ~flag
;
2236 removed
|= flag
, added
&= ~flag
;
2241 *premoved
= removed
;
2246 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2248 unsigned long before
, after
, added
, removed
;
2249 struct userNode
*uNode
;
2251 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2252 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2254 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2255 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2257 /* Strip helping flag if they're only a support helper and not
2258 * currently in #support. */
2259 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2260 struct channelList
*schannels
;
2262 schannels
= chanserv_support_channels();
2263 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2264 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2265 if (GetUserMode(schannels
->list
[ii
], uNode
))
2267 if (ii
< schannels
->used
)
2271 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2274 if (after
&& !before
) {
2275 /* Add user to current helper list. */
2276 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2277 userList_append(&curr_helpers
, uNode
);
2278 } else if (!after
&& before
) {
2279 /* Remove user from current helper list. */
2280 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2281 userList_remove(&curr_helpers
, uNode
);
2288 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2292 char *set_display
[] = {
2293 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", /* "STYLE", */
2294 "EMAIL", "ANNOUNCEMENTS", "MAXLOGINS", "LANGUAGE",
2295 "FAKEHOST", "TITLE", "EPITHET"
2298 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2299 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_HEADER");
2301 /* Do this so options are presented in a consistent order. */
2302 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2303 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2304 opt(user
, hi
, override
, 0, NULL
);
2305 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_END");
2308 static NICKSERV_FUNC(cmd_set
)
2310 struct handle_info
*hi
;
2313 hi
= user
->handle_info
;
2315 set_list(user
, hi
, 0);
2318 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2319 reply("NSMSG_INVALID_OPTION", argv
[1]);
2322 return opt(user
, hi
, 0, argc
-1, argv
+1);
2325 static NICKSERV_FUNC(cmd_oset
)
2327 struct handle_info
*hi
;
2330 NICKSERV_MIN_PARMS(2);
2332 if (!(hi
= get_victim_oper(user
, argv
[1])))
2336 set_list(user
, hi
, 0);
2340 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2341 reply("NSMSG_INVALID_OPTION", argv
[2]);
2345 return opt(user
, hi
, 1, argc
-2, argv
+2);
2348 static OPTION_FUNC(opt_info
)
2352 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2354 hi
->infoline
= NULL
;
2356 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2360 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2361 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2365 static OPTION_FUNC(opt_width
)
2368 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2370 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2371 hi
->screen_width
= MIN_LINE_SIZE
;
2372 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2373 hi
->screen_width
= MAX_LINE_SIZE
;
2375 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2379 static OPTION_FUNC(opt_tablewidth
)
2382 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2384 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2385 hi
->table_width
= MIN_LINE_SIZE
;
2386 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2387 hi
->table_width
= MAX_LINE_SIZE
;
2389 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2393 static OPTION_FUNC(opt_color
)
2396 if (enabled_string(argv
[1]))
2397 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2398 else if (disabled_string(argv
[1]))
2399 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2401 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2406 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2410 static OPTION_FUNC(opt_privmsg
)
2413 if (enabled_string(argv
[1]))
2414 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2415 else if (disabled_string(argv
[1]))
2416 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2418 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2423 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2428 static OPTION_FUNC(opt_style)
2433 if (!irccasecmp(argv[1], "Zoot"))
2434 hi->userlist_style = HI_STYLE_ZOOT;
2435 else if (!irccasecmp(argv[1], "def"))
2436 hi->userlist_style = HI_STYLE_DEF;
2439 switch (hi->userlist_style) {
2448 send_message(user, nickserv, "NSMSG_SET_STYLE", style);
2453 static OPTION_FUNC(opt_announcements
)
2458 if (enabled_string(argv
[1]))
2459 hi
->announcements
= 'y';
2460 else if (disabled_string(argv
[1]))
2461 hi
->announcements
= 'n';
2462 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2463 hi
->announcements
= '?';
2465 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2470 switch (hi
->announcements
) {
2471 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2472 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2473 case '?': choice
= "default"; break;
2474 default: choice
= "unknown"; break;
2476 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2480 static OPTION_FUNC(opt_password
)
2483 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2488 cryptpass(argv
[1], hi
->passwd
);
2490 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2494 static OPTION_FUNC(opt_flags
)
2497 unsigned int ii
, flen
;
2500 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2505 nickserv_apply_flags(user
, hi
, argv
[1]);
2507 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2508 if (hi
->flags
& (1 << ii
))
2509 flags
[flen
++] = handle_flags
[ii
];
2512 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2514 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2518 static OPTION_FUNC(opt_email
)
2522 if (!is_valid_email_addr(argv
[1])) {
2523 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2526 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2527 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2530 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2531 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2533 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2535 nickserv_set_email_addr(hi
, argv
[1]);
2537 nickserv_eat_cookie(hi
->cookie
);
2538 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2541 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2545 static OPTION_FUNC(opt_maxlogins
)
2547 unsigned char maxlogins
;
2549 maxlogins
= strtoul(argv
[1], NULL
, 0);
2550 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2551 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2554 hi
->maxlogins
= maxlogins
;
2556 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2557 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2561 static OPTION_FUNC(opt_language
)
2563 struct language
*lang
;
2565 lang
= language_find(argv
[1]);
2566 if (irccasecmp(lang
->name
, argv
[1]))
2567 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2568 hi
->language
= lang
;
2570 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2575 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2576 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2578 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2579 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2580 && (user
->handle_info
->opserv_level
< 1000))) {
2581 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2584 if ((user
->handle_info
->opserv_level
< new_level
)
2585 || ((user
->handle_info
->opserv_level
== new_level
)
2586 && (user
->handle_info
->opserv_level
< 1000))) {
2587 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2590 if (user
->handle_info
== target
) {
2591 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2594 if (target
->opserv_level
== new_level
)
2596 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2597 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2598 target
->opserv_level
= new_level
;
2602 static OPTION_FUNC(opt_level
)
2607 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2611 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2612 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2616 static OPTION_FUNC(opt_epithet
)
2618 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2621 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2625 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2629 if ((epithet
[0] == '*') && !epithet
[1])
2632 hi
->epithet
= strdup(epithet
);
2636 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2638 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2642 static OPTION_FUNC(opt_title
)
2646 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2648 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2653 if (strchr(title
, '.')) {
2654 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2657 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2658 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2659 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2664 if (!strcmp(title
, "*")) {
2665 hi
->fakehost
= NULL
;
2667 hi
->fakehost
= malloc(strlen(title
)+2);
2668 hi
->fakehost
[0] = '.';
2669 strcpy(hi
->fakehost
+1, title
);
2672 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2673 title
= hi
->fakehost
+ 1;
2677 title
= user_find_message(user
, "MSG_NONE");
2678 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2682 static OPTION_FUNC(opt_fakehost
)
2686 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2688 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2693 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
2694 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
2698 if (!strcmp(fake
, "*"))
2699 hi
->fakehost
= NULL
;
2701 hi
->fakehost
= strdup(fake
);
2702 fake
= hi
->fakehost
;
2705 fake
= generate_fakehost(hi
);
2707 fake
= user_find_message(user
, "MSG_NONE");
2708 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
2712 static NICKSERV_FUNC(cmd_reclaim
)
2714 struct handle_info
*hi
;
2715 struct nick_info
*ni
;
2716 struct userNode
*victim
;
2718 NICKSERV_MIN_PARMS(2);
2719 hi
= user
->handle_info
;
2720 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
2722 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
2725 if (ni
->owner
!= user
->handle_info
) {
2726 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
2729 victim
= GetUserH(ni
->nick
);
2731 reply("MSG_NICK_UNKNOWN", ni
->nick
);
2734 if (victim
== user
) {
2735 reply("NSMSG_NICK_USER_YOU");
2738 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
2739 switch (nickserv_conf
.reclaim_action
) {
2740 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
2741 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
2742 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
2743 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
2748 static NICKSERV_FUNC(cmd_unregnick
)
2751 struct handle_info
*hi
;
2752 struct nick_info
*ni
;
2754 hi
= user
->handle_info
;
2755 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
2756 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2758 reply("NSMSG_UNKNOWN_NICK", nick
);
2761 if (hi
!= ni
->owner
) {
2762 reply("NSMSG_NOT_YOUR_NICK", nick
);
2765 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2770 static NICKSERV_FUNC(cmd_ounregnick
)
2772 struct nick_info
*ni
;
2774 NICKSERV_MIN_PARMS(2);
2775 if (!(ni
= get_nick_info(argv
[1]))) {
2776 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
2779 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
2780 reply("MSG_USER_OUTRANKED", ni
->nick
);
2783 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2788 static NICKSERV_FUNC(cmd_unregister
)
2790 struct handle_info
*hi
;
2793 NICKSERV_MIN_PARMS(2);
2794 hi
= user
->handle_info
;
2797 if (checkpass(passwd
, hi
->passwd
)) {
2798 nickserv_unregister_handle(hi
, user
);
2801 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
2802 reply("NSMSG_PASSWORD_INVALID");
2807 static NICKSERV_FUNC(cmd_ounregister
)
2809 struct handle_info
*hi
;
2811 NICKSERV_MIN_PARMS(2);
2812 if (!(hi
= get_victim_oper(user
, argv
[1])))
2814 nickserv_unregister_handle(hi
, user
);
2818 static NICKSERV_FUNC(cmd_status
)
2820 if (nickserv_conf
.disable_nicks
) {
2821 reply("NSMSG_GLOBAL_STATS_NONICK",
2822 dict_size(nickserv_handle_dict
));
2824 if (user
->handle_info
) {
2826 struct nick_info
*ni
;
2827 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
2828 reply("NSMSG_HANDLE_STATS", cnt
);
2830 reply("NSMSG_HANDLE_NONE");
2832 reply("NSMSG_GLOBAL_STATS",
2833 dict_size(nickserv_handle_dict
),
2834 dict_size(nickserv_nick_dict
));
2839 static NICKSERV_FUNC(cmd_ghost
)
2841 struct userNode
*target
;
2842 char reason
[MAXLEN
];
2844 NICKSERV_MIN_PARMS(2);
2845 if (!(target
= GetUserH(argv
[1]))) {
2846 reply("MSG_NICK_UNKNOWN", argv
[1]);
2849 if (target
== user
) {
2850 reply("NSMSG_CANNOT_GHOST_SELF");
2853 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
2854 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
2857 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
2858 DelUser(target
, nickserv
, 1, reason
);
2859 reply("NSMSG_GHOST_KILLED", argv
[1]);
2863 static NICKSERV_FUNC(cmd_vacation
)
2865 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
2866 reply("NSMSG_ON_VACATION");
2871 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
2873 struct handle_info
*hi
;
2876 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
2878 #ifdef WITH_PROTOCOL_BAHAMUT
2881 saxdb_start_record(ctx
, iter_key(it
), 0);
2882 if (hi
->announcements
!= '?') {
2883 flags
[0] = hi
->announcements
;
2885 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
2888 struct handle_cookie
*cookie
= hi
->cookie
;
2891 switch (cookie
->type
) {
2892 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
2893 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
2894 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
2895 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
2896 default: type
= NULL
; break;
2899 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
2900 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
2901 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
2903 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
2904 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
2905 saxdb_end_record(ctx
);
2909 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
2911 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
2913 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
2917 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
2918 if (hi
->flags
& (1 << ii
))
2919 flags
[flen
++] = handle_flags
[ii
];
2921 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
2923 #ifdef WITH_PROTOCOL_BAHAMUT
2924 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
2927 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
2928 if (hi
->last_quit_host
[0])
2929 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
2930 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
2931 if (hi
->masks
->used
)
2932 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
2934 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
2936 struct string_list
*slist
;
2937 struct nick_info
*ni
;
2939 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
2940 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
2941 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
2945 if (hi
->opserv_level
)
2946 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
2947 if (hi
->language
!= lang_C
)
2948 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
2949 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
2950 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
2951 if (hi
->screen_width
)
2952 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
2953 if (hi
->table_width
)
2954 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
2955 flags
[0] = hi
->userlist_style
;
2957 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
2958 saxdb_end_record(ctx
);
2963 static handle_merge_func_t
*handle_merge_func_list
;
2964 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
2967 reg_handle_merge_func(handle_merge_func_t func
)
2969 if (handle_merge_func_used
== handle_merge_func_size
) {
2970 if (handle_merge_func_size
) {
2971 handle_merge_func_size
<<= 1;
2972 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
2974 handle_merge_func_size
= 8;
2975 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
2978 handle_merge_func_list
[handle_merge_func_used
++] = func
;
2981 static NICKSERV_FUNC(cmd_merge
)
2983 struct handle_info
*hi_from
, *hi_to
;
2984 struct userNode
*last_user
;
2985 struct userData
*cList
, *cListNext
;
2986 unsigned int ii
, jj
, n
;
2987 char buffer
[MAXLEN
];
2989 NICKSERV_MIN_PARMS(3);
2991 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
2993 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
2995 if (hi_to
== hi_from
) {
2996 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3000 for (n
=0; n
<handle_merge_func_used
; n
++)
3001 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3003 /* Append "from" handle's nicks to "to" handle's nick list. */
3005 struct nick_info
*last_ni
;
3006 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3007 last_ni
->next
= hi_from
->nicks
;
3009 while (hi_from
->nicks
) {
3010 hi_from
->nicks
->owner
= hi_to
;
3011 hi_from
->nicks
= hi_from
->nicks
->next
;
3014 /* Merge the hostmasks. */
3015 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3016 char *mask
= hi_from
->masks
->list
[ii
];
3017 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3018 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3020 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3021 string_list_append(hi_to
->masks
, strdup(mask
));
3024 /* Merge the lists of authed users. */
3026 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3027 last_user
->next_authed
= hi_from
->users
;
3029 hi_to
->users
= hi_from
->users
;
3031 /* Repoint the old "from" handle's users. */
3032 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3033 last_user
->handle_info
= hi_to
;
3035 hi_from
->users
= NULL
;
3037 /* Merge channel userlists. */
3038 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3039 struct userData
*cList2
;
3040 cListNext
= cList
->u_next
;
3041 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3042 if (cList
->channel
== cList2
->channel
)
3044 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3045 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
);
3046 /* keep cList2 in hi_to; remove cList from hi_from */
3047 del_channel_user(cList
, 1);
3050 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
);
3051 /* remove the lower-ranking cList2 from hi_to */
3052 del_channel_user(cList2
, 1);
3054 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3056 /* cList needs to be moved from hi_from to hi_to */
3057 cList
->handle
= hi_to
;
3058 /* Remove from linked list for hi_from */
3059 assert(!cList
->u_prev
);
3060 hi_from
->channels
= cList
->u_next
;
3062 cList
->u_next
->u_prev
= cList
->u_prev
;
3063 /* Add to linked list for hi_to */
3064 cList
->u_prev
= NULL
;
3065 cList
->u_next
= hi_to
->channels
;
3066 if (hi_to
->channels
)
3067 hi_to
->channels
->u_prev
= cList
;
3068 hi_to
->channels
= cList
;
3072 /* Do they get an OpServ level promotion? */
3073 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3074 hi_to
->opserv_level
= hi_from
->opserv_level
;
3076 /* What about last seen time? */
3077 if (hi_from
->lastseen
> hi_to
->lastseen
)
3078 hi_to
->lastseen
= hi_from
->lastseen
;
3080 /* Does a fakehost carry over? (This intentionally doesn't set it
3081 * for users previously attached to hi_to. They'll just have to
3084 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3085 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3087 /* Notify of success. */
3088 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3089 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3090 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3092 /* Unregister the "from" handle. */
3093 nickserv_unregister_handle(hi_from
, NULL
);
3098 struct nickserv_discrim
{
3099 unsigned int limit
, min_level
, max_level
;
3100 unsigned long flags_on
, flags_off
;
3101 time_t min_registered
, max_registered
;
3103 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3104 const char *nickmask
;
3105 const char *hostmask
;
3106 const char *handlemask
;
3107 const char *emailmask
;
3110 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3112 struct discrim_apply_info
{
3113 struct nickserv_discrim
*discrim
;
3114 discrim_search_func func
;
3115 struct userNode
*source
;
3116 unsigned int matched
;
3119 static struct nickserv_discrim
*
3120 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3123 struct nickserv_discrim
*discrim
;
3125 discrim
= malloc(sizeof(*discrim
));
3126 memset(discrim
, 0, sizeof(*discrim
));
3127 discrim
->min_level
= 0;
3128 discrim
->max_level
= ~0;
3129 discrim
->limit
= 50;
3130 discrim
->min_registered
= 0;
3131 discrim
->max_registered
= INT_MAX
;
3132 discrim
->lastseen
= now
;
3134 for (i
=0; i
<argc
; i
++) {
3135 if (i
== argc
- 1) {
3136 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3139 if (!irccasecmp(argv
[i
], "limit")) {
3140 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3141 } else if (!irccasecmp(argv
[i
], "flags")) {
3142 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3143 } else if (!irccasecmp(argv
[i
], "registered")) {
3144 const char *cmp
= argv
[++i
];
3145 if (cmp
[0] == '<') {
3146 if (cmp
[1] == '=') {
3147 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3149 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3151 } else if (cmp
[0] == '=') {
3152 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3153 } else if (cmp
[0] == '>') {
3154 if (cmp
[1] == '=') {
3155 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3157 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3160 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3162 } else if (!irccasecmp(argv
[i
], "seen")) {
3163 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3164 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3165 discrim
->nickmask
= argv
[++i
];
3166 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3168 if (!irccasecmp(argv
[i
], "exact")) {
3169 if (i
== argc
- 1) {
3170 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3173 discrim
->hostmask_type
= EXACT
;
3174 } else if (!irccasecmp(argv
[i
], "subset")) {
3175 if (i
== argc
- 1) {
3176 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3179 discrim
->hostmask_type
= SUBSET
;
3180 } else if (!irccasecmp(argv
[i
], "superset")) {
3181 if (i
== argc
- 1) {
3182 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3185 discrim
->hostmask_type
= SUPERSET
;
3186 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3187 if (i
== argc
- 1) {
3188 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3191 discrim
->hostmask_type
= LASTQUIT
;
3194 discrim
->hostmask_type
= SUPERSET
;
3196 discrim
->hostmask
= argv
[++i
];
3197 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3198 if (!irccasecmp(argv
[++i
], "*")) {
3199 discrim
->handlemask
= 0;
3201 discrim
->handlemask
= argv
[i
];
3203 } else if (!irccasecmp(argv
[i
], "email")) {
3204 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3205 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3207 } else if (!irccasecmp(argv
[++i
], "*")) {
3208 discrim
->emailmask
= 0;
3210 discrim
->emailmask
= argv
[i
];
3212 } else if (!irccasecmp(argv
[i
], "access")) {
3213 const char *cmp
= argv
[++i
];
3214 if (cmp
[0] == '<') {
3215 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3216 if (cmp
[1] == '=') {
3217 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3219 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3221 } else if (cmp
[0] == '=') {
3222 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3223 } else if (cmp
[0] == '>') {
3224 if (cmp
[1] == '=') {
3225 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3227 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3230 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3233 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3244 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3246 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3247 || (discrim
->flags_off
& hi
->flags
)
3248 || (discrim
->min_registered
> hi
->registered
)
3249 || (discrim
->max_registered
< hi
->registered
)
3250 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3251 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3252 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3253 || (discrim
->min_level
> hi
->opserv_level
)
3254 || (discrim
->max_level
< hi
->opserv_level
)) {
3257 if (discrim
->hostmask
) {
3259 for (i
=0; i
<hi
->masks
->used
; i
++) {
3260 const char *mask
= hi
->masks
->list
[i
];
3261 if ((discrim
->hostmask_type
== SUBSET
)
3262 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3263 else if ((discrim
->hostmask_type
== EXACT
)
3264 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3265 else if ((discrim
->hostmask_type
== SUPERSET
)
3266 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3267 else if ((discrim
->hostmask_type
== LASTQUIT
)
3268 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3270 if (i
==hi
->masks
->used
) return 0;
3272 if (discrim
->nickmask
) {
3273 struct nick_info
*nick
= hi
->nicks
;
3275 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3278 if (!nick
) return 0;
3284 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3286 dict_iterator_t it
, next
;
3287 unsigned int matched
;
3289 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3290 it
&& (matched
< discrim
->limit
);
3292 next
= iter_next(it
);
3293 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3294 dsf(source
, iter_data(it
));
3302 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3304 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3308 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3313 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3315 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3316 nickserv_unregister_handle(match
, source
);
3320 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3322 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3323 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3324 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3325 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3326 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3330 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3332 struct handle_info_list hil
;
3333 struct helpfile_table tbl
;
3338 memset(&hil
, 0, sizeof(hil
));
3339 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3340 struct handle_info
*hi
= iter_data(it
);
3341 if (hi
->opserv_level
)
3342 handle_info_list_append(&hil
, hi
);
3344 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3345 tbl
.length
= hil
.used
+ 1;
3347 tbl
.flags
= TABLE_NO_FREE
;
3348 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3349 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3352 for (ii
= 0; ii
< hil
.used
; ) {
3353 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3354 ary
[0] = hil
.list
[ii
]->handle
;
3355 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3356 tbl
.contents
[++ii
] = ary
;
3358 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3359 reply("MSG_MATCH_COUNT", hil
.used
);
3360 for (ii
= 0; ii
< hil
.used
; ii
++)
3361 free(tbl
.contents
[ii
]);
3366 static NICKSERV_FUNC(cmd_search
)
3368 struct nickserv_discrim
*discrim
;
3369 discrim_search_func action
;
3370 struct svccmd
*subcmd
;
3371 unsigned int matches
;
3374 NICKSERV_MIN_PARMS(3);
3375 sprintf(buf
, "search %s", argv
[1]);
3376 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3377 if (!irccasecmp(argv
[1], "print"))
3378 action
= search_print_func
;
3379 else if (!irccasecmp(argv
[1], "count"))
3380 action
= search_count_func
;
3381 else if (!irccasecmp(argv
[1], "unregister"))
3382 action
= search_unregister_func
;
3384 reply("NSMSG_INVALID_ACTION", argv
[1]);
3388 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3391 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3395 if (action
== search_print_func
)
3396 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3397 else if (action
== search_count_func
)
3398 discrim
->limit
= INT_MAX
;
3400 matches
= nickserv_discrim_search(discrim
, action
, user
);
3403 reply("MSG_MATCH_COUNT", matches
);
3405 reply("MSG_NO_MATCHES");
3411 static MODCMD_FUNC(cmd_checkpass
)
3413 struct handle_info
*hi
;
3415 NICKSERV_MIN_PARMS(3);
3416 if (!(hi
= get_handle_info(argv
[1]))) {
3417 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3420 if (checkpass(argv
[2], hi
->passwd
))
3421 reply("CHECKPASS_YES");
3423 reply("CHECKPASS_NO");
3429 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3432 struct string_list
*masks
, *slist
;
3433 struct handle_info
*hi
;
3434 struct userNode
*authed_users
;
3435 unsigned long int id
;
3439 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3440 id
= str
? strtoul(str
, NULL
, 0) : 0;
3441 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3443 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3446 if ((hi
= get_handle_info(handle
))) {
3447 authed_users
= hi
->users
;
3449 dict_remove(nickserv_handle_dict
, hi
->handle
);
3451 authed_users
= NULL
;
3453 hi
= register_handle(handle
, str
, id
);
3455 hi
->users
= authed_users
;
3456 while (authed_users
) {
3457 authed_users
->handle_info
= hi
;
3458 authed_users
= authed_users
->next_authed
;
3461 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3462 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3463 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3464 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3465 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3466 hi
->language
= language_find(str
? str
: "C");
3467 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3468 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3469 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3471 hi
->infoline
= strdup(str
);
3472 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3473 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3474 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3475 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3476 /* We want to read the nicks even if disable_nicks is set. This is so
3477 * that we don't lose the nick data entirely. */
3478 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3480 for (ii
=0; ii
<slist
->used
; ii
++)
3481 register_nick(slist
->list
[ii
], hi
);
3483 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3485 for (ii
=0; str
[ii
]; ii
++)
3486 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3488 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3489 hi
->userlist_style
= str
? str
[0] : HI_STYLE_ZOOT
;
3490 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3491 hi
->announcements
= str
? str
[0] : '?';
3492 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3493 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3494 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3495 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3496 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3498 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3500 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3501 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3503 nickserv_set_email_addr(hi
, str
);
3504 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3506 hi
->epithet
= strdup(str
);
3507 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3509 hi
->fakehost
= strdup(str
);
3510 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3512 const char *data
, *type
, *expires
, *cookie_str
;
3513 struct handle_cookie
*cookie
;
3515 cookie
= calloc(1, sizeof(*cookie
));
3516 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3517 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3518 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3519 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3520 if (!type
|| !expires
|| !cookie_str
) {
3521 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3524 if (!irccasecmp(type
, KEY_ACTIVATION
))
3525 cookie
->type
= ACTIVATION
;
3526 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3527 cookie
->type
= PASSWORD_CHANGE
;
3528 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3529 cookie
->type
= EMAIL_CHANGE
;
3530 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3531 cookie
->type
= ALLOWAUTH
;
3533 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3536 cookie
->expires
= strtoul(expires
, NULL
, 0);
3537 if (cookie
->expires
< now
)
3540 cookie
->data
= strdup(data
);
3541 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3545 nickserv_bake_cookie(cookie
);
3547 nickserv_free_cookie(cookie
);
3552 nickserv_saxdb_read(dict_t db
) {
3554 struct record_data
*rd
;
3556 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3558 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3563 static NICKSERV_FUNC(cmd_mergedb
)
3565 struct timeval start
, stop
;
3568 NICKSERV_MIN_PARMS(2);
3569 gettimeofday(&start
, NULL
);
3570 if (!(db
= parse_database(argv
[1]))) {
3571 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3574 nickserv_saxdb_read(db
);
3576 gettimeofday(&stop
, NULL
);
3577 stop
.tv_sec
-= start
.tv_sec
;
3578 stop
.tv_usec
-= start
.tv_usec
;
3579 if (stop
.tv_usec
< 0) {
3581 stop
.tv_usec
+= 1000000;
3583 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3588 expire_handles(UNUSED_ARG(void *data
))
3590 dict_iterator_t it
, next
;
3592 struct handle_info
*hi
;
3594 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3595 next
= iter_next(it
);
3597 if ((hi
->opserv_level
> 0)
3599 || HANDLE_FLAGGED(hi
, FROZEN
)
3600 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3603 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3604 if ((now
- hi
->lastseen
) > expiry
) {
3605 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3606 nickserv_unregister_handle(hi
, NULL
);
3610 if (nickserv_conf
.handle_expire_frequency
)
3611 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3615 nickserv_load_dict(const char *fname
)
3619 if (!(file
= fopen(fname
, "r"))) {
3620 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
3623 while (!feof(file
)) {
3624 fgets(line
, sizeof(line
), file
);
3627 if (line
[strlen(line
)-1] == '\n')
3628 line
[strlen(line
)-1] = 0;
3629 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
3632 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
3635 static enum reclaim_action
3636 reclaim_action_from_string(const char *str
) {
3638 return RECLAIM_NONE
;
3639 else if (!irccasecmp(str
, "warn"))
3640 return RECLAIM_WARN
;
3641 else if (!irccasecmp(str
, "svsnick"))
3642 return RECLAIM_SVSNICK
;
3643 else if (!irccasecmp(str
, "kill"))
3644 return RECLAIM_KILL
;
3646 return RECLAIM_NONE
;
3650 nickserv_conf_read(void)
3652 dict_t conf_node
, child
;
3656 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
3657 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
3660 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
3662 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
3663 if (nickserv_conf
.valid_handle_regex_set
)
3664 regfree(&nickserv_conf
.valid_handle_regex
);
3666 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3667 nickserv_conf
.valid_handle_regex_set
= !err
;
3668 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
3670 nickserv_conf
.valid_handle_regex_set
= 0;
3672 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
3673 if (nickserv_conf
.valid_nick_regex_set
)
3674 regfree(&nickserv_conf
.valid_nick_regex
);
3676 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3677 nickserv_conf
.valid_nick_regex_set
= !err
;
3678 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
3680 nickserv_conf
.valid_nick_regex_set
= 0;
3682 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
3684 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
3685 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
3686 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
3687 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
3688 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
3689 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
3690 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
3691 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
3692 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
3693 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
3694 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
3695 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
3696 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
3697 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
3698 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
3699 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
3700 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
3701 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
3702 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
3703 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
3704 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
3705 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
3706 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
3707 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
3708 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
3710 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
3711 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
3712 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3714 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3715 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
3716 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3718 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3719 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
3720 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
3721 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
3722 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
3723 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
3724 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
3725 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
3726 if (!nickserv_conf
.disable_nicks
) {
3727 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
3728 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3729 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
3730 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
3731 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
3732 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3733 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
3734 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
3736 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
3737 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
3738 const char *key
= iter_key(it
), *value
;
3742 if (!strncasecmp(key
, "uc_", 3))
3743 flag
= toupper(key
[3]);
3744 else if (!strncasecmp(key
, "lc_", 3))
3745 flag
= tolower(key
[3]);
3749 if ((pos
= handle_inverse_flags
[flag
])) {
3750 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
3751 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
3754 if (nickserv_conf
.weak_password_dict
)
3755 dict_delete(nickserv_conf
.weak_password_dict
);
3756 nickserv_conf
.weak_password_dict
= dict_new();
3757 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
3758 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
3759 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
3760 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
3762 nickserv_load_dict(str
);
3763 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
3764 if (nickserv
&& str
)
3765 NickChange(nickserv
, str
, 0);
3766 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
3767 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
3768 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
3769 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
3770 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
3771 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
3772 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
3773 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
3774 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
3775 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
3776 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
3777 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
3778 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
3779 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
3780 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
3781 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
3782 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
3783 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
3784 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
3785 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
3786 str
= conf_get_data("server/network", RECDB_QSTRING
);
3787 nickserv_conf
.network_name
= str
? str
: "some IRC network";
3788 if (!nickserv_conf
.auth_policer_params
) {
3789 nickserv_conf
.auth_policer_params
= policer_params_new();
3790 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
3791 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
3793 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
3794 for (it
=dict_first(child
); it
; it
=iter_next(it
))
3795 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
3799 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
3801 char newnick
[NICKLEN
+1];
3810 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3812 case RECLAIM_SVSNICK
:
3814 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
3815 } while (GetUserH(newnick
));
3816 irc_svsnick(nickserv
, user
, newnick
);
3819 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
3820 irc_kill(nickserv
, user
, msg
);
3826 nickserv_reclaim_p(void *data
) {
3827 struct userNode
*user
= data
;
3828 struct nick_info
*ni
= get_nick_info(user
->nick
);
3830 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3834 check_user_nick(struct userNode
*user
) {
3835 struct nick_info
*ni
;
3836 user
->modes
&= ~FLAGS_REGNICK
;
3837 if (!(ni
= get_nick_info(user
->nick
)))
3839 if (user
->handle_info
== ni
->owner
) {
3840 user
->modes
|= FLAGS_REGNICK
;
3844 if (nickserv_conf
.warn_nick_owned
)
3845 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3846 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
3848 if (nickserv_conf
.auto_reclaim_delay
)
3849 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
3851 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3856 handle_new_user(struct userNode
*user
)
3858 return check_user_nick(user
);
3862 handle_account(struct userNode
*user
, const char *stamp
)
3864 struct handle_info
*hi
;
3867 #ifdef WITH_PROTOCOL_P10
3868 time_t timestamp
= 0;
3870 colon
= strchr(stamp
, ':');
3871 if(colon
&& colon
[1])
3874 timestamp
= atoi(colon
+1);
3876 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
3877 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
3879 log_module(MAIN_LOG
, LOG_WARNING
, "%s using account %s but timestamp does not match %lu is not %lu.", user
->nick
, stamp
, timestamp
, hi
->registered
);
3883 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
3884 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
3888 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
3891 set_user_handle_info(user
, hi
, 0);
3893 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
3898 handle_nick_change(struct userNode
*user
, const char *old_nick
)
3900 struct handle_info
*hi
;
3902 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
3903 dict_remove(nickserv_allow_auth_dict
, old_nick
);
3904 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
3906 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3907 check_user_nick(user
);
3911 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
3913 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
3914 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3915 set_user_handle_info(user
, NULL
, 0);
3918 static struct modcmd
*
3919 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
3921 if (min_level
> 0) {
3923 sprintf(buf
, "%u", min_level
);
3924 if (must_be_qualified
) {
3925 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
3927 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
3929 } else if (min_level
== 0) {
3930 if (must_be_qualified
) {
3931 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3933 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3936 if (must_be_qualified
) {
3937 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
3939 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
3945 nickserv_db_cleanup(void)
3947 unreg_del_user_func(nickserv_remove_user
);
3948 userList_clean(&curr_helpers
);
3949 policer_params_delete(nickserv_conf
.auth_policer_params
);
3950 dict_delete(nickserv_handle_dict
);
3951 dict_delete(nickserv_nick_dict
);
3952 dict_delete(nickserv_opt_dict
);
3953 dict_delete(nickserv_allow_auth_dict
);
3954 dict_delete(nickserv_email_dict
);
3955 dict_delete(nickserv_id_dict
);
3956 dict_delete(nickserv_conf
.weak_password_dict
);
3957 free(auth_func_list
);
3958 free(unreg_func_list
);
3960 free(allowauth_func_list
);
3961 free(handle_merge_func_list
);
3962 free(failpw_func_list
);
3963 if (nickserv_conf
.valid_handle_regex_set
)
3964 regfree(&nickserv_conf
.valid_handle_regex
);
3965 if (nickserv_conf
.valid_nick_regex_set
)
3966 regfree(&nickserv_conf
.valid_nick_regex
);
3970 init_nickserv(const char *nick
)
3973 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
3974 reg_new_user_func(handle_new_user
);
3975 reg_nick_change_func(handle_nick_change
);
3976 reg_del_user_func(nickserv_remove_user
);
3977 reg_account_func(handle_account
);
3979 /* set up handle_inverse_flags */
3980 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
3981 for (i
=0; handle_flags
[i
]; i
++) {
3982 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
3983 flag_access_levels
[i
] = 0;
3986 conf_register_reload(nickserv_conf_read
);
3987 nickserv_opt_dict
= dict_new();
3988 nickserv_email_dict
= dict_new();
3989 dict_set_free_keys(nickserv_email_dict
, free
);
3990 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
3992 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
3993 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
3994 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
3995 * a big pain to disable since its nolonger in the config file. ) -Rubin
3997 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
3998 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
3999 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4000 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4001 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4002 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4003 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4004 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4005 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4006 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4007 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4008 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4009 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4010 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4011 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4012 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4013 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4014 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4015 if (!nickserv_conf
.disable_nicks
) {
4016 /* nick management commands */
4017 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4018 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4019 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4020 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4021 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4022 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4024 if (nickserv_conf
.email_enabled
) {
4025 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4026 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4027 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4028 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4029 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4030 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4032 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4033 /* miscellaneous commands */
4034 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4035 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4036 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4037 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4038 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4040 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4041 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4042 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4043 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4044 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4045 /* dict_insert(nickserv_opt_dict, "STYLE", opt_style); */
4046 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4047 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4048 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4049 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4050 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4051 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4052 if (nickserv_conf
.titlehost_suffix
) {
4053 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4054 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4056 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4057 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4058 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4060 nickserv_handle_dict
= dict_new();
4061 dict_set_free_keys(nickserv_handle_dict
, free
);
4062 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4064 nickserv_id_dict
= dict_new();
4065 dict_set_free_keys(nickserv_id_dict
, free
);
4067 nickserv_nick_dict
= dict_new();
4068 dict_set_free_data(nickserv_nick_dict
, free
);
4070 nickserv_allow_auth_dict
= dict_new();
4072 userList_init(&curr_helpers
);
4075 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4076 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4077 nickserv_service
= service_register(nickserv
);
4079 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4080 reg_exit_func(nickserv_db_cleanup
);
4081 if(nickserv_conf
.handle_expire_frequency
)
4082 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4083 message_register_table(msgtab
);