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", "That email address already has an account. Use RESETPASS if you forgot your password." },
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
);
1324 /* this wont work if email is required .. */
1325 process_adduser_pending(user
);
1330 static NICKSERV_FUNC(cmd_oregister
)
1333 struct userNode
*settee
;
1334 struct handle_info
*hi
;
1336 NICKSERV_MIN_PARMS(4);
1338 if (!is_valid_handle(argv
[1])) {
1339 reply("NSMSG_BAD_HANDLE", argv
[1]);
1343 if (strchr(argv
[3], '@')) {
1344 mask
= canonicalize_hostmask(strdup(argv
[3]));
1346 settee
= GetUserH(argv
[4]);
1348 reply("MSG_NICK_UNKNOWN", argv
[4]);
1355 } else if ((settee
= GetUserH(argv
[3]))) {
1356 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1358 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1361 if (settee
&& settee
->handle_info
) {
1362 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1366 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1370 string_list_append(hi
->masks
, mask
);
1374 static NICKSERV_FUNC(cmd_handleinfo
)
1377 unsigned int i
, pos
=0, herelen
;
1378 struct userNode
*target
, *next_un
;
1379 struct handle_info
*hi
;
1380 const char *nsmsg_none
;
1383 if (!(hi
= user
->handle_info
)) {
1384 reply("NSMSG_MUST_AUTH");
1387 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1391 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1392 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1394 #ifdef WITH_PROTOCOL_BAHAMUT
1395 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1397 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1400 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1401 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1403 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1406 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1407 if (HANDLE_FLAGGED(hi
, FROZEN
))
1408 reply("NSMSG_HANDLEINFO_VACATION");
1410 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1411 struct do_not_register
*dnr
;
1412 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1413 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1414 if (!oper_outranks(user
, hi
))
1416 } else if (hi
!= user
->handle_info
) {
1417 reply("NSMSG_HANDLEINFO_END");
1421 if (nickserv_conf
.email_enabled
)
1422 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1426 switch (hi
->cookie
->type
) {
1427 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1428 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1429 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1430 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1431 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1437 unsigned long flen
= 1;
1438 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1440 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1441 if (hi
->flags
& 1 << i
)
1442 flags
[flen
++] = handle_flags
[i
];
1444 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1446 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1449 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1450 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1451 || (hi
->opserv_level
> 0)) {
1452 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1456 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1458 if (hi
->last_quit_host
[0])
1459 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1461 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1463 if (nickserv_conf
.disable_nicks
) {
1464 /* nicks disabled; don't show anything about registered nicks */
1465 } else if (hi
->nicks
) {
1466 struct nick_info
*ni
, *next_ni
;
1467 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1468 herelen
= strlen(ni
->nick
);
1469 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1471 goto print_nicks_buff
;
1475 memcpy(buff
+pos
, ni
->nick
, herelen
);
1476 pos
+= herelen
; buff
[pos
++] = ' ';
1480 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1485 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1488 if (hi
->masks
->used
) {
1489 for (i
=0; i
< hi
->masks
->used
; i
++) {
1490 herelen
= strlen(hi
->masks
->list
[i
]);
1491 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1493 goto print_mask_buff
;
1495 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1496 pos
+= herelen
; buff
[pos
++] = ' ';
1497 if (i
+1 == hi
->masks
->used
) {
1500 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1505 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1509 struct userData
*channel
, *next
;
1512 for (channel
= hi
->channels
; channel
; channel
= next
) {
1513 next
= channel
->u_next
;
1514 name
= channel
->channel
->channel
->name
;
1515 herelen
= strlen(name
);
1516 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1518 goto print_chans_buff
;
1520 if (IsUserSuspended(channel
))
1522 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1526 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1531 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1534 for (target
= hi
->users
; target
; target
= next_un
) {
1535 herelen
= strlen(target
->nick
);
1536 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1538 goto print_cnick_buff
;
1540 next_un
= target
->next_authed
;
1542 memcpy(buff
+pos
, target
->nick
, herelen
);
1543 pos
+= herelen
; buff
[pos
++] = ' ';
1547 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1552 reply("NSMSG_HANDLEINFO_END");
1556 static NICKSERV_FUNC(cmd_userinfo
)
1558 struct userNode
*target
;
1560 NICKSERV_MIN_PARMS(2);
1561 if (!(target
= GetUserH(argv
[1]))) {
1562 reply("MSG_NICK_UNKNOWN", argv
[1]);
1565 if (target
->handle_info
)
1566 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1568 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1572 static NICKSERV_FUNC(cmd_nickinfo
)
1574 struct nick_info
*ni
;
1576 NICKSERV_MIN_PARMS(2);
1577 if (!(ni
= get_nick_info(argv
[1]))) {
1578 reply("MSG_NICK_UNKNOWN", argv
[1]);
1581 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1585 static NICKSERV_FUNC(cmd_rename_handle
)
1587 struct handle_info
*hi
;
1588 char msgbuf
[MAXLEN
], *old_handle
;
1591 NICKSERV_MIN_PARMS(3);
1592 if (!(hi
= get_victim_oper(user
, argv
[1])))
1594 if (!is_valid_handle(argv
[2])) {
1595 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1598 if (get_handle_info(argv
[2])) {
1599 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1602 if(strlen(argv
[2]) > 15)
1604 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1608 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1609 hi
->handle
= strdup(argv
[2]);
1610 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1611 for (nn
=0; nn
<rf_list_used
; nn
++)
1612 rf_list
[nn
](hi
, old_handle
);
1613 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1614 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1615 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1620 static failpw_func_t
*failpw_func_list
;
1621 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1624 reg_failpw_func(failpw_func_t func
)
1626 if (failpw_func_used
== failpw_func_size
) {
1627 if (failpw_func_size
) {
1628 failpw_func_size
<<= 1;
1629 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1631 failpw_func_size
= 8;
1632 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1635 failpw_func_list
[failpw_func_used
++] = func
;
1639 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1641 * called by nefariouses enhanced AC login-on-connect code
1644 struct handle_info
*loc_auth(char *handle
, char *password
)
1646 int pw_arg
, used
, maxlogins
;
1649 struct handle_info
*hi
;
1650 struct userNode
*other
;
1652 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1658 /* We don't know the users hostname, or anything because they
1659 * havn't registered yet. So we can only allow LOC if your
1660 * account has *@* as a hostmask.
1662 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1664 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1673 /* Responses from here on look up the language used by the handle they asked about. */
1674 if (!checkpass(password
, hi
->passwd
)) {
1677 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1680 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1681 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1682 if (++used
>= maxlogins
) {
1689 static NICKSERV_FUNC(cmd_auth
)
1691 int pw_arg
, used
, maxlogins
;
1692 struct handle_info
*hi
;
1694 struct userNode
*other
;
1696 if (user
->handle_info
) {
1697 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1700 if (IsStamped(user
)) {
1701 /* Unauthenticated users might still have been stamped
1702 previously and could therefore have a hidden host;
1703 do not allow them to authenticate. */
1704 reply("NSMSG_STAMPED_AUTH");
1708 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1710 } else if (argc
== 2) {
1711 if (nickserv_conf
.disable_nicks
) {
1712 if (!(hi
= get_handle_info(user
->nick
))) {
1713 reply("NSMSG_HANDLE_NOT_FOUND");
1717 /* try to look up their handle from their nick */
1718 struct nick_info
*ni
;
1719 ni
= get_nick_info(user
->nick
);
1721 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1728 reply("MSG_MISSING_PARAMS", argv
[0]);
1729 svccmd_send_help_brief(user
, nickserv
, cmd
);
1733 reply("NSMSG_HANDLE_NOT_FOUND");
1736 /* Responses from here on look up the language used by the handle they asked about. */
1737 passwd
= argv
[pw_arg
];
1738 if (!valid_user_for(user
, hi
)) {
1739 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1740 send_message_type(4, user
, cmd
->parent
->bot
,
1741 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1744 send_message_type(4, user
, cmd
->parent
->bot
,
1745 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1747 argv
[pw_arg
] = "BADMASK";
1750 if (!checkpass(passwd
, hi
->passwd
)) {
1752 send_message_type(4, user
, cmd
->parent
->bot
,
1753 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1754 argv
[pw_arg
] = "BADPASS";
1755 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1756 if (nickserv_conf
.autogag_enabled
) {
1757 if (!user
->auth_policer
.params
) {
1758 user
->auth_policer
.last_req
= now
;
1759 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1761 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1763 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1764 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1765 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1767 argv
[pw_arg
] = "GAGGED";
1772 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1773 send_message_type(4, user
, cmd
->parent
->bot
,
1774 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1775 argv
[pw_arg
] = "SUSPENDED";
1778 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1779 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1780 if (++used
>= maxlogins
) {
1781 send_message_type(4, user
, cmd
->parent
->bot
,
1782 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1784 argv
[pw_arg
] = "MAXLOGINS";
1789 set_user_handle_info(user
, hi
, 1);
1790 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1791 reply("NSMSG_PLEASE_SET_EMAIL");
1792 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1793 reply("NSMSG_WEAK_PASSWORD");
1794 if (hi
->passwd
[0] != '$')
1795 cryptpass(passwd
, hi
->passwd
);
1796 reply("NSMSG_AUTH_SUCCESS");
1798 process_adduser_pending(user
);
1799 argv
[pw_arg
] = "****";
1803 static allowauth_func_t
*allowauth_func_list
;
1804 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
1807 reg_allowauth_func(allowauth_func_t func
)
1809 if (allowauth_func_used
== allowauth_func_size
) {
1810 if (allowauth_func_size
) {
1811 allowauth_func_size
<<= 1;
1812 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
1814 allowauth_func_size
= 8;
1815 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
1818 allowauth_func_list
[allowauth_func_used
++] = func
;
1821 static NICKSERV_FUNC(cmd_allowauth
)
1823 struct userNode
*target
;
1824 struct handle_info
*hi
;
1827 NICKSERV_MIN_PARMS(2);
1828 if (!(target
= GetUserH(argv
[1]))) {
1829 reply("MSG_NICK_UNKNOWN", argv
[1]);
1832 if (target
->handle_info
) {
1833 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
1836 if (IsStamped(target
)) {
1837 /* Unauthenticated users might still have been stamped
1838 previously and could therefore have a hidden host;
1839 do not allow them to authenticate to an account. */
1840 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
1845 else if (!(hi
= get_handle_info(argv
[2]))) {
1846 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
1850 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
1851 reply("MSG_USER_OUTRANKED", hi
->handle
);
1854 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
1855 || (hi
->opserv_level
> 0))
1856 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
1857 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
1860 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
1861 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
1862 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
1863 if (nickserv_conf
.email_enabled
)
1864 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
1866 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
1867 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
1869 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
1871 for (n
=0; n
<allowauth_func_used
; n
++)
1872 allowauth_func_list
[n
](user
, target
, hi
);
1876 static NICKSERV_FUNC(cmd_authcookie
)
1878 struct handle_info
*hi
;
1880 NICKSERV_MIN_PARMS(2);
1881 if (user
->handle_info
) {
1882 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1885 if (IsStamped(user
)) {
1886 /* Unauthenticated users might still have been stamped
1887 previously and could therefore have a hidden host;
1888 do not allow them to authenticate to an account. */
1889 reply("NSMSG_STAMPED_AUTHCOOKIE");
1892 if (!(hi
= get_handle_info(argv
[1]))) {
1893 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1896 if (!hi
->email_addr
) {
1897 reply("MSG_SET_EMAIL_ADDR");
1900 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
1904 static NICKSERV_FUNC(cmd_delcookie
)
1906 struct handle_info
*hi
;
1908 hi
= user
->handle_info
;
1910 reply("NSMSG_NO_COOKIE");
1913 switch (hi
->cookie
->type
) {
1916 reply("NSMSG_MUST_TIME_OUT");
1919 nickserv_eat_cookie(hi
->cookie
);
1920 reply("NSMSG_ATE_COOKIE");
1926 static NICKSERV_FUNC(cmd_odelcookie
)
1928 struct handle_info
*hi
;
1930 NICKSERV_MIN_PARMS(2);
1932 if (!(hi
= get_victim_oper(user
, argv
[1])))
1936 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
1940 nickserv_eat_cookie(hi
->cookie
);
1941 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
1946 static NICKSERV_FUNC(cmd_resetpass
)
1948 struct handle_info
*hi
;
1949 char crypted
[MD5_CRYPT_LENGTH
];
1952 NICKSERV_MIN_PARMS(3);
1953 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
1957 if (user
->handle_info
) {
1958 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1961 if (IsStamped(user
)) {
1962 /* Unauthenticated users might still have been stamped
1963 previously and could therefore have a hidden host;
1964 do not allow them to activate an account. */
1965 reply("NSMSG_STAMPED_RESETPASS");
1968 if (!(hi
= get_handle_info(argv
[1]))) {
1969 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1972 if (!hi
->email_addr
) {
1973 reply("MSG_SET_EMAIL_ADDR");
1976 cryptpass(argv
[2], crypted
);
1978 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
1982 static NICKSERV_FUNC(cmd_cookie
)
1984 struct handle_info
*hi
;
1987 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
1990 NICKSERV_MIN_PARMS(3);
1991 if (!(hi
= get_handle_info(argv
[1]))) {
1992 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1998 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1999 reply("NSMSG_HANDLE_SUSPENDED");
2004 reply("NSMSG_NO_COOKIE");
2008 /* Check validity of operation before comparing cookie to
2009 * prohibit guessing by authed users. */
2010 if (user
->handle_info
2011 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2012 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2013 reply("NSMSG_CANNOT_COOKIE");
2017 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2018 reply("NSMSG_BAD_COOKIE");
2022 switch (hi
->cookie
->type
) {
2024 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2025 set_user_handle_info(user
, hi
, 1);
2026 reply("NSMSG_HANDLE_ACTIVATED");
2027 if (nickserv_conf
.sync_log
)
2028 SyncLog("ACCOUNTACC %s", hi
->handle
);
2030 case PASSWORD_CHANGE
:
2031 set_user_handle_info(user
, hi
, 1);
2032 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2033 reply("NSMSG_PASSWORD_CHANGED");
2034 if (nickserv_conf
.sync_log
)
2035 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2038 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2040 * This should only happen if an OREGISTER was sent. Require
2041 * email must be enabled! - SiRVulcaN
2043 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2045 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2046 reply("NSMSG_EMAIL_CHANGED");
2047 if (nickserv_conf
.sync_log
)
2048 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2051 set_user_handle_info(user
, hi
, 1);
2052 reply("NSMSG_AUTH_SUCCESS");
2055 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2056 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2060 nickserv_eat_cookie(hi
->cookie
);
2062 process_adduser_pending(user
);
2067 static NICKSERV_FUNC(cmd_oregnick
) {
2069 struct handle_info
*target
;
2070 struct nick_info
*ni
;
2072 NICKSERV_MIN_PARMS(3);
2073 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2076 if (!is_registerable_nick(nick
)) {
2077 reply("NSMSG_BAD_NICK", nick
);
2080 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2082 reply("NSMSG_NICK_EXISTS", nick
);
2085 register_nick(nick
, target
);
2086 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2090 static NICKSERV_FUNC(cmd_regnick
) {
2092 struct nick_info
*ni
;
2094 if (!is_registerable_nick(user
->nick
)) {
2095 reply("NSMSG_BAD_NICK", user
->nick
);
2098 /* count their nicks, see if it's too many */
2099 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2100 if (n
>= nickserv_conf
.nicks_per_handle
) {
2101 reply("NSMSG_TOO_MANY_NICKS");
2104 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2106 reply("NSMSG_NICK_EXISTS", user
->nick
);
2109 register_nick(user
->nick
, user
->handle_info
);
2110 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2114 static NICKSERV_FUNC(cmd_pass
)
2116 struct handle_info
*hi
;
2117 const char *old_pass
, *new_pass
;
2119 NICKSERV_MIN_PARMS(3);
2120 hi
= user
->handle_info
;
2124 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2125 if (!checkpass(old_pass
, hi
->passwd
)) {
2126 argv
[1] = "BADPASS";
2127 reply("NSMSG_PASSWORD_INVALID");
2130 cryptpass(new_pass
, hi
->passwd
);
2131 if (nickserv_conf
.sync_log
)
2132 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2134 reply("NSMSG_PASS_SUCCESS");
2139 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2142 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2143 for (i
=0; i
<hi
->masks
->used
; i
++) {
2144 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2145 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2150 string_list_append(hi
->masks
, new_mask
);
2151 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2155 static NICKSERV_FUNC(cmd_addmask
)
2158 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2159 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2163 if (!is_gline(argv
[1])) {
2164 reply("NSMSG_MASK_INVALID", argv
[1]);
2167 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2171 static NICKSERV_FUNC(cmd_oaddmask
)
2173 struct handle_info
*hi
;
2175 NICKSERV_MIN_PARMS(3);
2176 if (!(hi
= get_victim_oper(user
, argv
[1])))
2178 return nickserv_addmask(user
, hi
, argv
[2]);
2182 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2185 for (i
=0; i
<hi
->masks
->used
; i
++) {
2186 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2187 char *old_mask
= hi
->masks
->list
[i
];
2188 if (hi
->masks
->used
== 1) {
2189 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2192 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2193 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2198 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2202 static NICKSERV_FUNC(cmd_delmask
)
2204 NICKSERV_MIN_PARMS(2);
2205 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2208 static NICKSERV_FUNC(cmd_odelmask
)
2210 struct handle_info
*hi
;
2211 NICKSERV_MIN_PARMS(3);
2212 if (!(hi
= get_victim_oper(user
, argv
[1])))
2214 return nickserv_delmask(user
, hi
, argv
[2]);
2218 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2219 unsigned int nn
, add
= 1, pos
;
2220 unsigned long added
, removed
, flag
;
2222 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2224 case '+': add
= 1; break;
2225 case '-': add
= 0; break;
2227 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2228 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2231 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2232 /* cheesy avoidance of looking up the flag name.. */
2233 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2236 flag
= 1 << (pos
- 1);
2238 added
|= flag
, removed
&= ~flag
;
2240 removed
|= flag
, added
&= ~flag
;
2245 *premoved
= removed
;
2250 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2252 unsigned long before
, after
, added
, removed
;
2253 struct userNode
*uNode
;
2255 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2256 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2258 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2259 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2261 /* Strip helping flag if they're only a support helper and not
2262 * currently in #support. */
2263 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2264 struct channelList
*schannels
;
2266 schannels
= chanserv_support_channels();
2267 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2268 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2269 if (GetUserMode(schannels
->list
[ii
], uNode
))
2271 if (ii
< schannels
->used
)
2275 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2278 if (after
&& !before
) {
2279 /* Add user to current helper list. */
2280 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2281 userList_append(&curr_helpers
, uNode
);
2282 } else if (!after
&& before
) {
2283 /* Remove user from current helper list. */
2284 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2285 userList_remove(&curr_helpers
, uNode
);
2292 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2296 char *set_display
[] = {
2297 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", /* "STYLE", */
2298 "EMAIL", "ANNOUNCEMENTS", "MAXLOGINS", "LANGUAGE",
2299 "FAKEHOST", "TITLE", "EPITHET"
2302 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2303 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_HEADER");
2305 /* Do this so options are presented in a consistent order. */
2306 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2307 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2308 opt(user
, hi
, override
, 0, NULL
);
2309 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_END");
2312 static NICKSERV_FUNC(cmd_set
)
2314 struct handle_info
*hi
;
2317 hi
= user
->handle_info
;
2319 set_list(user
, hi
, 0);
2322 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2323 reply("NSMSG_INVALID_OPTION", argv
[1]);
2326 return opt(user
, hi
, 0, argc
-1, argv
+1);
2329 static NICKSERV_FUNC(cmd_oset
)
2331 struct handle_info
*hi
;
2334 NICKSERV_MIN_PARMS(2);
2336 if (!(hi
= get_victim_oper(user
, argv
[1])))
2340 set_list(user
, hi
, 0);
2344 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2345 reply("NSMSG_INVALID_OPTION", argv
[2]);
2349 return opt(user
, hi
, 1, argc
-2, argv
+2);
2352 static OPTION_FUNC(opt_info
)
2356 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2358 hi
->infoline
= NULL
;
2360 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2364 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2365 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2369 static OPTION_FUNC(opt_width
)
2372 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2374 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2375 hi
->screen_width
= MIN_LINE_SIZE
;
2376 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2377 hi
->screen_width
= MAX_LINE_SIZE
;
2379 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2383 static OPTION_FUNC(opt_tablewidth
)
2386 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2388 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2389 hi
->table_width
= MIN_LINE_SIZE
;
2390 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2391 hi
->table_width
= MAX_LINE_SIZE
;
2393 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2397 static OPTION_FUNC(opt_color
)
2400 if (enabled_string(argv
[1]))
2401 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2402 else if (disabled_string(argv
[1]))
2403 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2405 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2410 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2414 static OPTION_FUNC(opt_privmsg
)
2417 if (enabled_string(argv
[1]))
2418 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2419 else if (disabled_string(argv
[1]))
2420 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2422 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2427 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2432 static OPTION_FUNC(opt_style)
2437 if (!irccasecmp(argv[1], "Zoot"))
2438 hi->userlist_style = HI_STYLE_ZOOT;
2439 else if (!irccasecmp(argv[1], "def"))
2440 hi->userlist_style = HI_STYLE_DEF;
2443 switch (hi->userlist_style) {
2452 send_message(user, nickserv, "NSMSG_SET_STYLE", style);
2457 static OPTION_FUNC(opt_announcements
)
2462 if (enabled_string(argv
[1]))
2463 hi
->announcements
= 'y';
2464 else if (disabled_string(argv
[1]))
2465 hi
->announcements
= 'n';
2466 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2467 hi
->announcements
= '?';
2469 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2474 switch (hi
->announcements
) {
2475 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2476 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2477 case '?': choice
= "default"; break;
2478 default: choice
= "unknown"; break;
2480 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2484 static OPTION_FUNC(opt_password
)
2487 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2492 cryptpass(argv
[1], hi
->passwd
);
2494 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2498 static OPTION_FUNC(opt_flags
)
2501 unsigned int ii
, flen
;
2504 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2509 nickserv_apply_flags(user
, hi
, argv
[1]);
2511 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2512 if (hi
->flags
& (1 << ii
))
2513 flags
[flen
++] = handle_flags
[ii
];
2516 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2518 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2522 static OPTION_FUNC(opt_email
)
2526 if (!is_valid_email_addr(argv
[1])) {
2527 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2530 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2531 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2534 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2535 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2537 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2539 nickserv_set_email_addr(hi
, argv
[1]);
2541 nickserv_eat_cookie(hi
->cookie
);
2542 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2545 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2549 static OPTION_FUNC(opt_maxlogins
)
2551 unsigned char maxlogins
;
2553 maxlogins
= strtoul(argv
[1], NULL
, 0);
2554 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2555 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2558 hi
->maxlogins
= maxlogins
;
2560 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2561 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2565 static OPTION_FUNC(opt_language
)
2567 struct language
*lang
;
2569 lang
= language_find(argv
[1]);
2570 if (irccasecmp(lang
->name
, argv
[1]))
2571 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2572 hi
->language
= lang
;
2574 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2579 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2580 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2582 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2583 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2584 && (user
->handle_info
->opserv_level
< 1000))) {
2585 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2588 if ((user
->handle_info
->opserv_level
< new_level
)
2589 || ((user
->handle_info
->opserv_level
== new_level
)
2590 && (user
->handle_info
->opserv_level
< 1000))) {
2591 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2594 if (user
->handle_info
== target
) {
2595 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2598 if (target
->opserv_level
== new_level
)
2600 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2601 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2602 target
->opserv_level
= new_level
;
2606 static OPTION_FUNC(opt_level
)
2611 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2615 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2616 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2620 static OPTION_FUNC(opt_epithet
)
2622 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2625 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2629 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2633 if ((epithet
[0] == '*') && !epithet
[1])
2636 hi
->epithet
= strdup(epithet
);
2640 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2642 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2646 static OPTION_FUNC(opt_title
)
2650 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2652 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2657 if (strchr(title
, '.')) {
2658 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2661 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2662 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2663 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2668 if (!strcmp(title
, "*")) {
2669 hi
->fakehost
= NULL
;
2671 hi
->fakehost
= malloc(strlen(title
)+2);
2672 hi
->fakehost
[0] = '.';
2673 strcpy(hi
->fakehost
+1, title
);
2676 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2677 title
= hi
->fakehost
+ 1;
2681 title
= user_find_message(user
, "MSG_NONE");
2682 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2686 static OPTION_FUNC(opt_fakehost
)
2690 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2692 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2697 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
2698 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
2702 if (!strcmp(fake
, "*"))
2703 hi
->fakehost
= NULL
;
2705 hi
->fakehost
= strdup(fake
);
2706 fake
= hi
->fakehost
;
2709 fake
= generate_fakehost(hi
);
2711 fake
= user_find_message(user
, "MSG_NONE");
2712 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
2716 static NICKSERV_FUNC(cmd_reclaim
)
2718 struct handle_info
*hi
;
2719 struct nick_info
*ni
;
2720 struct userNode
*victim
;
2722 NICKSERV_MIN_PARMS(2);
2723 hi
= user
->handle_info
;
2724 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
2726 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
2729 if (ni
->owner
!= user
->handle_info
) {
2730 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
2733 victim
= GetUserH(ni
->nick
);
2735 reply("MSG_NICK_UNKNOWN", ni
->nick
);
2738 if (victim
== user
) {
2739 reply("NSMSG_NICK_USER_YOU");
2742 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
2743 switch (nickserv_conf
.reclaim_action
) {
2744 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
2745 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
2746 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
2747 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
2752 static NICKSERV_FUNC(cmd_unregnick
)
2755 struct handle_info
*hi
;
2756 struct nick_info
*ni
;
2758 hi
= user
->handle_info
;
2759 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
2760 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2762 reply("NSMSG_UNKNOWN_NICK", nick
);
2765 if (hi
!= ni
->owner
) {
2766 reply("NSMSG_NOT_YOUR_NICK", nick
);
2769 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2774 static NICKSERV_FUNC(cmd_ounregnick
)
2776 struct nick_info
*ni
;
2778 NICKSERV_MIN_PARMS(2);
2779 if (!(ni
= get_nick_info(argv
[1]))) {
2780 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
2783 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
2784 reply("MSG_USER_OUTRANKED", ni
->nick
);
2787 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2792 static NICKSERV_FUNC(cmd_unregister
)
2794 struct handle_info
*hi
;
2797 NICKSERV_MIN_PARMS(2);
2798 hi
= user
->handle_info
;
2801 if (checkpass(passwd
, hi
->passwd
)) {
2802 nickserv_unregister_handle(hi
, user
);
2805 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
2806 reply("NSMSG_PASSWORD_INVALID");
2811 static NICKSERV_FUNC(cmd_ounregister
)
2813 struct handle_info
*hi
;
2815 NICKSERV_MIN_PARMS(2);
2816 if (!(hi
= get_victim_oper(user
, argv
[1])))
2818 nickserv_unregister_handle(hi
, user
);
2822 static NICKSERV_FUNC(cmd_status
)
2824 if (nickserv_conf
.disable_nicks
) {
2825 reply("NSMSG_GLOBAL_STATS_NONICK",
2826 dict_size(nickserv_handle_dict
));
2828 if (user
->handle_info
) {
2830 struct nick_info
*ni
;
2831 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
2832 reply("NSMSG_HANDLE_STATS", cnt
);
2834 reply("NSMSG_HANDLE_NONE");
2836 reply("NSMSG_GLOBAL_STATS",
2837 dict_size(nickserv_handle_dict
),
2838 dict_size(nickserv_nick_dict
));
2843 static NICKSERV_FUNC(cmd_ghost
)
2845 struct userNode
*target
;
2846 char reason
[MAXLEN
];
2848 NICKSERV_MIN_PARMS(2);
2849 if (!(target
= GetUserH(argv
[1]))) {
2850 reply("MSG_NICK_UNKNOWN", argv
[1]);
2853 if (target
== user
) {
2854 reply("NSMSG_CANNOT_GHOST_SELF");
2857 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
2858 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
2861 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
2862 DelUser(target
, nickserv
, 1, reason
);
2863 reply("NSMSG_GHOST_KILLED", argv
[1]);
2867 static NICKSERV_FUNC(cmd_vacation
)
2869 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
2870 reply("NSMSG_ON_VACATION");
2875 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
2877 struct handle_info
*hi
;
2880 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
2882 #ifdef WITH_PROTOCOL_BAHAMUT
2885 saxdb_start_record(ctx
, iter_key(it
), 0);
2886 if (hi
->announcements
!= '?') {
2887 flags
[0] = hi
->announcements
;
2889 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
2892 struct handle_cookie
*cookie
= hi
->cookie
;
2895 switch (cookie
->type
) {
2896 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
2897 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
2898 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
2899 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
2900 default: type
= NULL
; break;
2903 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
2904 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
2905 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
2907 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
2908 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
2909 saxdb_end_record(ctx
);
2913 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
2915 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
2917 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
2921 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
2922 if (hi
->flags
& (1 << ii
))
2923 flags
[flen
++] = handle_flags
[ii
];
2925 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
2927 #ifdef WITH_PROTOCOL_BAHAMUT
2928 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
2931 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
2932 if (hi
->last_quit_host
[0])
2933 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
2934 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
2935 if (hi
->masks
->used
)
2936 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
2938 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
2940 struct string_list
*slist
;
2941 struct nick_info
*ni
;
2943 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
2944 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
2945 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
2949 if (hi
->opserv_level
)
2950 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
2951 if (hi
->language
!= lang_C
)
2952 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
2953 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
2954 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
2955 if (hi
->screen_width
)
2956 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
2957 if (hi
->table_width
)
2958 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
2959 flags
[0] = hi
->userlist_style
;
2961 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
2962 saxdb_end_record(ctx
);
2967 static handle_merge_func_t
*handle_merge_func_list
;
2968 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
2971 reg_handle_merge_func(handle_merge_func_t func
)
2973 if (handle_merge_func_used
== handle_merge_func_size
) {
2974 if (handle_merge_func_size
) {
2975 handle_merge_func_size
<<= 1;
2976 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
2978 handle_merge_func_size
= 8;
2979 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
2982 handle_merge_func_list
[handle_merge_func_used
++] = func
;
2985 static NICKSERV_FUNC(cmd_merge
)
2987 struct handle_info
*hi_from
, *hi_to
;
2988 struct userNode
*last_user
;
2989 struct userData
*cList
, *cListNext
;
2990 unsigned int ii
, jj
, n
;
2991 char buffer
[MAXLEN
];
2993 NICKSERV_MIN_PARMS(3);
2995 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
2997 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
2999 if (hi_to
== hi_from
) {
3000 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3004 for (n
=0; n
<handle_merge_func_used
; n
++)
3005 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3007 /* Append "from" handle's nicks to "to" handle's nick list. */
3009 struct nick_info
*last_ni
;
3010 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3011 last_ni
->next
= hi_from
->nicks
;
3013 while (hi_from
->nicks
) {
3014 hi_from
->nicks
->owner
= hi_to
;
3015 hi_from
->nicks
= hi_from
->nicks
->next
;
3018 /* Merge the hostmasks. */
3019 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3020 char *mask
= hi_from
->masks
->list
[ii
];
3021 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3022 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3024 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3025 string_list_append(hi_to
->masks
, strdup(mask
));
3028 /* Merge the lists of authed users. */
3030 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3031 last_user
->next_authed
= hi_from
->users
;
3033 hi_to
->users
= hi_from
->users
;
3035 /* Repoint the old "from" handle's users. */
3036 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3037 last_user
->handle_info
= hi_to
;
3039 hi_from
->users
= NULL
;
3041 /* Merge channel userlists. */
3042 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3043 struct userData
*cList2
;
3044 cListNext
= cList
->u_next
;
3045 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3046 if (cList
->channel
== cList2
->channel
)
3048 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3049 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
);
3050 /* keep cList2 in hi_to; remove cList from hi_from */
3051 del_channel_user(cList
, 1);
3054 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
);
3055 /* remove the lower-ranking cList2 from hi_to */
3056 del_channel_user(cList2
, 1);
3058 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3060 /* cList needs to be moved from hi_from to hi_to */
3061 cList
->handle
= hi_to
;
3062 /* Remove from linked list for hi_from */
3063 assert(!cList
->u_prev
);
3064 hi_from
->channels
= cList
->u_next
;
3066 cList
->u_next
->u_prev
= cList
->u_prev
;
3067 /* Add to linked list for hi_to */
3068 cList
->u_prev
= NULL
;
3069 cList
->u_next
= hi_to
->channels
;
3070 if (hi_to
->channels
)
3071 hi_to
->channels
->u_prev
= cList
;
3072 hi_to
->channels
= cList
;
3076 /* Do they get an OpServ level promotion? */
3077 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3078 hi_to
->opserv_level
= hi_from
->opserv_level
;
3080 /* What about last seen time? */
3081 if (hi_from
->lastseen
> hi_to
->lastseen
)
3082 hi_to
->lastseen
= hi_from
->lastseen
;
3084 /* Does a fakehost carry over? (This intentionally doesn't set it
3085 * for users previously attached to hi_to. They'll just have to
3088 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3089 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3091 /* Notify of success. */
3092 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3093 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3094 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3096 /* Unregister the "from" handle. */
3097 nickserv_unregister_handle(hi_from
, NULL
);
3102 struct nickserv_discrim
{
3103 unsigned int limit
, min_level
, max_level
;
3104 unsigned long flags_on
, flags_off
;
3105 time_t min_registered
, max_registered
;
3107 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3108 const char *nickmask
;
3109 const char *hostmask
;
3110 const char *handlemask
;
3111 const char *emailmask
;
3114 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3116 struct discrim_apply_info
{
3117 struct nickserv_discrim
*discrim
;
3118 discrim_search_func func
;
3119 struct userNode
*source
;
3120 unsigned int matched
;
3123 static struct nickserv_discrim
*
3124 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3127 struct nickserv_discrim
*discrim
;
3129 discrim
= malloc(sizeof(*discrim
));
3130 memset(discrim
, 0, sizeof(*discrim
));
3131 discrim
->min_level
= 0;
3132 discrim
->max_level
= ~0;
3133 discrim
->limit
= 50;
3134 discrim
->min_registered
= 0;
3135 discrim
->max_registered
= INT_MAX
;
3136 discrim
->lastseen
= now
;
3138 for (i
=0; i
<argc
; i
++) {
3139 if (i
== argc
- 1) {
3140 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3143 if (!irccasecmp(argv
[i
], "limit")) {
3144 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3145 } else if (!irccasecmp(argv
[i
], "flags")) {
3146 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3147 } else if (!irccasecmp(argv
[i
], "registered")) {
3148 const char *cmp
= argv
[++i
];
3149 if (cmp
[0] == '<') {
3150 if (cmp
[1] == '=') {
3151 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3153 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3155 } else if (cmp
[0] == '=') {
3156 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3157 } else if (cmp
[0] == '>') {
3158 if (cmp
[1] == '=') {
3159 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3161 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3164 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3166 } else if (!irccasecmp(argv
[i
], "seen")) {
3167 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3168 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3169 discrim
->nickmask
= argv
[++i
];
3170 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3172 if (!irccasecmp(argv
[i
], "exact")) {
3173 if (i
== argc
- 1) {
3174 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3177 discrim
->hostmask_type
= EXACT
;
3178 } else if (!irccasecmp(argv
[i
], "subset")) {
3179 if (i
== argc
- 1) {
3180 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3183 discrim
->hostmask_type
= SUBSET
;
3184 } else if (!irccasecmp(argv
[i
], "superset")) {
3185 if (i
== argc
- 1) {
3186 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3189 discrim
->hostmask_type
= SUPERSET
;
3190 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3191 if (i
== argc
- 1) {
3192 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3195 discrim
->hostmask_type
= LASTQUIT
;
3198 discrim
->hostmask_type
= SUPERSET
;
3200 discrim
->hostmask
= argv
[++i
];
3201 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3202 if (!irccasecmp(argv
[++i
], "*")) {
3203 discrim
->handlemask
= 0;
3205 discrim
->handlemask
= argv
[i
];
3207 } else if (!irccasecmp(argv
[i
], "email")) {
3208 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3209 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3211 } else if (!irccasecmp(argv
[++i
], "*")) {
3212 discrim
->emailmask
= 0;
3214 discrim
->emailmask
= argv
[i
];
3216 } else if (!irccasecmp(argv
[i
], "access")) {
3217 const char *cmp
= argv
[++i
];
3218 if (cmp
[0] == '<') {
3219 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3220 if (cmp
[1] == '=') {
3221 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3223 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3225 } else if (cmp
[0] == '=') {
3226 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3227 } else if (cmp
[0] == '>') {
3228 if (cmp
[1] == '=') {
3229 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3231 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3234 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3237 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3248 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3250 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3251 || (discrim
->flags_off
& hi
->flags
)
3252 || (discrim
->min_registered
> hi
->registered
)
3253 || (discrim
->max_registered
< hi
->registered
)
3254 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3255 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3256 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3257 || (discrim
->min_level
> hi
->opserv_level
)
3258 || (discrim
->max_level
< hi
->opserv_level
)) {
3261 if (discrim
->hostmask
) {
3263 for (i
=0; i
<hi
->masks
->used
; i
++) {
3264 const char *mask
= hi
->masks
->list
[i
];
3265 if ((discrim
->hostmask_type
== SUBSET
)
3266 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3267 else if ((discrim
->hostmask_type
== EXACT
)
3268 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3269 else if ((discrim
->hostmask_type
== SUPERSET
)
3270 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3271 else if ((discrim
->hostmask_type
== LASTQUIT
)
3272 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3274 if (i
==hi
->masks
->used
) return 0;
3276 if (discrim
->nickmask
) {
3277 struct nick_info
*nick
= hi
->nicks
;
3279 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3282 if (!nick
) return 0;
3288 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3290 dict_iterator_t it
, next
;
3291 unsigned int matched
;
3293 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3294 it
&& (matched
< discrim
->limit
);
3296 next
= iter_next(it
);
3297 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3298 dsf(source
, iter_data(it
));
3306 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3308 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3312 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3317 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3319 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3320 nickserv_unregister_handle(match
, source
);
3324 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3326 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3327 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3328 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3329 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3330 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3334 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3336 struct handle_info_list hil
;
3337 struct helpfile_table tbl
;
3342 memset(&hil
, 0, sizeof(hil
));
3343 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3344 struct handle_info
*hi
= iter_data(it
);
3345 if (hi
->opserv_level
)
3346 handle_info_list_append(&hil
, hi
);
3348 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3349 tbl
.length
= hil
.used
+ 1;
3351 tbl
.flags
= TABLE_NO_FREE
;
3352 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3353 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3356 for (ii
= 0; ii
< hil
.used
; ) {
3357 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3358 ary
[0] = hil
.list
[ii
]->handle
;
3359 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3360 tbl
.contents
[++ii
] = ary
;
3362 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3363 reply("MSG_MATCH_COUNT", hil
.used
);
3364 for (ii
= 0; ii
< hil
.used
; ii
++)
3365 free(tbl
.contents
[ii
]);
3370 static NICKSERV_FUNC(cmd_search
)
3372 struct nickserv_discrim
*discrim
;
3373 discrim_search_func action
;
3374 struct svccmd
*subcmd
;
3375 unsigned int matches
;
3378 NICKSERV_MIN_PARMS(3);
3379 sprintf(buf
, "search %s", argv
[1]);
3380 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3381 if (!irccasecmp(argv
[1], "print"))
3382 action
= search_print_func
;
3383 else if (!irccasecmp(argv
[1], "count"))
3384 action
= search_count_func
;
3385 else if (!irccasecmp(argv
[1], "unregister"))
3386 action
= search_unregister_func
;
3388 reply("NSMSG_INVALID_ACTION", argv
[1]);
3392 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3395 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3399 if (action
== search_print_func
)
3400 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3401 else if (action
== search_count_func
)
3402 discrim
->limit
= INT_MAX
;
3404 matches
= nickserv_discrim_search(discrim
, action
, user
);
3407 reply("MSG_MATCH_COUNT", matches
);
3409 reply("MSG_NO_MATCHES");
3415 static MODCMD_FUNC(cmd_checkpass
)
3417 struct handle_info
*hi
;
3419 NICKSERV_MIN_PARMS(3);
3420 if (!(hi
= get_handle_info(argv
[1]))) {
3421 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3424 if (checkpass(argv
[2], hi
->passwd
))
3425 reply("CHECKPASS_YES");
3427 reply("CHECKPASS_NO");
3433 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3436 struct string_list
*masks
, *slist
;
3437 struct handle_info
*hi
;
3438 struct userNode
*authed_users
;
3439 struct userData
*channels
;
3440 unsigned long int id
;
3444 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3445 id
= str
? strtoul(str
, NULL
, 0) : 0;
3446 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3448 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3451 if ((hi
= get_handle_info(handle
))) {
3452 authed_users
= hi
->users
;
3453 channels
= hi
->channels
;
3455 hi
->channels
= NULL
;
3456 dict_remove(nickserv_handle_dict
, hi
->handle
);
3458 authed_users
= NULL
;
3461 hi
= register_handle(handle
, str
, id
);
3463 hi
->users
= authed_users
;
3464 while (authed_users
) {
3465 authed_users
->handle_info
= hi
;
3466 authed_users
= authed_users
->next_authed
;
3469 hi
->channels
= channels
;
3470 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3471 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3472 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3473 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3474 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3475 hi
->language
= language_find(str
? str
: "C");
3476 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3477 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3478 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3480 hi
->infoline
= strdup(str
);
3481 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3482 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3483 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3484 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3485 /* We want to read the nicks even if disable_nicks is set. This is so
3486 * that we don't lose the nick data entirely. */
3487 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3489 for (ii
=0; ii
<slist
->used
; ii
++)
3490 register_nick(slist
->list
[ii
], hi
);
3492 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3494 for (ii
=0; str
[ii
]; ii
++)
3495 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3497 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3498 hi
->userlist_style
= str
? str
[0] : HI_STYLE_ZOOT
;
3499 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3500 hi
->announcements
= str
? str
[0] : '?';
3501 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3502 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3503 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3504 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3505 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3507 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3509 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3510 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3512 nickserv_set_email_addr(hi
, str
);
3513 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3515 hi
->epithet
= strdup(str
);
3516 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3518 hi
->fakehost
= strdup(str
);
3519 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3521 const char *data
, *type
, *expires
, *cookie_str
;
3522 struct handle_cookie
*cookie
;
3524 cookie
= calloc(1, sizeof(*cookie
));
3525 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3526 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3527 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3528 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3529 if (!type
|| !expires
|| !cookie_str
) {
3530 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3533 if (!irccasecmp(type
, KEY_ACTIVATION
))
3534 cookie
->type
= ACTIVATION
;
3535 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3536 cookie
->type
= PASSWORD_CHANGE
;
3537 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3538 cookie
->type
= EMAIL_CHANGE
;
3539 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3540 cookie
->type
= ALLOWAUTH
;
3542 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3545 cookie
->expires
= strtoul(expires
, NULL
, 0);
3546 if (cookie
->expires
< now
)
3549 cookie
->data
= strdup(data
);
3550 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3554 nickserv_bake_cookie(cookie
);
3556 nickserv_free_cookie(cookie
);
3561 nickserv_saxdb_read(dict_t db
) {
3563 struct record_data
*rd
;
3565 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3567 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3572 static NICKSERV_FUNC(cmd_mergedb
)
3574 struct timeval start
, stop
;
3577 NICKSERV_MIN_PARMS(2);
3578 gettimeofday(&start
, NULL
);
3579 if (!(db
= parse_database(argv
[1]))) {
3580 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3583 nickserv_saxdb_read(db
);
3585 gettimeofday(&stop
, NULL
);
3586 stop
.tv_sec
-= start
.tv_sec
;
3587 stop
.tv_usec
-= start
.tv_usec
;
3588 if (stop
.tv_usec
< 0) {
3590 stop
.tv_usec
+= 1000000;
3592 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3597 expire_handles(UNUSED_ARG(void *data
))
3599 dict_iterator_t it
, next
;
3601 struct handle_info
*hi
;
3603 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3604 next
= iter_next(it
);
3606 if ((hi
->opserv_level
> 0)
3608 || HANDLE_FLAGGED(hi
, FROZEN
)
3609 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3612 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3613 if ((now
- hi
->lastseen
) > expiry
) {
3614 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3615 nickserv_unregister_handle(hi
, NULL
);
3619 if (nickserv_conf
.handle_expire_frequency
)
3620 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3624 nickserv_load_dict(const char *fname
)
3628 if (!(file
= fopen(fname
, "r"))) {
3629 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
3632 while (!feof(file
)) {
3633 fgets(line
, sizeof(line
), file
);
3636 if (line
[strlen(line
)-1] == '\n')
3637 line
[strlen(line
)-1] = 0;
3638 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
3641 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
3644 static enum reclaim_action
3645 reclaim_action_from_string(const char *str
) {
3647 return RECLAIM_NONE
;
3648 else if (!irccasecmp(str
, "warn"))
3649 return RECLAIM_WARN
;
3650 else if (!irccasecmp(str
, "svsnick"))
3651 return RECLAIM_SVSNICK
;
3652 else if (!irccasecmp(str
, "kill"))
3653 return RECLAIM_KILL
;
3655 return RECLAIM_NONE
;
3659 nickserv_conf_read(void)
3661 dict_t conf_node
, child
;
3665 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
3666 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
3669 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
3671 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
3672 if (nickserv_conf
.valid_handle_regex_set
)
3673 regfree(&nickserv_conf
.valid_handle_regex
);
3675 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3676 nickserv_conf
.valid_handle_regex_set
= !err
;
3677 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
3679 nickserv_conf
.valid_handle_regex_set
= 0;
3681 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
3682 if (nickserv_conf
.valid_nick_regex_set
)
3683 regfree(&nickserv_conf
.valid_nick_regex
);
3685 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3686 nickserv_conf
.valid_nick_regex_set
= !err
;
3687 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
3689 nickserv_conf
.valid_nick_regex_set
= 0;
3691 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
3693 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
3694 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
3695 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
3696 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
3697 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
3698 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
3699 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
3700 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
3701 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
3702 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
3703 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
3704 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
3705 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
3706 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
3707 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
3708 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
3709 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
3710 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
3711 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
3712 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
3713 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
3714 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
3715 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
3716 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
3717 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
3719 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
3720 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
3721 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3723 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3724 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
3725 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3727 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3728 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
3729 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
3730 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
3731 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
3732 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
3733 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
3734 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
3735 if (!nickserv_conf
.disable_nicks
) {
3736 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
3737 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3738 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
3739 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
3740 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
3741 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3742 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
3743 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
3745 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
3746 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
3747 const char *key
= iter_key(it
), *value
;
3751 if (!strncasecmp(key
, "uc_", 3))
3752 flag
= toupper(key
[3]);
3753 else if (!strncasecmp(key
, "lc_", 3))
3754 flag
= tolower(key
[3]);
3758 if ((pos
= handle_inverse_flags
[flag
])) {
3759 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
3760 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
3763 if (nickserv_conf
.weak_password_dict
)
3764 dict_delete(nickserv_conf
.weak_password_dict
);
3765 nickserv_conf
.weak_password_dict
= dict_new();
3766 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
3767 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
3768 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
3769 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
3771 nickserv_load_dict(str
);
3772 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
3773 if (nickserv
&& str
)
3774 NickChange(nickserv
, str
, 0);
3775 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
3776 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
3777 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
3778 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
3779 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
3780 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
3781 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
3782 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
3783 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
3784 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
3785 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
3786 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
3787 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
3788 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
3789 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
3790 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
3791 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
3792 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
3793 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
3794 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
3795 str
= conf_get_data("server/network", RECDB_QSTRING
);
3796 nickserv_conf
.network_name
= str
? str
: "some IRC network";
3797 if (!nickserv_conf
.auth_policer_params
) {
3798 nickserv_conf
.auth_policer_params
= policer_params_new();
3799 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
3800 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
3802 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
3803 for (it
=dict_first(child
); it
; it
=iter_next(it
))
3804 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
3808 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
3810 char newnick
[NICKLEN
+1];
3819 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3821 case RECLAIM_SVSNICK
:
3823 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
3824 } while (GetUserH(newnick
));
3825 irc_svsnick(nickserv
, user
, newnick
);
3828 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
3829 irc_kill(nickserv
, user
, msg
);
3835 nickserv_reclaim_p(void *data
) {
3836 struct userNode
*user
= data
;
3837 struct nick_info
*ni
= get_nick_info(user
->nick
);
3839 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3843 check_user_nick(struct userNode
*user
) {
3844 struct nick_info
*ni
;
3845 user
->modes
&= ~FLAGS_REGNICK
;
3846 if (!(ni
= get_nick_info(user
->nick
)))
3848 if (user
->handle_info
== ni
->owner
) {
3849 user
->modes
|= FLAGS_REGNICK
;
3853 if (nickserv_conf
.warn_nick_owned
)
3854 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3855 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
3857 if (nickserv_conf
.auto_reclaim_delay
)
3858 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
3860 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3865 handle_new_user(struct userNode
*user
)
3867 return check_user_nick(user
);
3871 handle_account(struct userNode
*user
, const char *stamp
)
3873 struct handle_info
*hi
;
3876 #ifdef WITH_PROTOCOL_P10
3877 time_t timestamp
= 0;
3879 colon
= strchr(stamp
, ':');
3880 if(colon
&& colon
[1])
3883 timestamp
= atoi(colon
+1);
3885 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
3886 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
3888 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
);
3892 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
3893 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
3897 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
3900 set_user_handle_info(user
, hi
, 0);
3902 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
3907 handle_nick_change(struct userNode
*user
, const char *old_nick
)
3909 struct handle_info
*hi
;
3911 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
3912 dict_remove(nickserv_allow_auth_dict
, old_nick
);
3913 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
3915 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3916 check_user_nick(user
);
3920 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
3922 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
3923 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3924 set_user_handle_info(user
, NULL
, 0);
3927 static struct modcmd
*
3928 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
3930 if (min_level
> 0) {
3932 sprintf(buf
, "%u", min_level
);
3933 if (must_be_qualified
) {
3934 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
3936 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
3938 } else if (min_level
== 0) {
3939 if (must_be_qualified
) {
3940 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3942 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3945 if (must_be_qualified
) {
3946 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
3948 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
3954 nickserv_db_cleanup(void)
3956 unreg_del_user_func(nickserv_remove_user
);
3957 userList_clean(&curr_helpers
);
3958 policer_params_delete(nickserv_conf
.auth_policer_params
);
3959 dict_delete(nickserv_handle_dict
);
3960 dict_delete(nickserv_nick_dict
);
3961 dict_delete(nickserv_opt_dict
);
3962 dict_delete(nickserv_allow_auth_dict
);
3963 dict_delete(nickserv_email_dict
);
3964 dict_delete(nickserv_id_dict
);
3965 dict_delete(nickserv_conf
.weak_password_dict
);
3966 free(auth_func_list
);
3967 free(unreg_func_list
);
3969 free(allowauth_func_list
);
3970 free(handle_merge_func_list
);
3971 free(failpw_func_list
);
3972 if (nickserv_conf
.valid_handle_regex_set
)
3973 regfree(&nickserv_conf
.valid_handle_regex
);
3974 if (nickserv_conf
.valid_nick_regex_set
)
3975 regfree(&nickserv_conf
.valid_nick_regex
);
3979 init_nickserv(const char *nick
)
3982 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
3983 reg_new_user_func(handle_new_user
);
3984 reg_nick_change_func(handle_nick_change
);
3985 reg_del_user_func(nickserv_remove_user
);
3986 reg_account_func(handle_account
);
3988 /* set up handle_inverse_flags */
3989 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
3990 for (i
=0; handle_flags
[i
]; i
++) {
3991 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
3992 flag_access_levels
[i
] = 0;
3995 conf_register_reload(nickserv_conf_read
);
3996 nickserv_opt_dict
= dict_new();
3997 nickserv_email_dict
= dict_new();
3998 dict_set_free_keys(nickserv_email_dict
, free
);
3999 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4001 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4002 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4003 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4004 * a big pain to disable since its nolonger in the config file. ) -Rubin
4006 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4007 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4008 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4009 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4010 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4011 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4012 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4013 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4014 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4015 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4016 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4017 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4018 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4019 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4020 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4021 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4022 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4023 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4024 if (!nickserv_conf
.disable_nicks
) {
4025 /* nick management commands */
4026 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4027 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4028 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4029 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4030 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4031 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4033 if (nickserv_conf
.email_enabled
) {
4034 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4035 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4036 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4037 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4038 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4039 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4041 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4042 /* miscellaneous commands */
4043 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4044 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4045 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4046 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4047 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4049 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4050 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4051 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4052 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4053 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4054 /* dict_insert(nickserv_opt_dict, "STYLE", opt_style); */
4055 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4056 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4057 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4058 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4059 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4060 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4061 if (nickserv_conf
.titlehost_suffix
) {
4062 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4063 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4065 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4066 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4067 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4069 nickserv_handle_dict
= dict_new();
4070 dict_set_free_keys(nickserv_handle_dict
, free
);
4071 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4073 nickserv_id_dict
= dict_new();
4074 dict_set_free_keys(nickserv_id_dict
, free
);
4076 nickserv_nick_dict
= dict_new();
4077 dict_set_free_data(nickserv_nick_dict
, free
);
4079 nickserv_allow_auth_dict
= dict_new();
4081 userList_init(&curr_helpers
);
4084 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4085 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4086 nickserv_service
= service_register(nickserv
);
4088 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4089 reg_exit_func(nickserv_db_cleanup
);
4090 if(nickserv_conf
.handle_expire_frequency
)
4091 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4092 message_register_table(msgtab
);