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_AUTO_OPER "auto_oper"
54 #define KEY_AUTO_ADMIN "auto_admin"
55 #define KEY_FLAG_LEVELS "flag_levels"
56 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
57 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
58 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
59 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
60 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
61 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
62 #define KEY_DICT_FILE "dict_file"
63 #define KEY_NICK "nick"
64 #define KEY_LANGUAGE "language"
65 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
66 #define KEY_AUTOGAG_DURATION "autogag_duration"
67 #define KEY_AUTH_POLICER "auth_policer"
68 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
69 #define KEY_EMAIL_ENABLED "email_enabled"
70 #define KEY_EMAIL_REQUIRED "email_required"
71 #define KEY_SYNC_LOG "sync_log"
72 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
73 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
74 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
77 #define KEY_PASSWD "passwd"
78 #define KEY_NICKS "nicks"
79 #define KEY_MASKS "masks"
80 #define KEY_OPSERV_LEVEL "opserv_level"
81 #define KEY_FLAGS "flags"
82 #define KEY_REGISTER_ON "register"
83 #define KEY_LAST_SEEN "lastseen"
84 #define KEY_INFO "info"
85 #define KEY_USERLIST_STYLE "user_style"
86 #define KEY_SCREEN_WIDTH "screen_width"
87 #define KEY_LAST_AUTHED_HOST "last_authed_host"
88 #define KEY_LAST_QUIT_HOST "last_quit_host"
89 #define KEY_EMAIL_ADDR "email_addr"
90 #define KEY_COOKIE "cookie"
91 #define KEY_COOKIE_DATA "data"
92 #define KEY_COOKIE_TYPE "type"
93 #define KEY_COOKIE_EXPIRES "expires"
94 #define KEY_ACTIVATION "activation"
95 #define KEY_PASSWORD_CHANGE "password change"
96 #define KEY_EMAIL_CHANGE "email change"
97 #define KEY_ALLOWAUTH "allowauth"
98 #define KEY_EPITHET "epithet"
99 #define KEY_TABLE_WIDTH "table_width"
100 #define KEY_ANNOUNCEMENTS "announcements"
101 #define KEY_MAXLOGINS "maxlogins"
102 #define KEY_FAKEHOST "fakehost"
104 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
106 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
107 #define OPTION_FUNC(NAME) int NAME(struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
108 typedef OPTION_FUNC(option_func_t
);
110 DEFINE_LIST(handle_info_list
, struct handle_info
*);
112 #define NICKSERV_MIN_PARMS(N) do { \
114 reply("MSG_MISSING_PARAMS", argv[0]); \
115 svccmd_send_help_brief(user, nickserv, cmd); \
119 struct userNode
*nickserv
;
120 struct userList curr_helpers
;
121 const char *handle_flags
= HANDLE_FLAGS
;
123 static struct module *nickserv_module
;
124 static struct service
*nickserv_service
;
125 static struct log_type
*NS_LOG
;
126 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
127 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
128 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
129 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
130 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
131 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
132 static char handle_inverse_flags
[256];
133 static unsigned int flag_access_levels
[32];
134 static const struct message_entry msgtab
[] = {
135 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
136 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu charactors or less."},
137 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
138 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
139 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
140 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
141 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
142 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
143 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
144 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
145 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
146 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
147 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
148 { "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." },
149 { "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." },
150 { "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." },
151 { "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." },
152 { "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." },
153 { "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." },
154 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
155 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
156 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
157 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
158 { "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." },
159 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
160 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
161 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
162 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
163 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
164 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
165 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
166 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
167 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
168 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
169 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
170 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
171 { "NSMSG_REGISTER_BAD_NICKMASK", "Could not recognize $b%s$b as either a current nick or a hostmask." },
172 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
173 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
174 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
175 { "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)" },
176 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
177 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
178 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
179 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
180 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
181 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
182 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
183 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
184 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
185 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
186 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
187 { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
188 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
189 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
190 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
191 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
192 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
193 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
194 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
195 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
196 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
197 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
198 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
199 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
200 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
201 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
202 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
203 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
204 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
205 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
206 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
207 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
208 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
209 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
210 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
211 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
212 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
213 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
214 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
215 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
216 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
217 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
218 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
219 { "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)." },
220 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
221 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
222 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
223 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
224 { "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." },
225 { "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." },
226 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
227 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
228 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
229 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
230 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
231 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
232 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
233 { "NSMSG_PASS_SUCCESS", "Password changed." },
234 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
235 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
236 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
237 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
238 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
239 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
240 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
241 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
242 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
243 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
244 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
245 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
246 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
247 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
248 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
249 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
250 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
251 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
252 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
253 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
254 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
255 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
256 { "NSMSG_NO_ACCESS", "Access denied." },
257 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
258 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
259 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
260 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
261 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
262 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
263 { "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." },
264 { "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." },
265 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
266 { "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." },
267 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
268 { "NSMSG_SEARCH_MATCH", "Match: %s" },
269 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
270 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
271 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
272 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
273 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
274 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
275 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
276 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
277 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
278 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
279 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
280 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
281 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
282 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
283 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
284 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
285 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
286 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
287 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
288 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
289 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
290 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
291 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
292 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
293 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
294 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
295 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
296 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
297 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
298 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
299 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
300 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
302 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
303 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
305 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
306 { "NSEMAIL_ACTIVATION_BODY",
307 "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"
309 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
310 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
311 "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"
312 "/msg %3$s@%4$s AUTH %5$s your-password\n"
313 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
314 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
316 "If you did NOT request this account, you do not need to do anything.\n"
317 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
318 { "NSEMAIL_ACTIVATION_BODY_WEB",
319 "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"
321 "To verify your email address and complete the account registration, visit the following URL:\n"
322 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
324 "If you did NOT request this account, you do not need to do anything.\n"
325 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
326 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
327 { "NSEMAIL_PASSWORD_CHANGE_BODY",
328 "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"
329 "To complete the password change, log on to %1$s and type the following command:\n"
330 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
331 "If you did NOT request your password to be changed, you do not need to do anything.\n"
332 "Please contact the %1$s staff if you have questions." },
333 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
334 "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"
335 "To complete the password change, click the following URL:\n"
336 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
337 "If you did NOT request your password to be changed, you do not need to do anything.\n"
338 "Please contact the %1$s staff if you have questions." },
339 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
340 #ifdef stupid_verify_old_email
341 { "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." },
342 { "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." },
344 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
345 { "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." },
346 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
347 { "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." },
348 { "CHECKPASS_YES", "Yes." },
349 { "CHECKPASS_NO", "No." },
353 enum reclaim_action
{
359 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
360 static void nickserv_reclaim_p(void *data
);
363 unsigned int disable_nicks
: 1;
364 unsigned int valid_handle_regex_set
: 1;
365 unsigned int valid_nick_regex_set
: 1;
366 unsigned int autogag_enabled
: 1;
367 unsigned int email_enabled
: 1;
368 unsigned int email_required
: 1;
369 unsigned int default_hostmask
: 1;
370 unsigned int warn_nick_owned
: 1;
371 unsigned int warn_clone_auth
: 1;
372 unsigned int sync_log
: 1;
373 unsigned long nicks_per_handle
;
374 unsigned long password_min_length
;
375 unsigned long password_min_digits
;
376 unsigned long password_min_upper
;
377 unsigned long password_min_lower
;
378 unsigned long db_backup_frequency
;
379 unsigned long handle_expire_frequency
;
380 unsigned long autogag_duration
;
381 unsigned long email_visible_level
;
382 unsigned long cookie_timeout
;
383 unsigned long handle_expire_delay
;
384 unsigned long nochan_handle_expire_delay
;
385 unsigned long modoper_level
;
386 unsigned long set_epithet_level
;
387 unsigned long set_title_level
;
388 unsigned long set_fakehost_level
;
389 unsigned long handles_per_email
;
390 unsigned long email_search_level
;
391 const char *network_name
;
392 const char *titlehost_suffix
;
393 regex_t valid_handle_regex
;
394 regex_t valid_nick_regex
;
395 dict_t weak_password_dict
;
396 struct policer_params
*auth_policer_params
;
397 enum reclaim_action reclaim_action
;
398 enum reclaim_action auto_reclaim_action
;
399 unsigned long auto_reclaim_delay
;
400 unsigned char default_maxlogins
;
401 unsigned char hard_maxlogins
;
402 const char *auto_oper
;
403 const char *auto_admin
;
406 /* We have 2^32 unique account IDs to use. */
407 unsigned long int highest_id
= 0;
410 canonicalize_hostmask(char *mask
)
412 char *out
= mask
, *temp
;
413 if ((temp
= strchr(mask
, '!'))) {
415 while (*temp
) *out
++ = *temp
++;
421 static struct handle_info
*
422 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
424 struct handle_info
*hi
;
426 #ifdef WITH_PROTOCOL_BAHAMUT
427 char id_base64
[IDLEN
+ 1];
430 /* Assign a unique account ID to the account; note that 0 is
431 an invalid account ID. 1 is therefore the first account ID. */
433 id
= 1 + highest_id
++;
435 /* Note: highest_id is and must always be the highest ID. */
436 if(id
> highest_id
) {
440 inttobase64(id_base64
, id
, IDLEN
);
442 /* Make sure an account with the same ID doesn't exist. If a
443 duplicate is found, log some details and assign a new one.
444 This should be impossible, but it never hurts to expect it. */
445 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
446 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
452 hi
= calloc(1, sizeof(*hi
));
453 hi
->userlist_style
= HI_DEFAULT_STYLE
;
454 hi
->announcements
= '?';
455 hi
->handle
= strdup(handle
);
456 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
458 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
460 #ifdef WITH_PROTOCOL_BAHAMUT
462 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
469 register_nick(const char *nick
, struct handle_info
*owner
)
471 struct nick_info
*ni
;
472 ni
= malloc(sizeof(struct nick_info
));
473 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
475 ni
->next
= owner
->nicks
;
477 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
481 delete_nick(struct nick_info
*ni
)
483 struct nick_info
*last
, *next
;
484 struct userNode
*user
;
485 /* Check to see if we should mark a user as unregistered. */
486 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
487 user
->modes
&= ~FLAGS_REGNICK
;
490 /* Remove ni from the nick_info linked list. */
491 if (ni
== ni
->owner
->nicks
) {
492 ni
->owner
->nicks
= ni
->next
;
494 last
= ni
->owner
->nicks
;
500 last
->next
= next
->next
;
502 dict_remove(nickserv_nick_dict
, ni
->nick
);
505 static unreg_func_t
*unreg_func_list
;
506 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
509 reg_unreg_func(unreg_func_t func
)
511 if (unreg_func_used
== unreg_func_size
) {
512 if (unreg_func_size
) {
513 unreg_func_size
<<= 1;
514 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
517 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
520 unreg_func_list
[unreg_func_used
++] = func
;
524 nickserv_free_cookie(void *data
)
526 struct handle_cookie
*cookie
= data
;
527 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
528 if (cookie
->data
) free(cookie
->data
);
533 free_handle_info(void *vhi
)
535 struct handle_info
*hi
= vhi
;
537 #ifdef WITH_PROTOCOL_BAHAMUT
540 inttobase64(id
, hi
->id
, IDLEN
);
541 dict_remove(nickserv_id_dict
, id
);
544 free_string_list(hi
->masks
);
548 delete_nick(hi
->nicks
);
553 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
554 nickserv_free_cookie(hi
->cookie
);
556 if (hi
->email_addr
) {
557 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
558 handle_info_list_remove(hil
, hi
);
560 dict_remove(nickserv_email_dict
, hi
->email_addr
);
565 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
568 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
)
572 for (n
=0; n
<unreg_func_used
; n
++)
573 unreg_func_list
[n
](notify
, hi
);
575 set_user_handle_info(hi
->users
, NULL
, 0);
577 if (nickserv_conf
.disable_nicks
)
578 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
580 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
583 if (nickserv_conf
.sync_log
)
584 SyncLog("UNREGISTER %s", hi
->handle
);
586 dict_remove(nickserv_handle_dict
, hi
->handle
);
590 get_handle_info(const char *handle
)
592 return dict_find(nickserv_handle_dict
, handle
, 0);
596 get_nick_info(const char *nick
)
598 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
602 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
607 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
608 mn
= channel
->members
.list
[nn
];
609 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
616 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
617 if (!user
->handle_info
) {
619 send_message(user
, bot
, "MSG_AUTHENTICATE");
623 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
625 send_message(user
, bot
, "NSMSG_NO_ACCESS");
629 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
631 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
635 if (user
->handle_info
->opserv_level
< min_level
) {
637 send_message(user
, bot
, "NSMSG_NO_ACCESS");
645 is_valid_handle(const char *handle
)
647 struct userNode
*user
;
648 /* cant register a juped nick/service nick as handle, to prevent confusion */
649 user
= GetUserH(handle
);
650 if (user
&& IsLocal(user
))
652 /* check against maximum length */
653 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
655 /* for consistency, only allow account names that could be nicks */
656 if (!is_valid_nick(handle
))
658 /* disallow account names that look like bad words */
659 if (opserv_bad_channel(handle
))
661 /* test either regex or containing all valid chars */
662 if (nickserv_conf
.valid_handle_regex_set
) {
663 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
666 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
667 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
671 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
676 is_registerable_nick(const char *nick
)
678 /* make sure it could be used as an account name */
679 if (!is_valid_handle(nick
))
682 if (strlen(nick
) > NICKLEN
)
684 /* test either regex or as valid handle */
685 if (nickserv_conf
.valid_nick_regex_set
) {
686 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
689 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
690 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
698 is_valid_email_addr(const char *email
)
700 return strchr(email
, '@') != NULL
;
704 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
706 if (hi
->email_addr
) {
707 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
708 return hi
->email_addr
;
718 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
720 struct handle_info
*hi
;
721 struct userNode
*target
;
725 if (!(hi
= get_handle_info(++name
))) {
726 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
731 if (!(target
= GetUserH(name
))) {
732 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
735 if (IsLocal(target
)) {
736 if (IsService(target
))
737 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
739 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
742 if (!(hi
= target
->handle_info
)) {
743 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
751 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
752 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
754 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
755 if ((user
->handle_info
->opserv_level
== 1000)
756 || (user
->handle_info
== hi
)
757 || ((user
->handle_info
->opserv_level
== 0)
758 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
759 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
763 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
767 static struct handle_info
*
768 get_victim_oper(struct userNode
*user
, const char *target
)
770 struct handle_info
*hi
;
771 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
773 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
774 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
777 return oper_outranks(user
, hi
) ? hi
: NULL
;
781 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
785 /* If no hostmasks on the account, allow it. */
786 if (!hi
->masks
->used
)
788 /* If any hostmask matches, allow it. */
789 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
790 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
792 /* If they are allowauthed to this account, allow it (removing the aa). */
793 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
794 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
797 /* The user is not allowed to use this account. */
802 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
805 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
809 if (len
< nickserv_conf
.password_min_length
) {
811 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
814 if (!irccasecmp(pass
, handle
)) {
816 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
819 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
822 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
825 for (i
=0; i
<len
; i
++) {
826 if (isdigit(pass
[i
]))
828 if (isupper(pass
[i
]))
830 if (islower(pass
[i
]))
833 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
834 || (cnt_upper
< nickserv_conf
.password_min_upper
)
835 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
837 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
843 static auth_func_t
*auth_func_list
;
844 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
847 reg_auth_func(auth_func_t func
)
849 if (auth_func_used
== auth_func_size
) {
850 if (auth_func_size
) {
851 auth_func_size
<<= 1;
852 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
855 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
858 auth_func_list
[auth_func_used
++] = func
;
861 static handle_rename_func_t
*rf_list
;
862 static unsigned int rf_list_size
, rf_list_used
;
865 reg_handle_rename_func(handle_rename_func_t func
)
867 if (rf_list_used
== rf_list_size
) {
870 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
873 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
876 rf_list
[rf_list_used
++] = func
;
880 generate_fakehost(struct handle_info
*handle
)
882 extern const char *hidden_host_suffix
;
883 static char buffer
[HOSTLEN
+1];
885 if (!handle
->fakehost
) {
886 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
888 } else if (handle
->fakehost
[0] == '.') {
889 /* A leading dot indicates the stored value is actually a title. */
890 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
893 return handle
->fakehost
;
897 apply_fakehost(struct handle_info
*handle
)
899 struct userNode
*target
;
904 fake
= generate_fakehost(handle
);
905 for (target
= handle
->users
; target
; target
= target
->next_authed
)
906 assign_fakehost(target
, fake
, 1);
909 void send_func_list(struct userNode
*user
)
912 struct handle_info
*old_info
;
914 old_info
= user
->handle_info
;
916 for (n
=0; n
<auth_func_used
; n
++)
917 auth_func_list
[n
](user
, old_info
);
921 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
924 struct handle_info
*old_info
;
926 /* This can happen if somebody uses COOKIE while authed, or if
927 * they re-auth to their current handle (which is silly, but users
929 if (user
->handle_info
== hi
)
932 if (user
->handle_info
) {
933 struct userNode
*other
;
936 userList_remove(&curr_helpers
, user
);
938 /* remove from next_authed linked list */
939 if (user
->handle_info
->users
== user
) {
940 user
->handle_info
->users
= user
->next_authed
;
942 for (other
= user
->handle_info
->users
;
943 other
->next_authed
!= user
;
944 other
= other
->next_authed
) ;
945 other
->next_authed
= user
->next_authed
;
947 /* if nobody left on old handle, and they're not an oper, remove !god */
948 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
949 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
950 /* record them as being last seen at this time */
951 user
->handle_info
->lastseen
= now
;
952 /* and record their hostmask */
953 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
955 old_info
= user
->handle_info
;
956 user
->handle_info
= hi
;
957 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
958 HANDLE_CLEAR_FLAG(hi
, HELPING
);
960 if (GetUserH(user
->nick
)) {
961 for (n
=0; n
<auth_func_used
; n
++)
962 auth_func_list
[n
](user
, old_info
);
967 struct nick_info
*ni
;
969 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
970 if (nickserv_conf
.warn_clone_auth
) {
971 struct userNode
*other
;
972 for (other
= hi
->users
; other
; other
= other
->next_authed
)
973 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
976 user
->next_authed
= hi
->users
;
980 userList_append(&curr_helpers
, user
);
982 if (hi
->fakehost
|| old_info
)
986 #ifdef WITH_PROTOCOL_BAHAMUT
987 /* Stamp users with their account ID. */
989 inttobase64(id
, hi
->id
, IDLEN
);
990 #elif WITH_PROTOCOL_P10
991 /* Stamp users with their account name. */
992 char *id
= hi
->handle
;
994 const char *id
= "???";
996 if (!nickserv_conf
.disable_nicks
) {
997 struct nick_info
*ni
;
998 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
999 if (!irccasecmp(user
->nick
, ni
->nick
)) {
1000 user
->modes
|= FLAGS_REGNICK
;
1005 StampUser(user
, id
, hi
->registered
);
1008 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1009 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1011 /* We cannot clear the user's account ID, unfortunately. */
1012 user
->next_authed
= NULL
;
1016 static struct handle_info
*
1017 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1019 struct handle_info
*hi
;
1020 struct nick_info
*ni
;
1021 char crypted
[MD5_CRYPT_LENGTH
];
1023 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1024 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1028 if(strlen(handle
) > 15)
1030 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1034 if (!is_secure_password(handle
, passwd
, user
))
1037 cryptpass(passwd
, crypted
);
1038 hi
= register_handle(handle
, crypted
, 0);
1039 hi
->masks
= alloc_string_list(1);
1041 hi
->language
= lang_C
;
1042 hi
->registered
= now
;
1044 hi
->flags
= HI_DEFAULT_FLAGS
;
1045 if (settee
&& !no_auth
)
1046 set_user_handle_info(settee
, hi
, 1);
1049 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1050 else if (nickserv_conf
.disable_nicks
)
1051 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1052 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1053 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1055 register_nick(user
->nick
, hi
);
1056 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1058 if (settee
&& (user
!= settee
))
1059 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1064 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1066 cookie
->hi
->cookie
= cookie
;
1067 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1070 /* Contributed by the great sneep of afternet ;) */
1071 /* Since this gets used in a URL, we want to avoid stuff that confuses
1072 * email clients such as ] and ?. a-z, 0-9 only.
1074 void genpass(char *str
, int len
)
1079 for(i
= 0; i
< len
; i
++)
1083 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1084 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1092 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1094 struct handle_cookie
*cookie
;
1095 char subject
[128], body
[4096], *misc
;
1096 const char *netname
, *fmt
;
1100 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1104 cookie
= calloc(1, sizeof(*cookie
));
1106 cookie
->type
= type
;
1107 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1109 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1110 /* Adding dedicated password gen function for more control -Rubin */
1111 genpass(cookie
->cookie
, 10);
1113 *inttobase64(cookie->cookie, rand(), 5);
1114 *inttobase64(cookie->cookie+5, rand(), 5);
1117 netname
= nickserv_conf
.network_name
;
1120 switch (cookie
->type
) {
1122 hi
->passwd
[0] = 0; /* invalidate password */
1123 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1124 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1125 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1128 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1130 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1132 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1135 case PASSWORD_CHANGE
:
1136 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1137 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1138 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1140 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1142 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1143 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1146 misc
= hi
->email_addr
;
1147 hi
->email_addr
= cookie
->data
;
1148 #ifdef stupid_verify_old_email
1150 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1151 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1152 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1153 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1154 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1155 sendmail(nickserv
, hi
, subject
, body
, 1);
1156 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1157 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1160 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1161 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1162 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1163 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1164 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1165 sendmail(nickserv
, hi
, subject
, body
, 1);
1167 #ifdef stupid_verify_old_email
1170 hi
->email_addr
= misc
;
1173 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1174 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1175 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1176 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1177 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1180 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1184 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1185 nickserv_bake_cookie(cookie
);
1189 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1191 cookie
->hi
->cookie
= NULL
;
1192 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1193 nickserv_free_cookie(cookie
);
1197 nickserv_free_email_addr(void *data
)
1199 handle_info_list_clean(data
);
1204 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1206 struct handle_info_list
*hil
;
1207 /* Remove from old handle_info_list ... */
1208 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1209 handle_info_list_remove(hil
, hi
);
1210 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1211 hi
->email_addr
= NULL
;
1213 /* Add to the new list.. */
1214 if (new_email_addr
) {
1215 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1216 hil
= calloc(1, sizeof(*hil
));
1217 hil
->tag
= strdup(new_email_addr
);
1218 handle_info_list_init(hil
);
1219 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1221 handle_info_list_append(hil
, hi
);
1222 hi
->email_addr
= hil
->tag
;
1226 static NICKSERV_FUNC(cmd_register
)
1228 struct handle_info
*hi
;
1229 const char *email_addr
, *password
;
1230 char syncpass
[MD5_CRYPT_LENGTH
];
1231 int no_auth
, weblink
;
1233 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1234 /* Require the first handle registered to belong to someone +o. */
1235 reply("NSMSG_REQUIRE_OPER");
1239 if (user
->handle_info
) {
1240 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1244 if (IsRegistering(user
)) {
1245 reply("NSMSG_ALREADY_REGISTERING");
1249 if (IsStamped(user
)) {
1250 /* Unauthenticated users might still have been stamped
1251 previously and could therefore have a hidden host;
1252 do not allow them to register a new account. */
1253 reply("NSMSG_STAMPED_REGISTER");
1257 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1259 if (!is_valid_handle(argv
[1])) {
1260 reply("NSMSG_BAD_HANDLE", argv
[1]);
1265 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1266 struct handle_info_list
*hil
;
1269 /* Remember email address. */
1270 email_addr
= argv
[3];
1272 /* Check that the email address looks valid.. */
1273 if (!is_valid_email_addr(email_addr
)) {
1274 reply("NSMSG_BAD_EMAIL_ADDR");
1278 /* .. and that we are allowed to send to it. */
1279 if ((str
= sendmail_prohibited_address(email_addr
))) {
1280 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1284 /* If we do email verify, make sure we don't spam the address. */
1285 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1287 for (nn
=0; nn
<hil
->used
; nn
++) {
1288 if (hil
->list
[nn
]->cookie
) {
1289 reply("NSMSG_EMAIL_UNACTIVATED");
1293 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1294 reply("NSMSG_EMAIL_OVERUSED");
1307 /* Webregister hack - send URL instead of IRC cookie
1310 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1314 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1316 /* Add any masks they should get. */
1317 if (nickserv_conf
.default_hostmask
) {
1318 string_list_append(hi
->masks
, strdup("*@*"));
1320 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1321 if (user
->ip
.s_addr
&& user
->hostname
[strspn(user
->hostname
, "0123456789.")])
1322 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1325 /* If they're the first to register, give them level 1000. */
1326 if (dict_size(nickserv_handle_dict
) == 1) {
1327 hi
->opserv_level
= 1000;
1328 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1331 /* Set their email address. */
1333 nickserv_set_email_addr(hi
, email_addr
);
1335 /* If they need to do email verification, tell them. */
1337 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1339 /* Set registering flag.. */
1340 user
->modes
|= FLAGS_REGISTERING
;
1342 if (nickserv_conf
.sync_log
) {
1343 cryptpass(password
, syncpass
);
1345 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1346 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1349 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1352 /* this wont work if email is required .. */
1353 process_adduser_pending(user
);
1358 static NICKSERV_FUNC(cmd_oregister
)
1361 struct userNode
*settee
;
1362 struct handle_info
*hi
;
1364 NICKSERV_MIN_PARMS(4);
1366 if (!is_valid_handle(argv
[1])) {
1367 reply("NSMSG_BAD_HANDLE", argv
[1]);
1371 if (strchr(argv
[3], '@')) {
1372 mask
= canonicalize_hostmask(strdup(argv
[3]));
1374 settee
= GetUserH(argv
[4]);
1376 reply("MSG_NICK_UNKNOWN", argv
[4]);
1383 } else if ((settee
= GetUserH(argv
[3]))) {
1384 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1386 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1389 if (settee
&& settee
->handle_info
) {
1390 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1394 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1398 string_list_append(hi
->masks
, mask
);
1402 static NICKSERV_FUNC(cmd_handleinfo
)
1405 unsigned int i
, pos
=0, herelen
;
1406 struct userNode
*target
, *next_un
;
1407 struct handle_info
*hi
;
1408 const char *nsmsg_none
;
1411 if (!(hi
= user
->handle_info
)) {
1412 reply("NSMSG_MUST_AUTH");
1415 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1419 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1420 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1422 #ifdef WITH_PROTOCOL_BAHAMUT
1423 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1425 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1428 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1429 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1431 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1434 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1435 if (HANDLE_FLAGGED(hi
, FROZEN
))
1436 reply("NSMSG_HANDLEINFO_VACATION");
1438 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1439 struct do_not_register
*dnr
;
1440 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1441 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1442 if (!oper_outranks(user
, hi
))
1444 } else if (hi
!= user
->handle_info
) {
1445 reply("NSMSG_HANDLEINFO_END");
1449 if (nickserv_conf
.email_enabled
)
1450 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1454 switch (hi
->cookie
->type
) {
1455 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1456 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1457 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1458 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1459 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1465 unsigned long flen
= 1;
1466 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1468 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1469 if (hi
->flags
& 1 << i
)
1470 flags
[flen
++] = handle_flags
[i
];
1472 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1474 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1477 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1478 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1479 || (hi
->opserv_level
> 0)) {
1480 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1484 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1486 if (hi
->last_quit_host
[0])
1487 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1489 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1491 if (nickserv_conf
.disable_nicks
) {
1492 /* nicks disabled; don't show anything about registered nicks */
1493 } else if (hi
->nicks
) {
1494 struct nick_info
*ni
, *next_ni
;
1495 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1496 herelen
= strlen(ni
->nick
);
1497 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1499 goto print_nicks_buff
;
1503 memcpy(buff
+pos
, ni
->nick
, herelen
);
1504 pos
+= herelen
; buff
[pos
++] = ' ';
1508 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1513 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1516 if (hi
->masks
->used
) {
1517 for (i
=0; i
< hi
->masks
->used
; i
++) {
1518 herelen
= strlen(hi
->masks
->list
[i
]);
1519 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1521 goto print_mask_buff
;
1523 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1524 pos
+= herelen
; buff
[pos
++] = ' ';
1525 if (i
+1 == hi
->masks
->used
) {
1528 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1533 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1537 struct userData
*channel
, *next
;
1540 for (channel
= hi
->channels
; channel
; channel
= next
) {
1541 next
= channel
->u_next
;
1542 name
= channel
->channel
->channel
->name
;
1543 herelen
= strlen(name
);
1544 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1546 goto print_chans_buff
;
1548 if (IsUserSuspended(channel
))
1550 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1554 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1559 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1562 for (target
= hi
->users
; target
; target
= next_un
) {
1563 herelen
= strlen(target
->nick
);
1564 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1566 goto print_cnick_buff
;
1568 next_un
= target
->next_authed
;
1570 memcpy(buff
+pos
, target
->nick
, herelen
);
1571 pos
+= herelen
; buff
[pos
++] = ' ';
1575 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1580 reply("NSMSG_HANDLEINFO_END");
1584 static NICKSERV_FUNC(cmd_userinfo
)
1586 struct userNode
*target
;
1588 NICKSERV_MIN_PARMS(2);
1589 if (!(target
= GetUserH(argv
[1]))) {
1590 reply("MSG_NICK_UNKNOWN", argv
[1]);
1593 if (target
->handle_info
)
1594 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1596 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1600 static NICKSERV_FUNC(cmd_nickinfo
)
1602 struct nick_info
*ni
;
1604 NICKSERV_MIN_PARMS(2);
1605 if (!(ni
= get_nick_info(argv
[1]))) {
1606 reply("MSG_NICK_UNKNOWN", argv
[1]);
1609 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1613 static NICKSERV_FUNC(cmd_rename_handle
)
1615 struct handle_info
*hi
;
1616 char msgbuf
[MAXLEN
], *old_handle
;
1619 NICKSERV_MIN_PARMS(3);
1620 if (!(hi
= get_victim_oper(user
, argv
[1])))
1622 if (!is_valid_handle(argv
[2])) {
1623 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1626 if (get_handle_info(argv
[2])) {
1627 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1630 if(strlen(argv
[2]) > 15)
1632 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1636 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1637 hi
->handle
= strdup(argv
[2]);
1638 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1639 for (nn
=0; nn
<rf_list_used
; nn
++)
1640 rf_list
[nn
](hi
, old_handle
);
1641 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1642 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1643 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1648 static failpw_func_t
*failpw_func_list
;
1649 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1652 reg_failpw_func(failpw_func_t func
)
1654 if (failpw_func_used
== failpw_func_size
) {
1655 if (failpw_func_size
) {
1656 failpw_func_size
<<= 1;
1657 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1659 failpw_func_size
= 8;
1660 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1663 failpw_func_list
[failpw_func_used
++] = func
;
1667 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1669 * called by nefariouses enhanced AC login-on-connect code
1672 struct handle_info
*loc_auth(char *handle
, char *password
)
1674 int pw_arg
, used
, maxlogins
;
1677 struct handle_info
*hi
;
1678 struct userNode
*other
;
1680 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1686 /* We don't know the users hostname, or anything because they
1687 * havn't registered yet. So we can only allow LOC if your
1688 * account has *@* as a hostmask.
1690 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1692 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1701 /* Responses from here on look up the language used by the handle they asked about. */
1702 if (!checkpass(password
, hi
->passwd
)) {
1705 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1708 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1709 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1710 if (++used
>= maxlogins
) {
1717 static NICKSERV_FUNC(cmd_auth
)
1719 int pw_arg
, used
, maxlogins
;
1720 struct handle_info
*hi
;
1722 struct userNode
*other
;
1724 if (user
->handle_info
) {
1725 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1728 if (IsStamped(user
)) {
1729 /* Unauthenticated users might still have been stamped
1730 previously and could therefore have a hidden host;
1731 do not allow them to authenticate. */
1732 reply("NSMSG_STAMPED_AUTH");
1736 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1738 } else if (argc
== 2) {
1739 if (nickserv_conf
.disable_nicks
) {
1740 if (!(hi
= get_handle_info(user
->nick
))) {
1741 reply("NSMSG_HANDLE_NOT_FOUND");
1745 /* try to look up their handle from their nick */
1746 struct nick_info
*ni
;
1747 ni
= get_nick_info(user
->nick
);
1749 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1756 reply("MSG_MISSING_PARAMS", argv
[0]);
1757 svccmd_send_help_brief(user
, nickserv
, cmd
);
1761 reply("NSMSG_HANDLE_NOT_FOUND");
1764 /* Responses from here on look up the language used by the handle they asked about. */
1765 passwd
= argv
[pw_arg
];
1766 if (!valid_user_for(user
, hi
)) {
1767 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1768 send_message_type(4, user
, cmd
->parent
->bot
,
1769 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1772 send_message_type(4, user
, cmd
->parent
->bot
,
1773 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1775 argv
[pw_arg
] = "BADMASK";
1778 if (!checkpass(passwd
, hi
->passwd
)) {
1780 send_message_type(4, user
, cmd
->parent
->bot
,
1781 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1782 argv
[pw_arg
] = "BADPASS";
1783 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1784 if (nickserv_conf
.autogag_enabled
) {
1785 if (!user
->auth_policer
.params
) {
1786 user
->auth_policer
.last_req
= now
;
1787 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1789 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1791 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1792 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1793 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1795 argv
[pw_arg
] = "GAGGED";
1800 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1801 send_message_type(4, user
, cmd
->parent
->bot
,
1802 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1803 argv
[pw_arg
] = "SUSPENDED";
1806 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1807 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1808 if (++used
>= maxlogins
) {
1809 send_message_type(4, user
, cmd
->parent
->bot
,
1810 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1812 argv
[pw_arg
] = "MAXLOGINS";
1817 set_user_handle_info(user
, hi
, 1);
1818 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1819 reply("NSMSG_PLEASE_SET_EMAIL");
1820 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1821 reply("NSMSG_WEAK_PASSWORD");
1822 if (hi
->passwd
[0] != '$')
1823 cryptpass(passwd
, hi
->passwd
);
1825 /* If a channel was waiting for this user to auth,
1826 * finish adding them */
1827 process_adduser_pending(user
);
1829 reply("NSMSG_AUTH_SUCCESS");
1832 /* Set +x if autohide is on */
1833 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
1834 irc_umode(user
, "+x");
1836 if(!IsOper(user
)) /* If they arnt already opered.. */
1838 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
1839 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
1841 irc_umode(user
,nickserv_conf
.auto_admin
);
1842 reply("NSMSG_AUTO_OPER_ADMIN");
1844 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
1846 irc_umode(user
,nickserv_conf
.auto_oper
);
1847 reply("NSMSG_AUTO_OPER");
1851 /* Wipe out the pass for the logs */
1852 argv
[pw_arg
] = "****";
1856 static allowauth_func_t
*allowauth_func_list
;
1857 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
1860 reg_allowauth_func(allowauth_func_t func
)
1862 if (allowauth_func_used
== allowauth_func_size
) {
1863 if (allowauth_func_size
) {
1864 allowauth_func_size
<<= 1;
1865 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
1867 allowauth_func_size
= 8;
1868 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
1871 allowauth_func_list
[allowauth_func_used
++] = func
;
1874 static NICKSERV_FUNC(cmd_allowauth
)
1876 struct userNode
*target
;
1877 struct handle_info
*hi
;
1880 NICKSERV_MIN_PARMS(2);
1881 if (!(target
= GetUserH(argv
[1]))) {
1882 reply("MSG_NICK_UNKNOWN", argv
[1]);
1885 if (target
->handle_info
) {
1886 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
1889 if (IsStamped(target
)) {
1890 /* Unauthenticated users might still have been stamped
1891 previously and could therefore have a hidden host;
1892 do not allow them to authenticate to an account. */
1893 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
1898 else if (!(hi
= get_handle_info(argv
[2]))) {
1899 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
1903 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
1904 reply("MSG_USER_OUTRANKED", hi
->handle
);
1907 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
1908 || (hi
->opserv_level
> 0))
1909 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
1910 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
1913 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
1914 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
1915 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
1916 if (nickserv_conf
.email_enabled
)
1917 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
1919 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
1920 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
1922 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
1924 for (n
=0; n
<allowauth_func_used
; n
++)
1925 allowauth_func_list
[n
](user
, target
, hi
);
1929 static NICKSERV_FUNC(cmd_authcookie
)
1931 struct handle_info
*hi
;
1933 NICKSERV_MIN_PARMS(2);
1934 if (user
->handle_info
) {
1935 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1938 if (IsStamped(user
)) {
1939 /* Unauthenticated users might still have been stamped
1940 previously and could therefore have a hidden host;
1941 do not allow them to authenticate to an account. */
1942 reply("NSMSG_STAMPED_AUTHCOOKIE");
1945 if (!(hi
= get_handle_info(argv
[1]))) {
1946 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1949 if (!hi
->email_addr
) {
1950 reply("MSG_SET_EMAIL_ADDR");
1953 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
1957 static NICKSERV_FUNC(cmd_delcookie
)
1959 struct handle_info
*hi
;
1961 hi
= user
->handle_info
;
1963 reply("NSMSG_NO_COOKIE");
1966 switch (hi
->cookie
->type
) {
1969 reply("NSMSG_MUST_TIME_OUT");
1972 nickserv_eat_cookie(hi
->cookie
);
1973 reply("NSMSG_ATE_COOKIE");
1979 static NICKSERV_FUNC(cmd_odelcookie
)
1981 struct handle_info
*hi
;
1983 NICKSERV_MIN_PARMS(2);
1985 if (!(hi
= get_victim_oper(user
, argv
[1])))
1989 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
1993 nickserv_eat_cookie(hi
->cookie
);
1994 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
1999 static NICKSERV_FUNC(cmd_resetpass
)
2001 struct handle_info
*hi
;
2002 char crypted
[MD5_CRYPT_LENGTH
];
2005 NICKSERV_MIN_PARMS(3);
2006 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2010 if (user
->handle_info
) {
2011 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2014 if (IsStamped(user
)) {
2015 /* Unauthenticated users might still have been stamped
2016 previously and could therefore have a hidden host;
2017 do not allow them to activate an account. */
2018 reply("NSMSG_STAMPED_RESETPASS");
2021 if (!(hi
= get_handle_info(argv
[1]))) {
2022 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2025 if (!hi
->email_addr
) {
2026 reply("MSG_SET_EMAIL_ADDR");
2029 cryptpass(argv
[2], crypted
);
2031 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2035 static NICKSERV_FUNC(cmd_cookie
)
2037 struct handle_info
*hi
;
2040 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2043 NICKSERV_MIN_PARMS(3);
2044 if (!(hi
= get_handle_info(argv
[1]))) {
2045 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2051 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2052 reply("NSMSG_HANDLE_SUSPENDED");
2057 reply("NSMSG_NO_COOKIE");
2061 /* Check validity of operation before comparing cookie to
2062 * prohibit guessing by authed users. */
2063 if (user
->handle_info
2064 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2065 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2066 reply("NSMSG_CANNOT_COOKIE");
2070 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2071 reply("NSMSG_BAD_COOKIE");
2075 switch (hi
->cookie
->type
) {
2077 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2078 set_user_handle_info(user
, hi
, 1);
2079 reply("NSMSG_HANDLE_ACTIVATED");
2080 if (nickserv_conf
.sync_log
)
2081 SyncLog("ACCOUNTACC %s", hi
->handle
);
2083 case PASSWORD_CHANGE
:
2084 set_user_handle_info(user
, hi
, 1);
2085 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2086 reply("NSMSG_PASSWORD_CHANGED");
2087 if (nickserv_conf
.sync_log
)
2088 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2091 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2093 * This should only happen if an OREGISTER was sent. Require
2094 * email must be enabled! - SiRVulcaN
2096 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2098 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2099 reply("NSMSG_EMAIL_CHANGED");
2100 if (nickserv_conf
.sync_log
)
2101 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2104 set_user_handle_info(user
, hi
, 1);
2105 reply("NSMSG_AUTH_SUCCESS");
2108 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2109 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2113 nickserv_eat_cookie(hi
->cookie
);
2115 process_adduser_pending(user
);
2120 static NICKSERV_FUNC(cmd_oregnick
) {
2122 struct handle_info
*target
;
2123 struct nick_info
*ni
;
2125 NICKSERV_MIN_PARMS(3);
2126 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2129 if (!is_registerable_nick(nick
)) {
2130 reply("NSMSG_BAD_NICK", nick
);
2133 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2135 reply("NSMSG_NICK_EXISTS", nick
);
2138 register_nick(nick
, target
);
2139 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2143 static NICKSERV_FUNC(cmd_regnick
) {
2145 struct nick_info
*ni
;
2147 if (!is_registerable_nick(user
->nick
)) {
2148 reply("NSMSG_BAD_NICK", user
->nick
);
2151 /* count their nicks, see if it's too many */
2152 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2153 if (n
>= nickserv_conf
.nicks_per_handle
) {
2154 reply("NSMSG_TOO_MANY_NICKS");
2157 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2159 reply("NSMSG_NICK_EXISTS", user
->nick
);
2162 register_nick(user
->nick
, user
->handle_info
);
2163 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2167 static NICKSERV_FUNC(cmd_pass
)
2169 struct handle_info
*hi
;
2170 const char *old_pass
, *new_pass
;
2172 NICKSERV_MIN_PARMS(3);
2173 hi
= user
->handle_info
;
2177 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2178 if (!checkpass(old_pass
, hi
->passwd
)) {
2179 argv
[1] = "BADPASS";
2180 reply("NSMSG_PASSWORD_INVALID");
2183 cryptpass(new_pass
, hi
->passwd
);
2184 if (nickserv_conf
.sync_log
)
2185 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2187 reply("NSMSG_PASS_SUCCESS");
2192 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2195 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2196 for (i
=0; i
<hi
->masks
->used
; i
++) {
2197 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2198 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2203 string_list_append(hi
->masks
, new_mask
);
2204 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2208 static NICKSERV_FUNC(cmd_addmask
)
2211 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2212 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2216 if (!is_gline(argv
[1])) {
2217 reply("NSMSG_MASK_INVALID", argv
[1]);
2220 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2224 static NICKSERV_FUNC(cmd_oaddmask
)
2226 struct handle_info
*hi
;
2228 NICKSERV_MIN_PARMS(3);
2229 if (!(hi
= get_victim_oper(user
, argv
[1])))
2231 return nickserv_addmask(user
, hi
, argv
[2]);
2235 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2238 for (i
=0; i
<hi
->masks
->used
; i
++) {
2239 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2240 char *old_mask
= hi
->masks
->list
[i
];
2241 if (hi
->masks
->used
== 1) {
2242 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2245 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2246 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2251 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2255 static NICKSERV_FUNC(cmd_delmask
)
2257 NICKSERV_MIN_PARMS(2);
2258 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2261 static NICKSERV_FUNC(cmd_odelmask
)
2263 struct handle_info
*hi
;
2264 NICKSERV_MIN_PARMS(3);
2265 if (!(hi
= get_victim_oper(user
, argv
[1])))
2267 return nickserv_delmask(user
, hi
, argv
[2]);
2271 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2272 unsigned int nn
, add
= 1, pos
;
2273 unsigned long added
, removed
, flag
;
2275 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2277 case '+': add
= 1; break;
2278 case '-': add
= 0; break;
2280 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2281 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2284 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2285 /* cheesy avoidance of looking up the flag name.. */
2286 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2289 flag
= 1 << (pos
- 1);
2291 added
|= flag
, removed
&= ~flag
;
2293 removed
|= flag
, added
&= ~flag
;
2298 *premoved
= removed
;
2303 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2305 unsigned long before
, after
, added
, removed
;
2306 struct userNode
*uNode
;
2308 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2309 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2311 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2312 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2314 /* Strip helping flag if they're only a support helper and not
2315 * currently in #support. */
2316 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2317 struct channelList
*schannels
;
2319 schannels
= chanserv_support_channels();
2320 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2321 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2322 if (GetUserMode(schannels
->list
[ii
], uNode
))
2324 if (ii
< schannels
->used
)
2328 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2331 if (after
&& !before
) {
2332 /* Add user to current helper list. */
2333 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2334 userList_append(&curr_helpers
, uNode
);
2335 } else if (!after
&& before
) {
2336 /* Remove user from current helper list. */
2337 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2338 userList_remove(&curr_helpers
, uNode
);
2345 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2349 char *set_display
[] = {
2350 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", /* "STYLE", */
2351 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2352 "FAKEHOST", "TITLE", "EPITHET"
2355 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2356 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_HEADER");
2358 /* Do this so options are presented in a consistent order. */
2359 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2360 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2361 opt(user
, hi
, override
, 0, NULL
);
2362 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_END");
2365 static NICKSERV_FUNC(cmd_set
)
2367 struct handle_info
*hi
;
2370 hi
= user
->handle_info
;
2372 set_list(user
, hi
, 0);
2375 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2376 reply("NSMSG_INVALID_OPTION", argv
[1]);
2379 return opt(user
, hi
, 0, argc
-1, argv
+1);
2382 static NICKSERV_FUNC(cmd_oset
)
2384 struct handle_info
*hi
;
2387 NICKSERV_MIN_PARMS(2);
2389 if (!(hi
= get_victim_oper(user
, argv
[1])))
2393 set_list(user
, hi
, 0);
2397 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2398 reply("NSMSG_INVALID_OPTION", argv
[2]);
2402 return opt(user
, hi
, 1, argc
-2, argv
+2);
2405 static OPTION_FUNC(opt_info
)
2409 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2411 hi
->infoline
= NULL
;
2413 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2417 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2418 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2422 static OPTION_FUNC(opt_width
)
2425 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2427 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2428 hi
->screen_width
= MIN_LINE_SIZE
;
2429 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2430 hi
->screen_width
= MAX_LINE_SIZE
;
2432 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2436 static OPTION_FUNC(opt_tablewidth
)
2439 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2441 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2442 hi
->table_width
= MIN_LINE_SIZE
;
2443 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2444 hi
->table_width
= MAX_LINE_SIZE
;
2446 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2450 static OPTION_FUNC(opt_color
)
2453 if (enabled_string(argv
[1]))
2454 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2455 else if (disabled_string(argv
[1]))
2456 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2458 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2463 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2467 static OPTION_FUNC(opt_privmsg
)
2470 if (enabled_string(argv
[1]))
2471 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2472 else if (disabled_string(argv
[1]))
2473 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2475 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2480 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2484 static OPTION_FUNC(opt_autohide
)
2487 if (enabled_string(argv
[1]))
2488 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2489 else if (disabled_string(argv
[1]))
2490 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2492 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2497 send_message(user
, nickserv
, "NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2502 static OPTION_FUNC(opt_style)
2507 if (!irccasecmp(argv[1], "Zoot"))
2508 hi->userlist_style = HI_STYLE_ZOOT;
2509 else if (!irccasecmp(argv[1], "def"))
2510 hi->userlist_style = HI_STYLE_DEF;
2513 switch (hi->userlist_style) {
2522 send_message(user, nickserv, "NSMSG_SET_STYLE", style);
2527 static OPTION_FUNC(opt_announcements
)
2532 if (enabled_string(argv
[1]))
2533 hi
->announcements
= 'y';
2534 else if (disabled_string(argv
[1]))
2535 hi
->announcements
= 'n';
2536 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2537 hi
->announcements
= '?';
2539 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2544 switch (hi
->announcements
) {
2545 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2546 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2547 case '?': choice
= "default"; break;
2548 default: choice
= "unknown"; break;
2550 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2554 static OPTION_FUNC(opt_password
)
2557 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2562 cryptpass(argv
[1], hi
->passwd
);
2564 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2568 static OPTION_FUNC(opt_flags
)
2571 unsigned int ii
, flen
;
2574 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2579 nickserv_apply_flags(user
, hi
, argv
[1]);
2581 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2582 if (hi
->flags
& (1 << ii
))
2583 flags
[flen
++] = handle_flags
[ii
];
2586 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2588 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2592 static OPTION_FUNC(opt_email
)
2596 if (!is_valid_email_addr(argv
[1])) {
2597 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2600 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2601 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2604 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2605 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2607 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2609 nickserv_set_email_addr(hi
, argv
[1]);
2611 nickserv_eat_cookie(hi
->cookie
);
2612 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2615 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2619 static OPTION_FUNC(opt_maxlogins
)
2621 unsigned char maxlogins
;
2623 maxlogins
= strtoul(argv
[1], NULL
, 0);
2624 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2625 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2628 hi
->maxlogins
= maxlogins
;
2630 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2631 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2635 static OPTION_FUNC(opt_language
)
2637 struct language
*lang
;
2639 lang
= language_find(argv
[1]);
2640 if (irccasecmp(lang
->name
, argv
[1]))
2641 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2642 hi
->language
= lang
;
2644 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2649 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2650 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2652 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2653 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2654 && (user
->handle_info
->opserv_level
< 1000))) {
2655 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2658 if ((user
->handle_info
->opserv_level
< new_level
)
2659 || ((user
->handle_info
->opserv_level
== new_level
)
2660 && (user
->handle_info
->opserv_level
< 1000))) {
2661 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2664 if (user
->handle_info
== target
) {
2665 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2668 if (target
->opserv_level
== new_level
)
2670 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2671 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2672 target
->opserv_level
= new_level
;
2676 static OPTION_FUNC(opt_level
)
2681 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2685 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2686 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2690 static OPTION_FUNC(opt_epithet
)
2692 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2695 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2699 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2703 if ((epithet
[0] == '*') && !epithet
[1])
2706 hi
->epithet
= strdup(epithet
);
2710 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2712 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2716 static OPTION_FUNC(opt_title
)
2720 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2722 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2727 if (strchr(title
, '.')) {
2728 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2731 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2732 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2733 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2738 if (!strcmp(title
, "*")) {
2739 hi
->fakehost
= NULL
;
2741 hi
->fakehost
= malloc(strlen(title
)+2);
2742 hi
->fakehost
[0] = '.';
2743 strcpy(hi
->fakehost
+1, title
);
2746 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2747 title
= hi
->fakehost
+ 1;
2751 title
= user_find_message(user
, "MSG_NONE");
2752 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2756 static OPTION_FUNC(opt_fakehost
)
2760 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2762 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2767 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
2768 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
2772 if (!strcmp(fake
, "*"))
2773 hi
->fakehost
= NULL
;
2775 hi
->fakehost
= strdup(fake
);
2776 fake
= hi
->fakehost
;
2779 fake
= generate_fakehost(hi
);
2781 fake
= user_find_message(user
, "MSG_NONE");
2782 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
2786 static NICKSERV_FUNC(cmd_reclaim
)
2788 struct handle_info
*hi
;
2789 struct nick_info
*ni
;
2790 struct userNode
*victim
;
2792 NICKSERV_MIN_PARMS(2);
2793 hi
= user
->handle_info
;
2794 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
2796 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
2799 if (ni
->owner
!= user
->handle_info
) {
2800 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
2803 victim
= GetUserH(ni
->nick
);
2805 reply("MSG_NICK_UNKNOWN", ni
->nick
);
2808 if (victim
== user
) {
2809 reply("NSMSG_NICK_USER_YOU");
2812 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
2813 switch (nickserv_conf
.reclaim_action
) {
2814 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
2815 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
2816 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
2817 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
2822 static NICKSERV_FUNC(cmd_unregnick
)
2825 struct handle_info
*hi
;
2826 struct nick_info
*ni
;
2828 hi
= user
->handle_info
;
2829 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
2830 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2832 reply("NSMSG_UNKNOWN_NICK", nick
);
2835 if (hi
!= ni
->owner
) {
2836 reply("NSMSG_NOT_YOUR_NICK", nick
);
2839 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2844 static NICKSERV_FUNC(cmd_ounregnick
)
2846 struct nick_info
*ni
;
2848 NICKSERV_MIN_PARMS(2);
2849 if (!(ni
= get_nick_info(argv
[1]))) {
2850 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
2853 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
2854 reply("MSG_USER_OUTRANKED", ni
->nick
);
2857 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2862 static NICKSERV_FUNC(cmd_unregister
)
2864 struct handle_info
*hi
;
2867 NICKSERV_MIN_PARMS(2);
2868 hi
= user
->handle_info
;
2871 if (checkpass(passwd
, hi
->passwd
)) {
2872 nickserv_unregister_handle(hi
, user
);
2875 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
2876 reply("NSMSG_PASSWORD_INVALID");
2881 static NICKSERV_FUNC(cmd_ounregister
)
2883 struct handle_info
*hi
;
2885 NICKSERV_MIN_PARMS(2);
2886 if (!(hi
= get_victim_oper(user
, argv
[1])))
2888 nickserv_unregister_handle(hi
, user
);
2892 static NICKSERV_FUNC(cmd_status
)
2894 if (nickserv_conf
.disable_nicks
) {
2895 reply("NSMSG_GLOBAL_STATS_NONICK",
2896 dict_size(nickserv_handle_dict
));
2898 if (user
->handle_info
) {
2900 struct nick_info
*ni
;
2901 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
2902 reply("NSMSG_HANDLE_STATS", cnt
);
2904 reply("NSMSG_HANDLE_NONE");
2906 reply("NSMSG_GLOBAL_STATS",
2907 dict_size(nickserv_handle_dict
),
2908 dict_size(nickserv_nick_dict
));
2913 static NICKSERV_FUNC(cmd_ghost
)
2915 struct userNode
*target
;
2916 char reason
[MAXLEN
];
2918 NICKSERV_MIN_PARMS(2);
2919 if (!(target
= GetUserH(argv
[1]))) {
2920 reply("MSG_NICK_UNKNOWN", argv
[1]);
2923 if (target
== user
) {
2924 reply("NSMSG_CANNOT_GHOST_SELF");
2927 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
2928 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
2931 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
2932 DelUser(target
, nickserv
, 1, reason
);
2933 reply("NSMSG_GHOST_KILLED", argv
[1]);
2937 static NICKSERV_FUNC(cmd_vacation
)
2939 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
2940 reply("NSMSG_ON_VACATION");
2945 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
2947 struct handle_info
*hi
;
2950 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
2952 #ifdef WITH_PROTOCOL_BAHAMUT
2955 saxdb_start_record(ctx
, iter_key(it
), 0);
2956 if (hi
->announcements
!= '?') {
2957 flags
[0] = hi
->announcements
;
2959 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
2962 struct handle_cookie
*cookie
= hi
->cookie
;
2965 switch (cookie
->type
) {
2966 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
2967 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
2968 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
2969 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
2970 default: type
= NULL
; break;
2973 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
2974 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
2975 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
2977 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
2978 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
2979 saxdb_end_record(ctx
);
2983 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
2985 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
2987 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
2991 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
2992 if (hi
->flags
& (1 << ii
))
2993 flags
[flen
++] = handle_flags
[ii
];
2995 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
2997 #ifdef WITH_PROTOCOL_BAHAMUT
2998 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
3001 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3002 if (hi
->last_quit_host
[0])
3003 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3004 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3005 if (hi
->masks
->used
)
3006 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3008 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3010 struct string_list
*slist
;
3011 struct nick_info
*ni
;
3013 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3014 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3015 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3019 if (hi
->opserv_level
)
3020 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3021 if (hi
->language
!= lang_C
)
3022 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3023 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3024 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3025 if (hi
->screen_width
)
3026 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3027 if (hi
->table_width
)
3028 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3029 flags
[0] = hi
->userlist_style
;
3031 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3032 saxdb_end_record(ctx
);
3037 static handle_merge_func_t
*handle_merge_func_list
;
3038 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3041 reg_handle_merge_func(handle_merge_func_t func
)
3043 if (handle_merge_func_used
== handle_merge_func_size
) {
3044 if (handle_merge_func_size
) {
3045 handle_merge_func_size
<<= 1;
3046 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3048 handle_merge_func_size
= 8;
3049 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3052 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3055 static NICKSERV_FUNC(cmd_merge
)
3057 struct handle_info
*hi_from
, *hi_to
;
3058 struct userNode
*last_user
;
3059 struct userData
*cList
, *cListNext
;
3060 unsigned int ii
, jj
, n
;
3061 char buffer
[MAXLEN
];
3063 NICKSERV_MIN_PARMS(3);
3065 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
3067 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
3069 if (hi_to
== hi_from
) {
3070 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3074 for (n
=0; n
<handle_merge_func_used
; n
++)
3075 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3077 /* Append "from" handle's nicks to "to" handle's nick list. */
3079 struct nick_info
*last_ni
;
3080 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3081 last_ni
->next
= hi_from
->nicks
;
3083 while (hi_from
->nicks
) {
3084 hi_from
->nicks
->owner
= hi_to
;
3085 hi_from
->nicks
= hi_from
->nicks
->next
;
3088 /* Merge the hostmasks. */
3089 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3090 char *mask
= hi_from
->masks
->list
[ii
];
3091 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3092 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3094 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3095 string_list_append(hi_to
->masks
, strdup(mask
));
3098 /* Merge the lists of authed users. */
3100 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3101 last_user
->next_authed
= hi_from
->users
;
3103 hi_to
->users
= hi_from
->users
;
3105 /* Repoint the old "from" handle's users. */
3106 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3107 last_user
->handle_info
= hi_to
;
3109 hi_from
->users
= NULL
;
3111 /* Merge channel userlists. */
3112 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3113 struct userData
*cList2
;
3114 cListNext
= cList
->u_next
;
3115 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3116 if (cList
->channel
== cList2
->channel
)
3118 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3119 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
);
3120 /* keep cList2 in hi_to; remove cList from hi_from */
3121 del_channel_user(cList
, 1);
3124 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
);
3125 /* remove the lower-ranking cList2 from hi_to */
3126 del_channel_user(cList2
, 1);
3128 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3130 /* cList needs to be moved from hi_from to hi_to */
3131 cList
->handle
= hi_to
;
3132 /* Remove from linked list for hi_from */
3133 assert(!cList
->u_prev
);
3134 hi_from
->channels
= cList
->u_next
;
3136 cList
->u_next
->u_prev
= cList
->u_prev
;
3137 /* Add to linked list for hi_to */
3138 cList
->u_prev
= NULL
;
3139 cList
->u_next
= hi_to
->channels
;
3140 if (hi_to
->channels
)
3141 hi_to
->channels
->u_prev
= cList
;
3142 hi_to
->channels
= cList
;
3146 /* Do they get an OpServ level promotion? */
3147 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3148 hi_to
->opserv_level
= hi_from
->opserv_level
;
3150 /* What about last seen time? */
3151 if (hi_from
->lastseen
> hi_to
->lastseen
)
3152 hi_to
->lastseen
= hi_from
->lastseen
;
3154 /* Does a fakehost carry over? (This intentionally doesn't set it
3155 * for users previously attached to hi_to. They'll just have to
3158 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3159 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3161 /* Notify of success. */
3162 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3163 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3164 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3166 /* Unregister the "from" handle. */
3167 nickserv_unregister_handle(hi_from
, NULL
);
3172 struct nickserv_discrim
{
3173 unsigned int limit
, min_level
, max_level
;
3174 unsigned long flags_on
, flags_off
;
3175 time_t min_registered
, max_registered
;
3177 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3178 const char *nickmask
;
3179 const char *hostmask
;
3180 const char *handlemask
;
3181 const char *emailmask
;
3184 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3186 struct discrim_apply_info
{
3187 struct nickserv_discrim
*discrim
;
3188 discrim_search_func func
;
3189 struct userNode
*source
;
3190 unsigned int matched
;
3193 static struct nickserv_discrim
*
3194 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3197 struct nickserv_discrim
*discrim
;
3199 discrim
= malloc(sizeof(*discrim
));
3200 memset(discrim
, 0, sizeof(*discrim
));
3201 discrim
->min_level
= 0;
3202 discrim
->max_level
= ~0;
3203 discrim
->limit
= 50;
3204 discrim
->min_registered
= 0;
3205 discrim
->max_registered
= INT_MAX
;
3206 discrim
->lastseen
= now
;
3208 for (i
=0; i
<argc
; i
++) {
3209 if (i
== argc
- 1) {
3210 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3213 if (!irccasecmp(argv
[i
], "limit")) {
3214 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3215 } else if (!irccasecmp(argv
[i
], "flags")) {
3216 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3217 } else if (!irccasecmp(argv
[i
], "registered")) {
3218 const char *cmp
= argv
[++i
];
3219 if (cmp
[0] == '<') {
3220 if (cmp
[1] == '=') {
3221 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3223 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3225 } else if (cmp
[0] == '=') {
3226 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3227 } else if (cmp
[0] == '>') {
3228 if (cmp
[1] == '=') {
3229 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3231 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3234 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3236 } else if (!irccasecmp(argv
[i
], "seen")) {
3237 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3238 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3239 discrim
->nickmask
= argv
[++i
];
3240 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3242 if (!irccasecmp(argv
[i
], "exact")) {
3243 if (i
== argc
- 1) {
3244 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3247 discrim
->hostmask_type
= EXACT
;
3248 } else if (!irccasecmp(argv
[i
], "subset")) {
3249 if (i
== argc
- 1) {
3250 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3253 discrim
->hostmask_type
= SUBSET
;
3254 } else if (!irccasecmp(argv
[i
], "superset")) {
3255 if (i
== argc
- 1) {
3256 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3259 discrim
->hostmask_type
= SUPERSET
;
3260 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3261 if (i
== argc
- 1) {
3262 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3265 discrim
->hostmask_type
= LASTQUIT
;
3268 discrim
->hostmask_type
= SUPERSET
;
3270 discrim
->hostmask
= argv
[++i
];
3271 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3272 if (!irccasecmp(argv
[++i
], "*")) {
3273 discrim
->handlemask
= 0;
3275 discrim
->handlemask
= argv
[i
];
3277 } else if (!irccasecmp(argv
[i
], "email")) {
3278 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3279 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3281 } else if (!irccasecmp(argv
[++i
], "*")) {
3282 discrim
->emailmask
= 0;
3284 discrim
->emailmask
= argv
[i
];
3286 } else if (!irccasecmp(argv
[i
], "access")) {
3287 const char *cmp
= argv
[++i
];
3288 if (cmp
[0] == '<') {
3289 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3290 if (cmp
[1] == '=') {
3291 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3293 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3295 } else if (cmp
[0] == '=') {
3296 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3297 } else if (cmp
[0] == '>') {
3298 if (cmp
[1] == '=') {
3299 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3301 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3304 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3307 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3318 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3320 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3321 || (discrim
->flags_off
& hi
->flags
)
3322 || (discrim
->min_registered
> hi
->registered
)
3323 || (discrim
->max_registered
< hi
->registered
)
3324 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3325 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3326 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3327 || (discrim
->min_level
> hi
->opserv_level
)
3328 || (discrim
->max_level
< hi
->opserv_level
)) {
3331 if (discrim
->hostmask
) {
3333 for (i
=0; i
<hi
->masks
->used
; i
++) {
3334 const char *mask
= hi
->masks
->list
[i
];
3335 if ((discrim
->hostmask_type
== SUBSET
)
3336 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3337 else if ((discrim
->hostmask_type
== EXACT
)
3338 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3339 else if ((discrim
->hostmask_type
== SUPERSET
)
3340 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3341 else if ((discrim
->hostmask_type
== LASTQUIT
)
3342 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3344 if (i
==hi
->masks
->used
) return 0;
3346 if (discrim
->nickmask
) {
3347 struct nick_info
*nick
= hi
->nicks
;
3349 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3352 if (!nick
) return 0;
3358 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3360 dict_iterator_t it
, next
;
3361 unsigned int matched
;
3363 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3364 it
&& (matched
< discrim
->limit
);
3366 next
= iter_next(it
);
3367 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3368 dsf(source
, iter_data(it
));
3376 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3378 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3382 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3387 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3389 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3390 nickserv_unregister_handle(match
, source
);
3394 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3396 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3397 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3398 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3399 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3400 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3404 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3406 struct handle_info_list hil
;
3407 struct helpfile_table tbl
;
3412 memset(&hil
, 0, sizeof(hil
));
3413 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3414 struct handle_info
*hi
= iter_data(it
);
3415 if (hi
->opserv_level
)
3416 handle_info_list_append(&hil
, hi
);
3418 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3419 tbl
.length
= hil
.used
+ 1;
3421 tbl
.flags
= TABLE_NO_FREE
;
3422 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3423 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3426 for (ii
= 0; ii
< hil
.used
; ) {
3427 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3428 ary
[0] = hil
.list
[ii
]->handle
;
3429 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3430 tbl
.contents
[++ii
] = ary
;
3432 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3433 reply("MSG_MATCH_COUNT", hil
.used
);
3434 for (ii
= 0; ii
< hil
.used
; ii
++)
3435 free(tbl
.contents
[ii
]);
3440 static NICKSERV_FUNC(cmd_search
)
3442 struct nickserv_discrim
*discrim
;
3443 discrim_search_func action
;
3444 struct svccmd
*subcmd
;
3445 unsigned int matches
;
3448 NICKSERV_MIN_PARMS(3);
3449 sprintf(buf
, "search %s", argv
[1]);
3450 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3451 if (!irccasecmp(argv
[1], "print"))
3452 action
= search_print_func
;
3453 else if (!irccasecmp(argv
[1], "count"))
3454 action
= search_count_func
;
3455 else if (!irccasecmp(argv
[1], "unregister"))
3456 action
= search_unregister_func
;
3458 reply("NSMSG_INVALID_ACTION", argv
[1]);
3462 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3465 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3469 if (action
== search_print_func
)
3470 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3471 else if (action
== search_count_func
)
3472 discrim
->limit
= INT_MAX
;
3474 matches
= nickserv_discrim_search(discrim
, action
, user
);
3477 reply("MSG_MATCH_COUNT", matches
);
3479 reply("MSG_NO_MATCHES");
3485 static MODCMD_FUNC(cmd_checkpass
)
3487 struct handle_info
*hi
;
3489 NICKSERV_MIN_PARMS(3);
3490 if (!(hi
= get_handle_info(argv
[1]))) {
3491 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3494 if (checkpass(argv
[2], hi
->passwd
))
3495 reply("CHECKPASS_YES");
3497 reply("CHECKPASS_NO");
3503 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3506 struct string_list
*masks
, *slist
;
3507 struct handle_info
*hi
;
3508 struct userNode
*authed_users
;
3509 struct userData
*channels
;
3510 unsigned long int id
;
3514 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3515 id
= str
? strtoul(str
, NULL
, 0) : 0;
3516 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3518 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3521 if ((hi
= get_handle_info(handle
))) {
3522 authed_users
= hi
->users
;
3523 channels
= hi
->channels
;
3525 hi
->channels
= NULL
;
3526 dict_remove(nickserv_handle_dict
, hi
->handle
);
3528 authed_users
= NULL
;
3531 hi
= register_handle(handle
, str
, id
);
3533 hi
->users
= authed_users
;
3534 while (authed_users
) {
3535 authed_users
->handle_info
= hi
;
3536 authed_users
= authed_users
->next_authed
;
3539 hi
->channels
= channels
;
3540 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3541 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3542 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3543 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3544 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3545 hi
->language
= language_find(str
? str
: "C");
3546 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3547 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3548 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3550 hi
->infoline
= strdup(str
);
3551 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3552 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3553 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3554 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3555 /* We want to read the nicks even if disable_nicks is set. This is so
3556 * that we don't lose the nick data entirely. */
3557 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3559 for (ii
=0; ii
<slist
->used
; ii
++)
3560 register_nick(slist
->list
[ii
], hi
);
3562 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3564 for (ii
=0; str
[ii
]; ii
++)
3565 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3567 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3568 hi
->userlist_style
= str
? str
[0] : HI_STYLE_ZOOT
;
3569 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3570 hi
->announcements
= str
? str
[0] : '?';
3571 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3572 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3573 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3574 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3575 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3577 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3579 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3580 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3582 nickserv_set_email_addr(hi
, str
);
3583 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3585 hi
->epithet
= strdup(str
);
3586 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3588 hi
->fakehost
= strdup(str
);
3589 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3591 const char *data
, *type
, *expires
, *cookie_str
;
3592 struct handle_cookie
*cookie
;
3594 cookie
= calloc(1, sizeof(*cookie
));
3595 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3596 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3597 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3598 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3599 if (!type
|| !expires
|| !cookie_str
) {
3600 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3603 if (!irccasecmp(type
, KEY_ACTIVATION
))
3604 cookie
->type
= ACTIVATION
;
3605 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3606 cookie
->type
= PASSWORD_CHANGE
;
3607 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3608 cookie
->type
= EMAIL_CHANGE
;
3609 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3610 cookie
->type
= ALLOWAUTH
;
3612 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3615 cookie
->expires
= strtoul(expires
, NULL
, 0);
3616 if (cookie
->expires
< now
)
3619 cookie
->data
= strdup(data
);
3620 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3624 nickserv_bake_cookie(cookie
);
3626 nickserv_free_cookie(cookie
);
3631 nickserv_saxdb_read(dict_t db
) {
3633 struct record_data
*rd
;
3635 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3637 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3642 static NICKSERV_FUNC(cmd_mergedb
)
3644 struct timeval start
, stop
;
3647 NICKSERV_MIN_PARMS(2);
3648 gettimeofday(&start
, NULL
);
3649 if (!(db
= parse_database(argv
[1]))) {
3650 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3653 nickserv_saxdb_read(db
);
3655 gettimeofday(&stop
, NULL
);
3656 stop
.tv_sec
-= start
.tv_sec
;
3657 stop
.tv_usec
-= start
.tv_usec
;
3658 if (stop
.tv_usec
< 0) {
3660 stop
.tv_usec
+= 1000000;
3662 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3667 expire_handles(UNUSED_ARG(void *data
))
3669 dict_iterator_t it
, next
;
3671 struct handle_info
*hi
;
3673 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3674 next
= iter_next(it
);
3676 if ((hi
->opserv_level
> 0)
3678 || HANDLE_FLAGGED(hi
, FROZEN
)
3679 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3682 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3683 if ((now
- hi
->lastseen
) > expiry
) {
3684 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3685 nickserv_unregister_handle(hi
, NULL
);
3689 if (nickserv_conf
.handle_expire_frequency
)
3690 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3694 nickserv_load_dict(const char *fname
)
3698 if (!(file
= fopen(fname
, "r"))) {
3699 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
3702 while (!feof(file
)) {
3703 fgets(line
, sizeof(line
), file
);
3706 if (line
[strlen(line
)-1] == '\n')
3707 line
[strlen(line
)-1] = 0;
3708 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
3711 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
3714 static enum reclaim_action
3715 reclaim_action_from_string(const char *str
) {
3717 return RECLAIM_NONE
;
3718 else if (!irccasecmp(str
, "warn"))
3719 return RECLAIM_WARN
;
3720 else if (!irccasecmp(str
, "svsnick"))
3721 return RECLAIM_SVSNICK
;
3722 else if (!irccasecmp(str
, "kill"))
3723 return RECLAIM_KILL
;
3725 return RECLAIM_NONE
;
3729 nickserv_conf_read(void)
3731 dict_t conf_node
, child
;
3735 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
3736 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
3739 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
3741 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
3742 if (nickserv_conf
.valid_handle_regex_set
)
3743 regfree(&nickserv_conf
.valid_handle_regex
);
3745 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3746 nickserv_conf
.valid_handle_regex_set
= !err
;
3747 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
3749 nickserv_conf
.valid_handle_regex_set
= 0;
3751 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
3752 if (nickserv_conf
.valid_nick_regex_set
)
3753 regfree(&nickserv_conf
.valid_nick_regex
);
3755 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3756 nickserv_conf
.valid_nick_regex_set
= !err
;
3757 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
3759 nickserv_conf
.valid_nick_regex_set
= 0;
3761 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
3763 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
3764 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
3765 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
3766 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
3767 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
3768 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
3769 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
3770 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
3771 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
3772 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
3773 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
3774 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
3775 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
3776 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
3777 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
3778 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
3779 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
3780 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
3781 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
3782 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
3783 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
3784 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
3785 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
3786 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
3787 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
3789 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
3790 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
3791 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3793 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3794 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
3795 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3797 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3798 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
3799 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
3800 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
3801 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
3802 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
3803 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
3804 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
3805 if (!nickserv_conf
.disable_nicks
) {
3806 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
3807 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3808 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
3809 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
3810 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
3811 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3812 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
3813 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
3815 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
3816 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
3817 const char *key
= iter_key(it
), *value
;
3821 if (!strncasecmp(key
, "uc_", 3))
3822 flag
= toupper(key
[3]);
3823 else if (!strncasecmp(key
, "lc_", 3))
3824 flag
= tolower(key
[3]);
3828 if ((pos
= handle_inverse_flags
[flag
])) {
3829 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
3830 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
3833 if (nickserv_conf
.weak_password_dict
)
3834 dict_delete(nickserv_conf
.weak_password_dict
);
3835 nickserv_conf
.weak_password_dict
= dict_new();
3836 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
3837 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
3838 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
3839 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
3841 nickserv_load_dict(str
);
3842 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
3843 if (nickserv
&& str
)
3844 NickChange(nickserv
, str
, 0);
3845 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
3846 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
3847 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
3848 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
3849 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
3850 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
3851 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
3852 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
3853 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
3854 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
3855 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
3856 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
3857 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
3858 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
3859 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
3860 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
3861 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
3862 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
3863 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
3864 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
3866 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
3867 nickserv_conf
.auto_oper
= str
? str
: "";
3869 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
3870 nickserv_conf
.auto_admin
= str
? str
: "";
3872 str
= conf_get_data("server/network", RECDB_QSTRING
);
3873 nickserv_conf
.network_name
= str
? str
: "some IRC network";
3874 if (!nickserv_conf
.auth_policer_params
) {
3875 nickserv_conf
.auth_policer_params
= policer_params_new();
3876 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
3877 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
3879 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
3880 for (it
=dict_first(child
); it
; it
=iter_next(it
))
3881 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
3885 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
3887 char newnick
[NICKLEN
+1];
3896 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3898 case RECLAIM_SVSNICK
:
3900 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
3901 } while (GetUserH(newnick
));
3902 irc_svsnick(nickserv
, user
, newnick
);
3905 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
3906 irc_kill(nickserv
, user
, msg
);
3912 nickserv_reclaim_p(void *data
) {
3913 struct userNode
*user
= data
;
3914 struct nick_info
*ni
= get_nick_info(user
->nick
);
3916 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3920 check_user_nick(struct userNode
*user
) {
3921 struct nick_info
*ni
;
3922 user
->modes
&= ~FLAGS_REGNICK
;
3923 if (!(ni
= get_nick_info(user
->nick
)))
3925 if (user
->handle_info
== ni
->owner
) {
3926 user
->modes
|= FLAGS_REGNICK
;
3930 if (nickserv_conf
.warn_nick_owned
)
3931 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3932 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
3934 if (nickserv_conf
.auto_reclaim_delay
)
3935 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
3937 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3942 handle_new_user(struct userNode
*user
)
3944 return check_user_nick(user
);
3948 handle_account(struct userNode
*user
, const char *stamp
)
3950 struct handle_info
*hi
;
3953 #ifdef WITH_PROTOCOL_P10
3954 time_t timestamp
= 0;
3956 colon
= strchr(stamp
, ':');
3957 if(colon
&& colon
[1])
3960 timestamp
= atoi(colon
+1);
3962 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
3963 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
3965 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
);
3969 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
3970 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
3974 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
3977 set_user_handle_info(user
, hi
, 0);
3979 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
3984 handle_nick_change(struct userNode
*user
, const char *old_nick
)
3986 struct handle_info
*hi
;
3988 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
3989 dict_remove(nickserv_allow_auth_dict
, old_nick
);
3990 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
3992 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3993 check_user_nick(user
);
3997 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
3999 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4000 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4001 set_user_handle_info(user
, NULL
, 0);
4004 static struct modcmd
*
4005 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4007 if (min_level
> 0) {
4009 sprintf(buf
, "%u", min_level
);
4010 if (must_be_qualified
) {
4011 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4013 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4015 } else if (min_level
== 0) {
4016 if (must_be_qualified
) {
4017 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4019 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4022 if (must_be_qualified
) {
4023 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4025 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4031 nickserv_db_cleanup(void)
4033 unreg_del_user_func(nickserv_remove_user
);
4034 userList_clean(&curr_helpers
);
4035 policer_params_delete(nickserv_conf
.auth_policer_params
);
4036 dict_delete(nickserv_handle_dict
);
4037 dict_delete(nickserv_nick_dict
);
4038 dict_delete(nickserv_opt_dict
);
4039 dict_delete(nickserv_allow_auth_dict
);
4040 dict_delete(nickserv_email_dict
);
4041 dict_delete(nickserv_id_dict
);
4042 dict_delete(nickserv_conf
.weak_password_dict
);
4043 free(auth_func_list
);
4044 free(unreg_func_list
);
4046 free(allowauth_func_list
);
4047 free(handle_merge_func_list
);
4048 free(failpw_func_list
);
4049 if (nickserv_conf
.valid_handle_regex_set
)
4050 regfree(&nickserv_conf
.valid_handle_regex
);
4051 if (nickserv_conf
.valid_nick_regex_set
)
4052 regfree(&nickserv_conf
.valid_nick_regex
);
4056 init_nickserv(const char *nick
)
4059 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4060 reg_new_user_func(handle_new_user
);
4061 reg_nick_change_func(handle_nick_change
);
4062 reg_del_user_func(nickserv_remove_user
);
4063 reg_account_func(handle_account
);
4065 /* set up handle_inverse_flags */
4066 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4067 for (i
=0; handle_flags
[i
]; i
++) {
4068 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4069 flag_access_levels
[i
] = 0;
4072 conf_register_reload(nickserv_conf_read
);
4073 nickserv_opt_dict
= dict_new();
4074 nickserv_email_dict
= dict_new();
4075 dict_set_free_keys(nickserv_email_dict
, free
);
4076 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4078 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4079 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4080 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4081 * a big pain to disable since its nolonger in the config file. ) -Rubin
4083 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4084 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4085 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4086 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4087 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4088 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4089 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4090 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4091 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4092 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4093 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4094 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4095 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4096 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4097 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4098 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4099 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4100 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4101 if (!nickserv_conf
.disable_nicks
) {
4102 /* nick management commands */
4103 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4104 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4105 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4106 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4107 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4108 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4110 if (nickserv_conf
.email_enabled
) {
4111 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4112 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4113 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4114 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4115 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4116 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4118 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4119 /* miscellaneous commands */
4120 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4121 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4122 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4123 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4124 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4126 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4127 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4128 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4129 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4130 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4131 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
4132 /* dict_insert(nickserv_opt_dict, "STYLE", opt_style); */
4133 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4134 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4135 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4136 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4137 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4138 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4139 if (nickserv_conf
.titlehost_suffix
) {
4140 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4141 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4143 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4144 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4145 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4147 nickserv_handle_dict
= dict_new();
4148 dict_set_free_keys(nickserv_handle_dict
, free
);
4149 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4151 nickserv_id_dict
= dict_new();
4152 dict_set_free_keys(nickserv_id_dict
, free
);
4154 nickserv_nick_dict
= dict_new();
4155 dict_set_free_data(nickserv_nick_dict
, free
);
4157 nickserv_allow_auth_dict
= dict_new();
4159 userList_init(&curr_helpers
);
4162 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4163 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4164 nickserv_service
= service_register(nickserv
);
4166 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4167 reg_exit_func(nickserv_db_cleanup
);
4168 if(nickserv_conf
.handle_expire_frequency
)
4169 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4170 message_register_table(msgtab
);