1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of srvx.
6 * srvx is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 #include "opserv.h" /* for gag_create(), opserv_bad_channel() */
34 #define NICKSERV_CONF_NAME "services/nickserv"
36 #define KEY_DISABLE_NICKS "disable_nicks"
37 #define KEY_DEFAULT_HOSTMASK "default_hostmask"
38 #define KEY_NICKS_PER_HANDLE "nicks_per_handle"
39 #define KEY_NICKS_PER_ACCOUNT "nicks_per_account"
40 #define KEY_PASSWORD_MIN_LENGTH "password_min_length"
41 #define KEY_PASSWORD_MIN_DIGITS "password_min_digits"
42 #define KEY_PASSWORD_MIN_UPPER "password_min_upper"
43 #define KEY_PASSWORD_MIN_LOWER "password_min_lower"
44 #define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
45 #define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
46 #define KEY_VALID_NICK_REGEX "valid_nick_regex"
47 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
48 #define KEY_MODOPER_LEVEL "modoper_level"
49 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
50 #define KEY_SET_TITLE_LEVEL "set_title_level"
51 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
52 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
53 #define KEY_FLAG_LEVELS "flag_levels"
54 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
55 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
56 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
57 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
58 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
59 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
60 #define KEY_DICT_FILE "dict_file"
61 #define KEY_NICK "nick"
62 #define KEY_LANGUAGE "language"
63 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
64 #define KEY_AUTOGAG_DURATION "autogag_duration"
65 #define KEY_AUTH_POLICER "auth_policer"
66 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
67 #define KEY_EMAIL_ENABLED "email_enabled"
68 #define KEY_EMAIL_REQUIRED "email_required"
69 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
70 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
71 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
74 #define KEY_PASSWD "passwd"
75 #define KEY_NICKS "nicks"
76 #define KEY_MASKS "masks"
77 #define KEY_OPSERV_LEVEL "opserv_level"
78 #define KEY_FLAGS "flags"
79 #define KEY_REGISTER_ON "register"
80 #define KEY_LAST_SEEN "lastseen"
81 #define KEY_INFO "info"
82 #define KEY_USERLIST_STYLE "user_style"
83 #define KEY_SCREEN_WIDTH "screen_width"
84 #define KEY_LAST_AUTHED_HOST "last_authed_host"
85 #define KEY_LAST_QUIT_HOST "last_quit_host"
86 #define KEY_EMAIL_ADDR "email_addr"
87 #define KEY_COOKIE "cookie"
88 #define KEY_COOKIE_DATA "data"
89 #define KEY_COOKIE_TYPE "type"
90 #define KEY_COOKIE_EXPIRES "expires"
91 #define KEY_ACTIVATION "activation"
92 #define KEY_PASSWORD_CHANGE "password change"
93 #define KEY_EMAIL_CHANGE "email change"
94 #define KEY_ALLOWAUTH "allowauth"
95 #define KEY_EPITHET "epithet"
96 #define KEY_TABLE_WIDTH "table_width"
97 #define KEY_ANNOUNCEMENTS "announcements"
98 #define KEY_MAXLOGINS "maxlogins"
99 #define KEY_FAKEHOST "fakehost"
101 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
103 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
104 #define OPTION_FUNC(NAME) int NAME(struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
105 typedef OPTION_FUNC(option_func_t
);
107 DEFINE_LIST(handle_info_list
, struct handle_info
*);
109 #define NICKSERV_MIN_PARMS(N) do { \
111 reply("MSG_MISSING_PARAMS", argv[0]); \
112 svccmd_send_help(user, nickserv, cmd); \
116 struct userNode
*nickserv
;
117 struct userList curr_helpers
;
118 const char *handle_flags
= HANDLE_FLAGS
;
120 static struct module *nickserv_module
;
121 static struct service
*nickserv_service
;
122 static struct log_type
*NS_LOG
;
123 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
124 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
125 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
126 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
127 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
128 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
129 static char handle_inverse_flags
[256];
130 static unsigned int flag_access_levels
[32];
131 static const struct message_entry msgtab
[] = {
132 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
133 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu charactors or less."},
134 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
135 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
136 { "NSMSG_PASSWORD_DICTIONARY", "Your password should not be the word \"password\", or any other dictionary word." },
137 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
138 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
139 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
140 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
141 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
142 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
143 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
144 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
145 { "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." },
146 { "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." },
147 { "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." },
148 { "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." },
149 { "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." },
150 { "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." },
151 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
152 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
153 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
154 { "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." },
155 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
156 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
157 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
158 { "NSMSG_EMAIL_OVERUSED", "There are already the maximum number of accounts associated with that email address." },
159 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
160 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
161 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
162 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
163 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
164 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
165 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
166 { "NSMSG_REGISTER_BAD_NICKMASK", "Could not recognize $b%s$b as either a current nick or a hostmask." },
167 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
168 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
169 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
170 { "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)" },
171 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
172 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
173 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
174 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
175 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
176 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
177 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
178 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
179 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
180 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
181 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
182 { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
183 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
184 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
185 { "NSMSG_HANDLEINFO_ON", "Account information for $b%s$b:" },
186 { "NSMSG_HANDLEINFO_ID", " Account ID: %lu" },
187 { "NSMSG_HANDLEINFO_REGGED", " Registered on: %s" },
188 { "NSMSG_HANDLEINFO_LASTSEEN", " Last seen: %s" },
189 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", " Last seen: Right now!" },
190 { "NSMSG_HANDLEINFO_VACATION", " On vacation." },
191 { "NSMSG_HANDLEINFO_EMAIL_ADDR", " Email address: %s" },
192 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", " Cookie: There is currently an activation cookie issued for this account" },
193 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", " Cookie: There is currently a password change cookie issued for this account" },
194 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", " Cookie: There is currently an email change cookie issued for this account" },
195 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", " Cookie: There is currently an allowauth cookie issued for this account" },
196 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", " Cookie: There is currently an unknown cookie issued for this account" },
197 { "NSMSG_HANDLEINFO_INFOLINE", " Infoline: %s" },
198 { "NSMSG_HANDLEINFO_FLAGS", " Flags: %s" },
199 { "NSMSG_HANDLEINFO_EPITHET", " Epithet: %s" },
200 { "NSMSG_HANDLEINFO_FAKEHOST", " Fake host: %s" },
201 { "NSMSG_HANDLEINFO_LAST_HOST", " Last quit hostmask: %s" },
202 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", " Last quit hostmask: Unknown" },
203 { "NSMSG_HANDLEINFO_NICKS", " Nickname(s): %s" },
204 { "NSMSG_HANDLEINFO_MASKS", " Hostmask(s): %s" },
205 { "NSMSG_HANDLEINFO_CHANNELS", " Channel(s): %s" },
206 { "NSMSG_HANDLEINFO_CURRENT", " Current nickname(s): %s" },
207 { "NSMSG_HANDLEINFO_DNR", " Do-not-register (by %s): %s" },
208 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
209 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
210 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
211 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
212 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
213 { "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)." },
214 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
215 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
216 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
217 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
218 { "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." },
219 { "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." },
220 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
221 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
222 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
223 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
224 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
225 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
226 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
227 { "NSMSG_PASS_SUCCESS", "Password changed." },
228 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
229 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
230 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
231 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
232 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
233 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
234 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
235 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
236 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
237 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
238 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
239 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
240 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
241 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
242 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
243 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
244 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
245 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
246 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
247 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
248 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
249 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
250 { "NSMSG_NO_ACCESS", "Access denied." },
251 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
252 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
253 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
254 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
255 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
256 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
257 { "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." },
258 { "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." },
259 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
260 { "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." },
261 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
262 { "NSMSG_SEARCH_MATCH", "Match: %s" },
263 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
264 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
265 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
266 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
267 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
268 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
269 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
270 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
271 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
272 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
273 { "NSMSG_SETTING_LIST", "$b$N account settings:$b" },
274 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
275 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
276 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
277 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
278 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
279 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
280 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
281 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
282 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
283 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
284 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
285 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
286 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
287 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
288 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
289 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
290 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
291 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
292 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
293 { "NSEMAIL_ACTIVATION_BODY",
294 "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"
296 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
297 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
298 "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"
299 "/msg %3$s@%4$s AUTH %5$s your-password\n"
300 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
301 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
303 "If you did NOT request this account, you do not need to do anything.\n"
304 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
305 { "NSEMAIL_ACTIVATION_BODY_WEB",
306 "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"
308 "To verify your email address and complete the account registration, visit the following URL:\n"
309 "http://www.afternet.org/play/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
311 "If you did NOT request this account, you do not need to do anything.\n"
312 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
313 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
314 { "NSEMAIL_PASSWORD_CHANGE_BODY",
315 "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"
316 "To complete the password change, log on to %1$s and type the following command:\n"
317 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
318 "If you did NOT request your password to be changed, you do not need to do anything.\n"
319 "Please contact the %1$s staff if you have questions." },
320 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
321 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
322 "To complete the password change, click the following URL:\n"
323 "http://www.afternet.org/play/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
324 "If you did NOT request your password to be changed, you do not need to do anything.\n"
325 "Please contact the %1$s staff if you have questions." },
326 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
327 { "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." },
328 { "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." },
329 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
330 { "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." },
331 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
332 { "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." },
333 { "CHECKPASS_YES", "Yes." },
334 { "CHECKPASS_NO", "No." },
338 enum reclaim_action
{
344 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
345 static void nickserv_reclaim_p(void *data
);
348 unsigned int disable_nicks
: 1;
349 unsigned int valid_handle_regex_set
: 1;
350 unsigned int valid_nick_regex_set
: 1;
351 unsigned int autogag_enabled
: 1;
352 unsigned int email_enabled
: 1;
353 unsigned int email_required
: 1;
354 unsigned int default_hostmask
: 1;
355 unsigned int warn_nick_owned
: 1;
356 unsigned int warn_clone_auth
: 1;
357 unsigned long nicks_per_handle
;
358 unsigned long password_min_length
;
359 unsigned long password_min_digits
;
360 unsigned long password_min_upper
;
361 unsigned long password_min_lower
;
362 unsigned long db_backup_frequency
;
363 unsigned long handle_expire_frequency
;
364 unsigned long autogag_duration
;
365 unsigned long email_visible_level
;
366 unsigned long cookie_timeout
;
367 unsigned long handle_expire_delay
;
368 unsigned long nochan_handle_expire_delay
;
369 unsigned long modoper_level
;
370 unsigned long set_epithet_level
;
371 unsigned long set_title_level
;
372 unsigned long set_fakehost_level
;
373 unsigned long handles_per_email
;
374 unsigned long email_search_level
;
375 const char *network_name
;
376 const char *titlehost_suffix
;
377 regex_t valid_handle_regex
;
378 regex_t valid_nick_regex
;
379 dict_t weak_password_dict
;
380 struct policer_params
*auth_policer_params
;
381 enum reclaim_action reclaim_action
;
382 enum reclaim_action auto_reclaim_action
;
383 unsigned long auto_reclaim_delay
;
384 unsigned char default_maxlogins
;
385 unsigned char hard_maxlogins
;
388 /* We have 2^32 unique account IDs to use. */
389 unsigned long int highest_id
= 0;
392 canonicalize_hostmask(char *mask
)
394 char *out
= mask
, *temp
;
395 if ((temp
= strchr(mask
, '!'))) {
397 while (*temp
) *out
++ = *temp
++;
403 static struct handle_info
*
404 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
406 struct handle_info
*hi
;
408 #ifdef WITH_PROTOCOL_BAHAMUT
409 char id_base64
[IDLEN
+ 1];
412 /* Assign a unique account ID to the account; note that 0 is
413 an invalid account ID. 1 is therefore the first account ID. */
415 id
= 1 + highest_id
++;
417 /* Note: highest_id is and must always be the highest ID. */
418 if(id
> highest_id
) {
422 inttobase64(id_base64
, id
, IDLEN
);
424 /* Make sure an account with the same ID doesn't exist. If a
425 duplicate is found, log some details and assign a new one.
426 This should be impossible, but it never hurts to expect it. */
427 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
428 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
434 hi
= calloc(1, sizeof(*hi
));
435 hi
->userlist_style
= HI_DEFAULT_STYLE
;
436 hi
->announcements
= '?';
437 hi
->handle
= strdup(handle
);
438 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
440 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
442 #ifdef WITH_PROTOCOL_BAHAMUT
444 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
451 register_nick(const char *nick
, struct handle_info
*owner
)
453 struct nick_info
*ni
;
454 ni
= malloc(sizeof(struct nick_info
));
455 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
457 ni
->next
= owner
->nicks
;
459 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
463 delete_nick(struct nick_info
*ni
)
465 struct nick_info
*last
, *next
;
466 struct userNode
*user
;
467 /* Check to see if we should mark a user as unregistered. */
468 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
469 user
->modes
&= ~FLAGS_REGNICK
;
472 /* Remove ni from the nick_info linked list. */
473 if (ni
== ni
->owner
->nicks
) {
474 ni
->owner
->nicks
= ni
->next
;
476 last
= ni
->owner
->nicks
;
482 last
->next
= next
->next
;
484 dict_remove(nickserv_nick_dict
, ni
->nick
);
487 static unreg_func_t
*unreg_func_list
;
488 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
491 reg_unreg_func(unreg_func_t func
)
493 if (unreg_func_used
== unreg_func_size
) {
494 if (unreg_func_size
) {
495 unreg_func_size
<<= 1;
496 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
499 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
502 unreg_func_list
[unreg_func_used
++] = func
;
506 nickserv_free_cookie(void *data
)
508 struct handle_cookie
*cookie
= data
;
509 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
510 if (cookie
->data
) free(cookie
->data
);
515 free_handle_info(void *vhi
)
517 struct handle_info
*hi
= vhi
;
519 #ifdef WITH_PROTOCOL_BAHAMUT
522 inttobase64(id
, hi
->id
, IDLEN
);
523 dict_remove(nickserv_id_dict
, id
);
526 free_string_list(hi
->masks
);
530 delete_nick(hi
->nicks
);
535 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
536 nickserv_free_cookie(hi
->cookie
);
538 if (hi
->email_addr
) {
539 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
540 handle_info_list_remove(hil
, hi
);
542 dict_remove(nickserv_email_dict
, hi
->email_addr
);
547 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
550 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
)
554 for (n
=0; n
<unreg_func_used
; n
++)
555 unreg_func_list
[n
](notify
, hi
);
557 set_user_handle_info(hi
->users
, NULL
, 0);
559 if (nickserv_conf
.disable_nicks
)
560 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
562 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
564 dict_remove(nickserv_handle_dict
, hi
->handle
);
568 get_handle_info(const char *handle
)
570 return dict_find(nickserv_handle_dict
, handle
, 0);
574 get_nick_info(const char *nick
)
576 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
580 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
585 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
586 mn
= channel
->members
.list
[nn
];
587 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
594 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
595 if (!user
->handle_info
) {
597 send_message(user
, bot
, "MSG_AUTHENTICATE");
601 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
603 send_message(user
, bot
, "NSMSG_NO_ACCESS");
607 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
609 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
613 if (user
->handle_info
->opserv_level
< min_level
) {
615 send_message(user
, bot
, "NSMSG_NO_ACCESS");
623 is_valid_handle(const char *handle
)
625 struct userNode
*user
;
626 /* cant register a juped nick/service nick as handle, to prevent confusion */
627 user
= GetUserH(handle
);
628 if (user
&& IsLocal(user
))
630 /* check against maximum length */
631 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
633 /* for consistency, only allow account names that could be nicks */
634 if (!is_valid_nick(handle
))
636 /* disallow account names that look like bad words */
637 if (opserv_bad_channel(handle
))
639 /* test either regex or containing all valid chars */
640 if (nickserv_conf
.valid_handle_regex_set
) {
641 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
644 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
645 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
649 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
654 is_registerable_nick(const char *nick
)
656 /* make sure it could be used as an account name */
657 if (!is_valid_handle(nick
))
660 if (strlen(nick
) > NICKLEN
)
662 /* test either regex or as valid handle */
663 if (nickserv_conf
.valid_nick_regex_set
) {
664 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
667 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
668 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
676 is_valid_email_addr(const char *email
)
678 return strchr(email
, '@') != NULL
;
682 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
684 if (hi
->email_addr
) {
685 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
686 return hi
->email_addr
;
696 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
698 struct handle_info
*hi
;
699 struct userNode
*target
;
703 if (!(hi
= get_handle_info(++name
))) {
704 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
709 if (!(target
= GetUserH(name
))) {
710 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
713 if (IsLocal(target
)) {
714 if (IsService(target
))
715 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
717 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
720 if (!(hi
= target
->handle_info
)) {
721 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
729 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
730 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
732 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
733 if ((user
->handle_info
->opserv_level
== 1000)
734 || (user
->handle_info
== hi
)
735 || ((user
->handle_info
->opserv_level
== 0)
736 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
737 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
741 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
745 static struct handle_info
*
746 get_victim_oper(struct userNode
*user
, const char *target
)
748 struct handle_info
*hi
;
749 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
751 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
752 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
755 return oper_outranks(user
, hi
) ? hi
: NULL
;
759 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
763 /* If no hostmasks on the account, allow it. */
764 if (!hi
->masks
->used
)
766 /* If any hostmask matches, allow it. */
767 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
768 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
770 /* If they are allowauthed to this account, allow it (removing the aa). */
771 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
772 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
775 /* The user is not allowed to use this account. */
780 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
783 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
785 if (len
< nickserv_conf
.password_min_length
) {
787 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
790 if (!irccasecmp(pass
, handle
)) {
792 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
795 dict_find(nickserv_conf
.weak_password_dict
, pass
, &i
);
798 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
801 for (i
=0; i
<len
; i
++) {
802 if (isdigit(pass
[i
]))
804 if (isupper(pass
[i
]))
806 if (islower(pass
[i
]))
809 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
810 || (cnt_upper
< nickserv_conf
.password_min_upper
)
811 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
813 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
819 static auth_func_t
*auth_func_list
;
820 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
823 reg_auth_func(auth_func_t func
)
825 if (auth_func_used
== auth_func_size
) {
826 if (auth_func_size
) {
827 auth_func_size
<<= 1;
828 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
831 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
834 auth_func_list
[auth_func_used
++] = func
;
837 static handle_rename_func_t
*rf_list
;
838 static unsigned int rf_list_size
, rf_list_used
;
841 reg_handle_rename_func(handle_rename_func_t func
)
843 if (rf_list_used
== rf_list_size
) {
846 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
849 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
852 rf_list
[rf_list_used
++] = func
;
856 generate_fakehost(struct handle_info
*handle
)
858 extern const char *hidden_host_suffix
;
859 static char buffer
[HOSTLEN
+1];
861 if (!handle
->fakehost
) {
862 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
864 } else if (handle
->fakehost
[0] == '.') {
865 /* A leading dot indicates the stored value is actually a title. */
866 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
869 return handle
->fakehost
;
873 apply_fakehost(struct handle_info
*handle
)
875 struct userNode
*target
;
880 fake
= generate_fakehost(handle
);
881 for (target
= handle
->users
; target
; target
= target
->next_authed
)
882 assign_fakehost(target
, fake
, 1);
886 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
889 struct handle_info
*old_info
;
891 /* This can happen if somebody uses COOKIE while authed, or if
892 * they re-auth to their current handle (which is silly, but users
894 if (user
->handle_info
== hi
)
897 if (user
->handle_info
) {
898 struct userNode
*other
;
901 userList_remove(&curr_helpers
, user
);
903 /* remove from next_authed linked list */
904 if (user
->handle_info
->users
== user
) {
905 user
->handle_info
->users
= user
->next_authed
;
907 for (other
= user
->handle_info
->users
;
908 other
->next_authed
!= user
;
909 other
= other
->next_authed
) ;
910 other
->next_authed
= user
->next_authed
;
912 /* if nobody left on old handle, and they're not an oper, remove !god */
913 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
914 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
915 /* record them as being last seen at this time */
916 user
->handle_info
->lastseen
= now
;
917 /* and record their hostmask */
918 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
920 old_info
= user
->handle_info
;
921 user
->handle_info
= hi
;
922 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
923 HANDLE_CLEAR_FLAG(hi
, HELPING
);
924 for (n
=0; n
<auth_func_used
; n
++)
925 auth_func_list
[n
](user
, old_info
);
927 struct nick_info
*ni
;
929 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
930 if (nickserv_conf
.warn_clone_auth
) {
931 struct userNode
*other
;
932 for (other
= hi
->users
; other
; other
= other
->next_authed
)
933 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
935 user
->next_authed
= hi
->users
;
939 userList_append(&curr_helpers
, user
);
941 if (hi
->fakehost
|| old_info
)
945 #ifdef WITH_PROTOCOL_BAHAMUT
946 /* Stamp users with their account ID. */
948 inttobase64(id
, hi
->id
, IDLEN
);
949 #elif WITH_PROTOCOL_P10
950 /* Stamp users with their account name. */
951 char *id
= hi
->handle
;
953 const char *id
= "???";
955 if (!nickserv_conf
.disable_nicks
) {
956 struct nick_info
*ni
;
957 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
958 if (!irccasecmp(user
->nick
, ni
->nick
)) {
959 user
->modes
|= FLAGS_REGNICK
;
964 StampUser(user
, id
, hi
->registered
);
967 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
968 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
970 /* We cannot clear the user's account ID, unfortunately. */
971 user
->next_authed
= NULL
;
975 static struct handle_info
*
976 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
978 struct handle_info
*hi
;
979 struct nick_info
*ni
;
980 char crypted
[MD5_CRYPT_LENGTH
];
982 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
983 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
987 if(strlen(handle
) > 15)
989 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
993 if (!is_secure_password(handle
, passwd
, user
))
996 cryptpass(passwd
, crypted
);
997 hi
= register_handle(handle
, crypted
, 0);
998 hi
->masks
= alloc_string_list(1);
1000 hi
->language
= lang_C
;
1001 hi
->registered
= now
;
1003 hi
->flags
= HI_DEFAULT_FLAGS
;
1004 if (settee
&& !no_auth
)
1005 set_user_handle_info(settee
, hi
, 1);
1008 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1009 else if (nickserv_conf
.disable_nicks
)
1010 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1011 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1012 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1014 register_nick(user
->nick
, hi
);
1015 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1017 if (settee
&& (user
!= settee
))
1018 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1023 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1025 cookie
->hi
->cookie
= cookie
;
1026 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1030 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1032 struct handle_cookie
*cookie
;
1033 char subject
[128], body
[4096], *misc
;
1034 const char *netname
, *fmt
;
1038 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1042 cookie
= calloc(1, sizeof(*cookie
));
1044 cookie
->type
= type
;
1045 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1046 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1047 inttobase64(cookie
->cookie
, rand(), 5);
1048 inttobase64(cookie
->cookie
+5, rand(), 5);
1050 netname
= nickserv_conf
.network_name
;
1053 switch (cookie
->type
) {
1055 hi
->passwd
[0] = 0; /* invalidate password */
1056 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1057 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1058 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1061 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1063 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1065 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1068 case PASSWORD_CHANGE
:
1069 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1070 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1071 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1073 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1075 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1076 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1079 misc
= hi
->email_addr
;
1080 hi
->email_addr
= cookie
->data
;
1082 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1083 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1084 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1085 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1086 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1087 sendmail(nickserv
, hi
, subject
, body
, 1);
1088 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1089 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1091 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1092 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1093 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1094 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1095 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1096 sendmail(nickserv
, hi
, subject
, body
, 1);
1099 hi
->email_addr
= misc
;
1102 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1103 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1104 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1105 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1106 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1109 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1113 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1114 nickserv_bake_cookie(cookie
);
1118 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1120 cookie
->hi
->cookie
= NULL
;
1121 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1122 nickserv_free_cookie(cookie
);
1126 nickserv_free_email_addr(void *data
)
1128 handle_info_list_clean(data
);
1133 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1135 struct handle_info_list
*hil
;
1136 /* Remove from old handle_info_list ... */
1137 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1138 handle_info_list_remove(hil
, hi
);
1139 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1140 hi
->email_addr
= NULL
;
1142 /* Add to the new list.. */
1143 if (new_email_addr
) {
1144 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1145 hil
= calloc(1, sizeof(*hil
));
1146 hil
->tag
= strdup(new_email_addr
);
1147 handle_info_list_init(hil
);
1148 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1150 handle_info_list_append(hil
, hi
);
1151 hi
->email_addr
= hil
->tag
;
1155 static NICKSERV_FUNC(cmd_register
)
1157 struct handle_info
*hi
;
1158 const char *email_addr
, *password
;
1159 int no_auth
, weblink
;
1161 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1162 /* Require the first handle registered to belong to someone +o. */
1163 reply("NSMSG_REQUIRE_OPER");
1167 if (user
->handle_info
) {
1168 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1172 if (IsRegistering(user
)) {
1173 reply("NSMSG_ALREADY_REGISTERING");
1177 if (IsStamped(user
)) {
1178 /* Unauthenticated users might still have been stamped
1179 previously and could therefore have a hidden host;
1180 do not allow them to register a new account. */
1181 reply("NSMSG_STAMPED_REGISTER");
1185 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1187 if (!is_valid_handle(argv
[1])) {
1188 reply("NSMSG_BAD_HANDLE", argv
[1]);
1193 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1194 struct handle_info_list
*hil
;
1197 /* Remember email address. */
1198 email_addr
= argv
[3];
1200 /* Check that the email address looks valid.. */
1201 if (!is_valid_email_addr(email_addr
)) {
1202 reply("NSMSG_BAD_EMAIL_ADDR");
1206 /* .. and that we are allowed to send to it. */
1207 if ((str
= sendmail_prohibited_address(email_addr
))) {
1208 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1212 /* If we do email verify, make sure we don't spam the address. */
1213 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1215 for (nn
=0; nn
<hil
->used
; nn
++) {
1216 if (hil
->list
[nn
]->cookie
) {
1217 reply("NSMSG_EMAIL_UNACTIVATED");
1221 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1222 reply("NSMSG_EMAIL_OVERUSED");
1235 /* Webregister hack - send URL instead of IRC cookie
1238 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1242 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1244 /* Add any masks they should get. */
1245 if (nickserv_conf
.default_hostmask
) {
1246 string_list_append(hi
->masks
, strdup("*@*"));
1248 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1249 if (user
->ip
.s_addr
&& user
->hostname
[strspn(user
->hostname
, "0123456789.")])
1250 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1253 /* If they're the first to register, give them level 1000. */
1254 if (dict_size(nickserv_handle_dict
) == 1) {
1255 hi
->opserv_level
= 1000;
1256 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1259 /* Set their email address. */
1261 nickserv_set_email_addr(hi
, email_addr
);
1263 /* If they need to do email verification, tell them. */
1265 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1267 /* Set registering flag.. */
1268 user
->modes
|= FLAGS_REGISTERING
;
1273 static NICKSERV_FUNC(cmd_oregister
)
1276 struct userNode
*settee
;
1277 struct handle_info
*hi
;
1279 NICKSERV_MIN_PARMS(4);
1281 if (!is_valid_handle(argv
[1])) {
1282 reply("NSMSG_BAD_HANDLE", argv
[1]);
1286 if (strchr(argv
[3], '@')) {
1287 mask
= canonicalize_hostmask(strdup(argv
[3]));
1289 settee
= GetUserH(argv
[4]);
1291 reply("MSG_NICK_UNKNOWN", argv
[4]);
1298 } else if ((settee
= GetUserH(argv
[3]))) {
1299 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1301 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1304 if (settee
&& settee
->handle_info
) {
1305 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1309 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1313 string_list_append(hi
->masks
, mask
);
1317 static NICKSERV_FUNC(cmd_handleinfo
)
1320 unsigned int i
, pos
=0, herelen
;
1321 struct userNode
*target
, *next_un
;
1322 struct handle_info
*hi
;
1323 const char *nsmsg_none
;
1326 if (!(hi
= user
->handle_info
)) {
1327 reply("NSMSG_MUST_AUTH");
1330 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1334 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1335 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1336 #ifdef WITH_PROTOCOL_BAHAMUT
1337 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1339 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1342 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1343 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1345 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1348 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1349 if (HANDLE_FLAGGED(hi
, FROZEN
))
1350 reply("NSMSG_HANDLEINFO_VACATION");
1352 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1353 struct do_not_register
*dnr
;
1354 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1355 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1356 if (!oper_outranks(user
, hi
))
1358 } else if (hi
!= user
->handle_info
)
1361 if (nickserv_conf
.email_enabled
)
1362 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1366 switch (hi
->cookie
->type
) {
1367 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1368 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1369 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1370 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1371 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1377 unsigned long flen
= 1;
1378 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1380 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1381 if (hi
->flags
& 1 << i
)
1382 flags
[flen
++] = handle_flags
[i
];
1384 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1386 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1389 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1390 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1391 || (hi
->opserv_level
> 0)) {
1392 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1396 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1398 if (hi
->last_quit_host
[0])
1399 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1401 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1403 if (nickserv_conf
.disable_nicks
) {
1404 /* nicks disabled; don't show anything about registered nicks */
1405 } else if (hi
->nicks
) {
1406 struct nick_info
*ni
, *next_ni
;
1407 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1408 herelen
= strlen(ni
->nick
);
1409 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1411 goto print_nicks_buff
;
1415 memcpy(buff
+pos
, ni
->nick
, herelen
);
1416 pos
+= herelen
; buff
[pos
++] = ' ';
1420 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1425 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1428 if (hi
->masks
->used
) {
1429 for (i
=0; i
< hi
->masks
->used
; i
++) {
1430 herelen
= strlen(hi
->masks
->list
[i
]);
1431 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1433 goto print_mask_buff
;
1435 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1436 pos
+= herelen
; buff
[pos
++] = ' ';
1437 if (i
+1 == hi
->masks
->used
) {
1440 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1445 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1449 struct userData
*channel
, *next
;
1452 for (channel
= hi
->channels
; channel
; channel
= next
) {
1453 next
= channel
->u_next
;
1454 name
= channel
->channel
->channel
->name
;
1455 herelen
= strlen(name
);
1456 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1458 goto print_chans_buff
;
1460 if (IsUserSuspended(channel
))
1462 pos
+= sprintf(buff
+pos
, "%d:%s ", channel
->access
, name
);
1466 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1471 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1474 for (target
= hi
->users
; target
; target
= next_un
) {
1475 herelen
= strlen(target
->nick
);
1476 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1478 goto print_cnick_buff
;
1480 next_un
= target
->next_authed
;
1482 memcpy(buff
+pos
, target
->nick
, herelen
);
1483 pos
+= herelen
; buff
[pos
++] = ' ';
1487 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1495 static NICKSERV_FUNC(cmd_userinfo
)
1497 struct userNode
*target
;
1499 NICKSERV_MIN_PARMS(2);
1500 if (!(target
= GetUserH(argv
[1]))) {
1501 reply("MSG_NICK_UNKNOWN", argv
[1]);
1504 if (target
->handle_info
)
1505 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1507 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1511 static NICKSERV_FUNC(cmd_nickinfo
)
1513 struct nick_info
*ni
;
1515 NICKSERV_MIN_PARMS(2);
1516 if (!(ni
= get_nick_info(argv
[1]))) {
1517 reply("MSG_NICK_UNKNOWN", argv
[1]);
1520 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1524 static NICKSERV_FUNC(cmd_rename_handle
)
1526 struct handle_info
*hi
;
1527 char msgbuf
[MAXLEN
], *old_handle
;
1530 NICKSERV_MIN_PARMS(3);
1531 if (!(hi
= get_victim_oper(user
, argv
[1])))
1533 if (!is_valid_handle(argv
[2])) {
1534 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1537 if (get_handle_info(argv
[2])) {
1538 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1541 if(strlen(argv
[2]) > 15)
1543 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1547 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1548 hi
->handle
= strdup(argv
[2]);
1549 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1550 for (nn
=0; nn
<rf_list_used
; nn
++)
1551 rf_list
[nn
](hi
, old_handle
);
1552 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1553 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1554 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1559 static failpw_func_t
*failpw_func_list
;
1560 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1563 reg_failpw_func(failpw_func_t func
)
1565 if (failpw_func_used
== failpw_func_size
) {
1566 if (failpw_func_size
) {
1567 failpw_func_size
<<= 1;
1568 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1570 failpw_func_size
= 8;
1571 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1574 failpw_func_list
[failpw_func_used
++] = func
;
1578 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1580 * called by nefariouses enhanced AC login-on-connect code
1583 struct handle_info
*loc_auth(char *handle
, char *password
)
1585 int pw_arg
, used
, maxlogins
;
1588 struct handle_info
*hi
;
1589 struct userNode
*other
;
1591 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1597 /* We don't know the users hostname, or anything because they
1598 * havn't registered yet. So we can only allow LOC if your
1599 * account has *@* as a hostmask.
1601 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1603 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1612 /* Responses from here on look up the language used by the handle they asked about. */
1613 if (!checkpass(password
, hi
->passwd
)) {
1616 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1619 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1620 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1621 if (++used
>= maxlogins
) {
1628 static NICKSERV_FUNC(cmd_auth
)
1630 int pw_arg
, used
, maxlogins
;
1631 struct handle_info
*hi
;
1633 struct userNode
*other
;
1635 if (user
->handle_info
) {
1636 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1639 if (IsStamped(user
)) {
1640 /* Unauthenticated users might still have been stamped
1641 previously and could therefore have a hidden host;
1642 do not allow them to authenticate. */
1643 reply("NSMSG_STAMPED_AUTH");
1647 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1649 } else if (argc
== 2) {
1650 if (nickserv_conf
.disable_nicks
) {
1651 if (!(hi
= get_handle_info(user
->nick
))) {
1652 reply("NSMSG_HANDLE_NOT_FOUND");
1656 /* try to look up their handle from their nick */
1657 struct nick_info
*ni
;
1658 ni
= get_nick_info(user
->nick
);
1660 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1667 reply("MSG_MISSING_PARAMS", argv
[0]);
1668 svccmd_send_help(user
, nickserv
, cmd
);
1672 reply("NSMSG_HANDLE_NOT_FOUND");
1675 /* Responses from here on look up the language used by the handle they asked about. */
1676 passwd
= argv
[pw_arg
];
1677 if (!valid_user_for(user
, hi
)) {
1678 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1679 send_message_type(4, user
, cmd
->parent
->bot
,
1680 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1683 send_message_type(4, user
, cmd
->parent
->bot
,
1684 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1686 argv
[pw_arg
] = "BADMASK";
1689 if (!checkpass(passwd
, hi
->passwd
)) {
1691 send_message_type(4, user
, cmd
->parent
->bot
,
1692 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1693 argv
[pw_arg
] = "BADPASS";
1694 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1695 if (nickserv_conf
.autogag_enabled
) {
1696 if (!user
->auth_policer
.params
) {
1697 user
->auth_policer
.last_req
= now
;
1698 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1700 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1702 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1703 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1704 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1706 argv
[pw_arg
] = "GAGGED";
1711 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1712 send_message_type(4, user
, cmd
->parent
->bot
,
1713 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1714 argv
[pw_arg
] = "SUSPENDED";
1717 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1718 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1719 if (++used
>= maxlogins
) {
1720 send_message_type(4, user
, cmd
->parent
->bot
,
1721 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1723 argv
[pw_arg
] = "MAXLOGINS";
1728 set_user_handle_info(user
, hi
, 1);
1729 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1730 reply("NSMSG_PLEASE_SET_EMAIL");
1731 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1732 reply("NSMSG_WEAK_PASSWORD");
1733 if (hi
->passwd
[0] != '$')
1734 cryptpass(passwd
, hi
->passwd
);
1735 reply("NSMSG_AUTH_SUCCESS");
1736 argv
[pw_arg
] = "****";
1740 static allowauth_func_t
*allowauth_func_list
;
1741 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
1744 reg_allowauth_func(allowauth_func_t func
)
1746 if (allowauth_func_used
== allowauth_func_size
) {
1747 if (allowauth_func_size
) {
1748 allowauth_func_size
<<= 1;
1749 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
1751 allowauth_func_size
= 8;
1752 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
1755 allowauth_func_list
[allowauth_func_used
++] = func
;
1758 static NICKSERV_FUNC(cmd_allowauth
)
1760 struct userNode
*target
;
1761 struct handle_info
*hi
;
1764 NICKSERV_MIN_PARMS(2);
1765 if (!(target
= GetUserH(argv
[1]))) {
1766 reply("MSG_NICK_UNKNOWN", argv
[1]);
1769 if (target
->handle_info
) {
1770 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
1773 if (IsStamped(target
)) {
1774 /* Unauthenticated users might still have been stamped
1775 previously and could therefore have a hidden host;
1776 do not allow them to authenticate to an account. */
1777 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
1782 else if (!(hi
= get_handle_info(argv
[2]))) {
1783 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
1787 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
1788 reply("MSG_USER_OUTRANKED", hi
->handle
);
1791 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
1792 || (hi
->opserv_level
> 0))
1793 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
1794 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
1797 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
1798 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
1799 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
1800 if (nickserv_conf
.email_enabled
)
1801 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
1803 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
1804 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
1806 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
1808 for (n
=0; n
<allowauth_func_used
; n
++)
1809 allowauth_func_list
[n
](user
, target
, hi
);
1813 static NICKSERV_FUNC(cmd_authcookie
)
1815 struct handle_info
*hi
;
1817 NICKSERV_MIN_PARMS(2);
1818 if (user
->handle_info
) {
1819 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1822 if (IsStamped(user
)) {
1823 /* Unauthenticated users might still have been stamped
1824 previously and could therefore have a hidden host;
1825 do not allow them to authenticate to an account. */
1826 reply("NSMSG_STAMPED_AUTHCOOKIE");
1829 if (!(hi
= get_handle_info(argv
[1]))) {
1830 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1833 if (!hi
->email_addr
) {
1834 reply("MSG_SET_EMAIL_ADDR");
1837 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
1841 static NICKSERV_FUNC(cmd_delcookie
)
1843 struct handle_info
*hi
;
1845 hi
= user
->handle_info
;
1847 reply("NSMSG_NO_COOKIE");
1850 switch (hi
->cookie
->type
) {
1853 reply("NSMSG_MUST_TIME_OUT");
1856 nickserv_eat_cookie(hi
->cookie
);
1857 reply("NSMSG_ATE_COOKIE");
1863 static NICKSERV_FUNC(cmd_resetpass
)
1865 struct handle_info
*hi
;
1866 char crypted
[MD5_CRYPT_LENGTH
];
1869 NICKSERV_MIN_PARMS(3);
1870 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
1874 if (user
->handle_info
) {
1875 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1878 if (IsStamped(user
)) {
1879 /* Unauthenticated users might still have been stamped
1880 previously and could therefore have a hidden host;
1881 do not allow them to activate an account. */
1882 reply("NSMSG_STAMPED_RESETPASS");
1885 if (!(hi
= get_handle_info(argv
[1]))) {
1886 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1889 if (!hi
->email_addr
) {
1890 reply("MSG_SET_EMAIL_ADDR");
1893 cryptpass(argv
[2], crypted
);
1895 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
1899 static NICKSERV_FUNC(cmd_cookie
)
1901 struct handle_info
*hi
;
1904 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
1907 NICKSERV_MIN_PARMS(3);
1908 if (!(hi
= get_handle_info(argv
[1]))) {
1909 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1915 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1916 reply("NSMSG_HANDLE_SUSPENDED");
1921 reply("NSMSG_NO_COOKIE");
1925 /* Check validity of operation before comparing cookie to
1926 * prohibit guessing by authed users. */
1927 if (user
->handle_info
1928 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
1929 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
1930 reply("NSMSG_CANNOT_COOKIE");
1934 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
1935 reply("NSMSG_BAD_COOKIE");
1939 switch (hi
->cookie
->type
) {
1941 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
1942 set_user_handle_info(user
, hi
, 1);
1943 reply("NSMSG_HANDLE_ACTIVATED");
1945 case PASSWORD_CHANGE
:
1946 set_user_handle_info(user
, hi
, 1);
1947 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
1948 reply("NSMSG_PASSWORD_CHANGED");
1951 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
1952 reply("NSMSG_EMAIL_CHANGED");
1955 set_user_handle_info(user
, hi
, 1);
1956 reply("NSMSG_AUTH_SUCCESS");
1959 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
1960 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
1964 nickserv_eat_cookie(hi
->cookie
);
1969 static NICKSERV_FUNC(cmd_oregnick
) {
1971 struct handle_info
*target
;
1972 struct nick_info
*ni
;
1974 NICKSERV_MIN_PARMS(3);
1975 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
1978 if (!is_registerable_nick(nick
)) {
1979 reply("NSMSG_BAD_NICK", nick
);
1982 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
1984 reply("NSMSG_NICK_EXISTS", nick
);
1987 register_nick(nick
, target
);
1988 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
1992 static NICKSERV_FUNC(cmd_regnick
) {
1994 struct nick_info
*ni
;
1996 if (!is_registerable_nick(user
->nick
)) {
1997 reply("NSMSG_BAD_NICK", user
->nick
);
2000 /* count their nicks, see if it's too many */
2001 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2002 if (n
>= nickserv_conf
.nicks_per_handle
) {
2003 reply("NSMSG_TOO_MANY_NICKS");
2006 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2008 reply("NSMSG_NICK_EXISTS", user
->nick
);
2011 register_nick(user
->nick
, user
->handle_info
);
2012 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2016 static NICKSERV_FUNC(cmd_pass
)
2018 struct handle_info
*hi
;
2019 const char *old_pass
, *new_pass
;
2021 NICKSERV_MIN_PARMS(3);
2022 hi
= user
->handle_info
;
2026 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2027 if (!checkpass(old_pass
, hi
->passwd
)) {
2028 argv
[1] = "BADPASS";
2029 reply("NSMSG_PASSWORD_INVALID");
2032 cryptpass(new_pass
, hi
->passwd
);
2034 reply("NSMSG_PASS_SUCCESS");
2039 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2042 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2043 for (i
=0; i
<hi
->masks
->used
; i
++) {
2044 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2045 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2050 string_list_append(hi
->masks
, new_mask
);
2051 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2055 static NICKSERV_FUNC(cmd_addmask
)
2058 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2059 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2063 if (!is_gline(argv
[1])) {
2064 reply("NSMSG_MASK_INVALID", argv
[1]);
2067 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2071 static NICKSERV_FUNC(cmd_oaddmask
)
2073 struct handle_info
*hi
;
2075 NICKSERV_MIN_PARMS(3);
2076 if (!(hi
= get_victim_oper(user
, argv
[1])))
2078 return nickserv_addmask(user
, hi
, argv
[2]);
2082 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2085 for (i
=0; i
<hi
->masks
->used
; i
++) {
2086 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2087 char *old_mask
= hi
->masks
->list
[i
];
2088 if (hi
->masks
->used
== 1) {
2089 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2092 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2093 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2098 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2102 static NICKSERV_FUNC(cmd_delmask
)
2104 NICKSERV_MIN_PARMS(2);
2105 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2108 static NICKSERV_FUNC(cmd_odelmask
)
2110 struct handle_info
*hi
;
2111 NICKSERV_MIN_PARMS(3);
2112 if (!(hi
= get_victim_oper(user
, argv
[1])))
2114 return nickserv_delmask(user
, hi
, argv
[2]);
2118 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2119 unsigned int nn
, add
= 1, pos
;
2120 unsigned long added
, removed
, flag
;
2122 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2124 case '+': add
= 1; break;
2125 case '-': add
= 0; break;
2127 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2128 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2131 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2132 /* cheesy avoidance of looking up the flag name.. */
2133 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2136 flag
= 1 << (pos
- 1);
2138 added
|= flag
, removed
&= ~flag
;
2140 removed
|= flag
, added
&= ~flag
;
2145 *premoved
= removed
;
2150 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2152 unsigned long before
, after
, added
, removed
;
2153 struct userNode
*uNode
;
2155 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2156 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2158 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2159 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2161 /* Strip helping flag if they're only a support helper and not
2162 * currently in #support. */
2163 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2164 struct channelList
*schannels
;
2166 schannels
= chanserv_support_channels();
2167 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2168 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2169 if (GetUserMode(schannels
->list
[ii
], uNode
))
2171 if (ii
< schannels
->used
)
2175 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2178 if (after
&& !before
) {
2179 /* Add user to current helper list. */
2180 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2181 userList_append(&curr_helpers
, uNode
);
2182 } else if (!after
&& before
) {
2183 /* Remove user from current helper list. */
2184 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2185 userList_remove(&curr_helpers
, uNode
);
2192 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2196 char *set_display
[] = {
2197 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2198 "EMAIL", "ANNOUNCEMENTS", "MAXLOGINS", "LANGUAGE"
2201 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2203 /* Do this so options are presented in a consistent order. */
2204 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2205 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2206 opt(user
, hi
, override
, 0, NULL
);
2209 static NICKSERV_FUNC(cmd_set
)
2211 struct handle_info
*hi
;
2214 hi
= user
->handle_info
;
2216 set_list(user
, hi
, 0);
2219 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2220 reply("NSMSG_INVALID_OPTION", argv
[1]);
2223 return opt(user
, hi
, 0, argc
-1, argv
+1);
2226 static NICKSERV_FUNC(cmd_oset
)
2228 struct handle_info
*hi
;
2231 NICKSERV_MIN_PARMS(2);
2233 if (!(hi
= get_victim_oper(user
, argv
[1])))
2237 set_list(user
, hi
, 0);
2241 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2242 reply("NSMSG_INVALID_OPTION", argv
[2]);
2246 return opt(user
, hi
, 1, argc
-2, argv
+2);
2249 static OPTION_FUNC(opt_info
)
2253 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2255 hi
->infoline
= NULL
;
2257 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2261 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2262 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2266 static OPTION_FUNC(opt_width
)
2269 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2271 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2272 hi
->screen_width
= MIN_LINE_SIZE
;
2273 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2274 hi
->screen_width
= MAX_LINE_SIZE
;
2276 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2280 static OPTION_FUNC(opt_tablewidth
)
2283 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2285 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2286 hi
->table_width
= MIN_LINE_SIZE
;
2287 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2288 hi
->table_width
= MAX_LINE_SIZE
;
2290 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2294 static OPTION_FUNC(opt_color
)
2297 if (enabled_string(argv
[1]))
2298 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2299 else if (disabled_string(argv
[1]))
2300 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2302 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2307 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2311 static OPTION_FUNC(opt_privmsg
)
2314 if (enabled_string(argv
[1]))
2315 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2316 else if (disabled_string(argv
[1]))
2317 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2319 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2324 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2328 static OPTION_FUNC(opt_style
)
2333 if (!irccasecmp(argv
[1], "Zoot"))
2334 hi
->userlist_style
= HI_STYLE_ZOOT
;
2335 else if (!irccasecmp(argv
[1], "def"))
2336 hi
->userlist_style
= HI_STYLE_DEF
;
2339 switch (hi
->userlist_style
) {
2348 send_message(user
, nickserv
, "NSMSG_SET_STYLE", style
);
2352 static OPTION_FUNC(opt_announcements
)
2357 if (enabled_string(argv
[1]))
2358 hi
->announcements
= 'y';
2359 else if (disabled_string(argv
[1]))
2360 hi
->announcements
= 'n';
2361 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2362 hi
->announcements
= '?';
2364 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2369 switch (hi
->announcements
) {
2370 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2371 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2372 case '?': choice
= "default"; break;
2373 default: choice
= "unknown"; break;
2375 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2379 static OPTION_FUNC(opt_password
)
2382 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2387 cryptpass(argv
[1], hi
->passwd
);
2389 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2393 static OPTION_FUNC(opt_flags
)
2396 unsigned int ii
, flen
;
2399 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2404 nickserv_apply_flags(user
, hi
, argv
[1]);
2406 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2407 if (hi
->flags
& (1 << ii
))
2408 flags
[flen
++] = handle_flags
[ii
];
2411 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2413 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2417 static OPTION_FUNC(opt_email
)
2421 if (!is_valid_email_addr(argv
[1])) {
2422 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2425 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2426 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2429 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2430 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2432 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2434 nickserv_set_email_addr(hi
, argv
[1]);
2436 nickserv_eat_cookie(hi
->cookie
);
2437 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2440 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2444 static OPTION_FUNC(opt_maxlogins
)
2446 unsigned char maxlogins
;
2448 maxlogins
= strtoul(argv
[1], NULL
, 0);
2449 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2450 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2453 hi
->maxlogins
= maxlogins
;
2455 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2456 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2460 static OPTION_FUNC(opt_language
)
2462 struct language
*lang
;
2464 lang
= language_find(argv
[1]);
2465 if (irccasecmp(lang
->name
, argv
[1]))
2466 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2467 hi
->language
= lang
;
2469 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2474 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2475 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2477 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2478 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2479 && (user
->handle_info
->opserv_level
< 1000))) {
2480 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2483 if ((user
->handle_info
->opserv_level
< new_level
)
2484 || ((user
->handle_info
->opserv_level
== new_level
)
2485 && (user
->handle_info
->opserv_level
< 1000))) {
2486 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2489 if (user
->handle_info
== target
) {
2490 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2493 if (target
->opserv_level
== new_level
)
2495 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2496 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2497 target
->opserv_level
= new_level
;
2501 static OPTION_FUNC(opt_level
)
2506 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2510 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2511 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2515 static OPTION_FUNC(opt_epithet
)
2518 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2522 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2523 char *epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2526 if ((epithet
[0] == '*') && !epithet
[1])
2529 hi
->epithet
= strdup(epithet
);
2533 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2535 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2539 static OPTION_FUNC(opt_title
)
2544 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2548 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2550 if (strchr(title
, '.')) {
2551 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2554 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2555 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2556 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2561 if (!strcmp(title
, "*")) {
2562 hi
->fakehost
= NULL
;
2564 hi
->fakehost
= malloc(strlen(title
)+2);
2565 hi
->fakehost
[0] = '.';
2566 strcpy(hi
->fakehost
+1, title
);
2569 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2570 title
= hi
->fakehost
+ 1;
2574 title
= user_find_message(user
, "MSG_NONE");
2575 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2579 static OPTION_FUNC(opt_fakehost
)
2584 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2588 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2590 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
2591 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
2595 if (!strcmp(fake
, "*"))
2596 hi
->fakehost
= NULL
;
2598 hi
->fakehost
= strdup(fake
);
2599 fake
= hi
->fakehost
;
2602 fake
= generate_fakehost(hi
);
2604 fake
= user_find_message(user
, "MSG_NONE");
2605 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
2609 static NICKSERV_FUNC(cmd_reclaim
)
2611 struct handle_info
*hi
;
2612 struct nick_info
*ni
;
2613 struct userNode
*victim
;
2615 NICKSERV_MIN_PARMS(2);
2616 hi
= user
->handle_info
;
2617 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
2619 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
2622 if (ni
->owner
!= user
->handle_info
) {
2623 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
2626 victim
= GetUserH(ni
->nick
);
2628 reply("MSG_NICK_UNKNOWN", ni
->nick
);
2631 if (victim
== user
) {
2632 reply("NSMSG_NICK_USER_YOU");
2635 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
2636 switch (nickserv_conf
.reclaim_action
) {
2637 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
2638 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
2639 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
2640 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
2645 static NICKSERV_FUNC(cmd_unregnick
)
2648 struct handle_info
*hi
;
2649 struct nick_info
*ni
;
2651 hi
= user
->handle_info
;
2652 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
2653 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2655 reply("NSMSG_UNKNOWN_NICK", nick
);
2658 if (hi
!= ni
->owner
) {
2659 reply("NSMSG_NOT_YOUR_NICK", nick
);
2662 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2667 static NICKSERV_FUNC(cmd_ounregnick
)
2669 struct nick_info
*ni
;
2671 NICKSERV_MIN_PARMS(2);
2672 if (!(ni
= get_nick_info(argv
[1]))) {
2673 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
2676 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
2677 reply("MSG_USER_OUTRANKED", ni
->nick
);
2680 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2685 static NICKSERV_FUNC(cmd_unregister
)
2687 struct handle_info
*hi
;
2690 NICKSERV_MIN_PARMS(2);
2691 hi
= user
->handle_info
;
2694 if (checkpass(passwd
, hi
->passwd
)) {
2695 nickserv_unregister_handle(hi
, user
);
2698 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
2699 reply("NSMSG_PASSWORD_INVALID");
2704 static NICKSERV_FUNC(cmd_ounregister
)
2706 struct handle_info
*hi
;
2708 NICKSERV_MIN_PARMS(2);
2709 if (!(hi
= get_victim_oper(user
, argv
[1])))
2711 nickserv_unregister_handle(hi
, user
);
2715 static NICKSERV_FUNC(cmd_status
)
2717 if (nickserv_conf
.disable_nicks
) {
2718 reply("NSMSG_GLOBAL_STATS_NONICK",
2719 dict_size(nickserv_handle_dict
));
2721 if (user
->handle_info
) {
2723 struct nick_info
*ni
;
2724 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
2725 reply("NSMSG_HANDLE_STATS", cnt
);
2727 reply("NSMSG_HANDLE_NONE");
2729 reply("NSMSG_GLOBAL_STATS",
2730 dict_size(nickserv_handle_dict
),
2731 dict_size(nickserv_nick_dict
));
2736 static NICKSERV_FUNC(cmd_ghost
)
2738 struct userNode
*target
;
2739 char reason
[MAXLEN
];
2741 NICKSERV_MIN_PARMS(2);
2742 if (!(target
= GetUserH(argv
[1]))) {
2743 reply("MSG_NICK_UNKNOWN", argv
[1]);
2746 if (target
== user
) {
2747 reply("NSMSG_CANNOT_GHOST_SELF");
2750 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
2751 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
2754 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
2755 DelUser(target
, nickserv
, 1, reason
);
2756 reply("NSMSG_GHOST_KILLED", argv
[1]);
2760 static NICKSERV_FUNC(cmd_vacation
)
2762 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
2763 reply("NSMSG_ON_VACATION");
2768 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
2770 struct handle_info
*hi
;
2773 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
2775 #ifdef WITH_PROTOCOL_BAHAMUT
2778 saxdb_start_record(ctx
, iter_key(it
), 0);
2779 if (hi
->announcements
!= '?') {
2780 flags
[0] = hi
->announcements
;
2782 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
2785 struct handle_cookie
*cookie
= hi
->cookie
;
2788 switch (cookie
->type
) {
2789 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
2790 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
2791 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
2792 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
2793 default: type
= NULL
; break;
2796 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
2797 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
2798 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
2800 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
2801 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
2802 saxdb_end_record(ctx
);
2806 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
2808 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
2810 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
2814 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
2815 if (hi
->flags
& (1 << ii
))
2816 flags
[flen
++] = handle_flags
[ii
];
2818 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
2820 #ifdef WITH_PROTOCOL_BAHAMUT
2821 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
2824 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
2825 if (hi
->last_quit_host
[0])
2826 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
2827 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
2828 if (hi
->masks
->used
)
2829 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
2831 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
2833 struct string_list
*slist
;
2834 struct nick_info
*ni
;
2836 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
2837 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
2838 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
2842 if (hi
->opserv_level
)
2843 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
2844 if (hi
->language
!= lang_C
)
2845 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
2846 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
2847 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
2848 if (hi
->screen_width
)
2849 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
2850 if (hi
->table_width
)
2851 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
2852 flags
[0] = hi
->userlist_style
;
2854 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
2855 saxdb_end_record(ctx
);
2860 static handle_merge_func_t
*handle_merge_func_list
;
2861 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
2864 reg_handle_merge_func(handle_merge_func_t func
)
2866 if (handle_merge_func_used
== handle_merge_func_size
) {
2867 if (handle_merge_func_size
) {
2868 handle_merge_func_size
<<= 1;
2869 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
2871 handle_merge_func_size
= 8;
2872 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
2875 handle_merge_func_list
[handle_merge_func_used
++] = func
;
2878 static NICKSERV_FUNC(cmd_merge
)
2880 struct handle_info
*hi_from
, *hi_to
;
2881 struct userNode
*last_user
;
2882 struct userData
*cList
, *cListNext
;
2883 unsigned int ii
, jj
, n
;
2884 char buffer
[MAXLEN
];
2886 NICKSERV_MIN_PARMS(3);
2888 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
2890 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
2892 if (hi_to
== hi_from
) {
2893 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
2897 for (n
=0; n
<handle_merge_func_used
; n
++)
2898 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
2900 /* Append "from" handle's nicks to "to" handle's nick list. */
2902 struct nick_info
*last_ni
;
2903 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
2904 last_ni
->next
= hi_from
->nicks
;
2906 while (hi_from
->nicks
) {
2907 hi_from
->nicks
->owner
= hi_to
;
2908 hi_from
->nicks
= hi_from
->nicks
->next
;
2911 /* Merge the hostmasks. */
2912 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
2913 char *mask
= hi_from
->masks
->list
[ii
];
2914 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
2915 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
2917 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
2918 string_list_append(hi_to
->masks
, strdup(mask
));
2921 /* Merge the lists of authed users. */
2923 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
2924 last_user
->next_authed
= hi_from
->users
;
2926 hi_to
->users
= hi_from
->users
;
2928 /* Repoint the old "from" handle's users. */
2929 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
2930 last_user
->handle_info
= hi_to
;
2932 hi_from
->users
= NULL
;
2934 /* Merge channel userlists. */
2935 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
2936 struct userData
*cList2
;
2937 cListNext
= cList
->u_next
;
2938 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
2939 if (cList
->channel
== cList2
->channel
)
2941 if (cList2
&& (cList2
->access
>= cList
->access
)) {
2942 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
);
2943 /* keep cList2 in hi_to; remove cList from hi_from */
2944 del_channel_user(cList
, 1);
2947 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
);
2948 /* remove the lower-ranking cList2 from hi_to */
2949 del_channel_user(cList2
, 1);
2951 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
2953 /* cList needs to be moved from hi_from to hi_to */
2954 cList
->handle
= hi_to
;
2955 /* Remove from linked list for hi_from */
2956 assert(!cList
->u_prev
);
2957 hi_from
->channels
= cList
->u_next
;
2959 cList
->u_next
->u_prev
= cList
->u_prev
;
2960 /* Add to linked list for hi_to */
2961 cList
->u_prev
= NULL
;
2962 cList
->u_next
= hi_to
->channels
;
2963 if (hi_to
->channels
)
2964 hi_to
->channels
->u_prev
= cList
;
2965 hi_to
->channels
= cList
;
2969 /* Do they get an OpServ level promotion? */
2970 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
2971 hi_to
->opserv_level
= hi_from
->opserv_level
;
2973 /* What about last seen time? */
2974 if (hi_from
->lastseen
> hi_to
->lastseen
)
2975 hi_to
->lastseen
= hi_from
->lastseen
;
2977 /* Notify of success. */
2978 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
2979 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
2980 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
2982 /* Unregister the "from" handle. */
2983 nickserv_unregister_handle(hi_from
, NULL
);
2988 struct nickserv_discrim
{
2989 unsigned int limit
, min_level
, max_level
;
2990 unsigned long flags_on
, flags_off
;
2991 time_t min_registered
, max_registered
;
2993 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
2994 const char *nickmask
;
2995 const char *hostmask
;
2996 const char *handlemask
;
2997 const char *emailmask
;
3000 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3002 struct discrim_apply_info
{
3003 struct nickserv_discrim
*discrim
;
3004 discrim_search_func func
;
3005 struct userNode
*source
;
3006 unsigned int matched
;
3009 static struct nickserv_discrim
*
3010 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3013 struct nickserv_discrim
*discrim
;
3015 discrim
= malloc(sizeof(*discrim
));
3016 memset(discrim
, 0, sizeof(*discrim
));
3017 discrim
->min_level
= 0;
3018 discrim
->max_level
= ~0;
3019 discrim
->limit
= 50;
3020 discrim
->min_registered
= 0;
3021 discrim
->max_registered
= INT_MAX
;
3022 discrim
->lastseen
= now
;
3024 for (i
=0; i
<argc
; i
++) {
3025 if (i
== argc
- 1) {
3026 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3029 if (!irccasecmp(argv
[i
], "limit")) {
3030 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3031 } else if (!irccasecmp(argv
[i
], "flags")) {
3032 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3033 } else if (!irccasecmp(argv
[i
], "registered")) {
3034 const char *cmp
= argv
[++i
];
3035 if (cmp
[0] == '<') {
3036 if (cmp
[1] == '=') {
3037 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3039 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3041 } else if (cmp
[0] == '=') {
3042 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3043 } else if (cmp
[0] == '>') {
3044 if (cmp
[1] == '=') {
3045 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3047 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3050 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3052 } else if (!irccasecmp(argv
[i
], "seen")) {
3053 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3054 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3055 discrim
->nickmask
= argv
[++i
];
3056 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3058 if (!irccasecmp(argv
[i
], "exact")) {
3059 if (i
== argc
- 1) {
3060 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3063 discrim
->hostmask_type
= EXACT
;
3064 } else if (!irccasecmp(argv
[i
], "subset")) {
3065 if (i
== argc
- 1) {
3066 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3069 discrim
->hostmask_type
= SUBSET
;
3070 } else if (!irccasecmp(argv
[i
], "superset")) {
3071 if (i
== argc
- 1) {
3072 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3075 discrim
->hostmask_type
= SUPERSET
;
3076 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3077 if (i
== argc
- 1) {
3078 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3081 discrim
->hostmask_type
= LASTQUIT
;
3084 discrim
->hostmask_type
= SUPERSET
;
3086 discrim
->hostmask
= argv
[++i
];
3087 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3088 if (!irccasecmp(argv
[++i
], "*")) {
3089 discrim
->handlemask
= 0;
3091 discrim
->handlemask
= argv
[i
];
3093 } else if (!irccasecmp(argv
[i
], "email")) {
3094 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3095 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3097 } else if (!irccasecmp(argv
[++i
], "*")) {
3098 discrim
->emailmask
= 0;
3100 discrim
->emailmask
= argv
[i
];
3102 } else if (!irccasecmp(argv
[i
], "access")) {
3103 const char *cmp
= argv
[++i
];
3104 if (cmp
[0] == '<') {
3105 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3106 if (cmp
[1] == '=') {
3107 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3109 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3111 } else if (cmp
[0] == '=') {
3112 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3113 } else if (cmp
[0] == '>') {
3114 if (cmp
[1] == '=') {
3115 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3117 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3120 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3123 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3134 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3136 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3137 || (discrim
->flags_off
& hi
->flags
)
3138 || (discrim
->min_registered
> hi
->registered
)
3139 || (discrim
->max_registered
< hi
->registered
)
3140 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3141 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3142 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3143 || (discrim
->min_level
> hi
->opserv_level
)
3144 || (discrim
->max_level
< hi
->opserv_level
)) {
3147 if (discrim
->hostmask
) {
3149 for (i
=0; i
<hi
->masks
->used
; i
++) {
3150 const char *mask
= hi
->masks
->list
[i
];
3151 if ((discrim
->hostmask_type
== SUBSET
)
3152 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3153 else if ((discrim
->hostmask_type
== EXACT
)
3154 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3155 else if ((discrim
->hostmask_type
== SUPERSET
)
3156 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3157 else if ((discrim
->hostmask_type
== LASTQUIT
)
3158 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3160 if (i
==hi
->masks
->used
) return 0;
3162 if (discrim
->nickmask
) {
3163 struct nick_info
*nick
= hi
->nicks
;
3165 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3168 if (!nick
) return 0;
3174 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3176 dict_iterator_t it
, next
;
3177 unsigned int matched
;
3179 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3180 it
&& (matched
< discrim
->limit
);
3182 next
= iter_next(it
);
3183 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3184 dsf(source
, iter_data(it
));
3192 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3194 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3198 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3203 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3205 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3206 nickserv_unregister_handle(match
, source
);
3210 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3212 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3213 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3214 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3215 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3216 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3220 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3222 struct handle_info_list hil
;
3223 struct helpfile_table tbl
;
3228 memset(&hil
, 0, sizeof(hil
));
3229 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3230 struct handle_info
*hi
= iter_data(it
);
3231 if (hi
->opserv_level
)
3232 handle_info_list_append(&hil
, hi
);
3234 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3235 tbl
.length
= hil
.used
+ 1;
3237 tbl
.flags
= TABLE_NO_FREE
;
3238 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3239 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3242 for (ii
= 0; ii
< hil
.used
; ) {
3243 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3244 ary
[0] = hil
.list
[ii
]->handle
;
3245 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3246 tbl
.contents
[++ii
] = ary
;
3248 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3249 reply("MSG_MATCH_COUNT", hil
.used
);
3250 for (ii
= 0; ii
< hil
.used
; ii
++)
3251 free(tbl
.contents
[ii
]);
3256 static NICKSERV_FUNC(cmd_search
)
3258 struct nickserv_discrim
*discrim
;
3259 discrim_search_func action
;
3260 struct svccmd
*subcmd
;
3261 unsigned int matches
;
3264 NICKSERV_MIN_PARMS(3);
3265 sprintf(buf
, "search %s", argv
[1]);
3266 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3267 if (!irccasecmp(argv
[1], "print"))
3268 action
= search_print_func
;
3269 else if (!irccasecmp(argv
[1], "count"))
3270 action
= search_count_func
;
3271 else if (!irccasecmp(argv
[1], "unregister"))
3272 action
= search_unregister_func
;
3274 reply("NSMSG_INVALID_ACTION", argv
[1]);
3278 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3281 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3285 if (action
== search_print_func
)
3286 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3287 else if (action
== search_count_func
)
3288 discrim
->limit
= INT_MAX
;
3290 matches
= nickserv_discrim_search(discrim
, action
, user
);
3293 reply("MSG_MATCH_COUNT", matches
);
3295 reply("MSG_NO_MATCHES");
3301 static MODCMD_FUNC(cmd_checkpass
)
3303 struct handle_info
*hi
;
3305 NICKSERV_MIN_PARMS(3);
3306 if (!(hi
= get_handle_info(argv
[1]))) {
3307 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3310 if (checkpass(argv
[2], hi
->passwd
))
3311 reply("CHECKPASS_YES");
3313 reply("CHECKPASS_NO");
3319 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3322 struct string_list
*masks
, *slist
;
3323 struct handle_info
*hi
;
3324 struct userNode
*authed_users
;
3325 unsigned long int id
;
3329 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3330 id
= str
? strtoul(str
, NULL
, 0) : 0;
3331 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3333 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3336 if ((hi
= get_handle_info(handle
))) {
3337 authed_users
= hi
->users
;
3339 dict_remove(nickserv_handle_dict
, hi
->handle
);
3341 authed_users
= NULL
;
3343 hi
= register_handle(handle
, str
, id
);
3345 hi
->users
= authed_users
;
3346 while (authed_users
) {
3347 authed_users
->handle_info
= hi
;
3348 authed_users
= authed_users
->next_authed
;
3351 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3352 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3353 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3354 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3355 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3356 hi
->language
= language_find(str
? str
: "C");
3357 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3358 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3359 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3361 hi
->infoline
= strdup(str
);
3362 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3363 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3364 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3365 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3366 /* We want to read the nicks even if disable_nicks is set. This is so
3367 * that we don't lose the nick data entirely. */
3368 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3370 for (ii
=0; ii
<slist
->used
; ii
++)
3371 register_nick(slist
->list
[ii
], hi
);
3373 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3375 for (ii
=0; str
[ii
]; ii
++)
3376 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3378 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3379 hi
->userlist_style
= str
? str
[0] : HI_STYLE_ZOOT
;
3380 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3381 hi
->announcements
= str
? str
[0] : '?';
3382 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3383 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3384 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3385 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3386 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3388 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3390 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3391 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3393 nickserv_set_email_addr(hi
, str
);
3394 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3396 hi
->epithet
= strdup(str
);
3397 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3399 hi
->fakehost
= strdup(str
);
3400 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3402 const char *data
, *type
, *expires
, *cookie_str
;
3403 struct handle_cookie
*cookie
;
3405 cookie
= calloc(1, sizeof(*cookie
));
3406 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3407 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3408 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3409 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3410 if (!type
|| !expires
|| !cookie_str
) {
3411 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3414 if (!irccasecmp(type
, KEY_ACTIVATION
))
3415 cookie
->type
= ACTIVATION
;
3416 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3417 cookie
->type
= PASSWORD_CHANGE
;
3418 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3419 cookie
->type
= EMAIL_CHANGE
;
3420 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3421 cookie
->type
= ALLOWAUTH
;
3423 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3426 cookie
->expires
= strtoul(expires
, NULL
, 0);
3427 if (cookie
->expires
< now
)
3430 cookie
->data
= strdup(data
);
3431 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3435 nickserv_bake_cookie(cookie
);
3437 nickserv_free_cookie(cookie
);
3442 nickserv_saxdb_read(dict_t db
) {
3444 struct record_data
*rd
;
3446 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3448 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3453 static NICKSERV_FUNC(cmd_mergedb
)
3455 struct timeval start
, stop
;
3458 NICKSERV_MIN_PARMS(2);
3459 gettimeofday(&start
, NULL
);
3460 if (!(db
= parse_database(argv
[1]))) {
3461 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3464 nickserv_saxdb_read(db
);
3466 gettimeofday(&stop
, NULL
);
3467 stop
.tv_sec
-= start
.tv_sec
;
3468 stop
.tv_usec
-= start
.tv_usec
;
3469 if (stop
.tv_usec
< 0) {
3471 stop
.tv_usec
+= 1000000;
3473 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3478 expire_handles(UNUSED_ARG(void *data
))
3480 dict_iterator_t it
, next
;
3482 struct handle_info
*hi
;
3484 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3485 next
= iter_next(it
);
3487 if ((hi
->opserv_level
> 0)
3489 || HANDLE_FLAGGED(hi
, FROZEN
)
3490 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3493 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3494 if ((now
- hi
->lastseen
) > expiry
) {
3495 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3496 nickserv_unregister_handle(hi
, NULL
);
3500 if (nickserv_conf
.handle_expire_frequency
)
3501 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3505 nickserv_load_dict(const char *fname
)
3509 if (!(file
= fopen(fname
, "r"))) {
3510 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
3513 while (!feof(file
)) {
3514 fgets(line
, sizeof(line
), file
);
3517 if (line
[strlen(line
)-1] == '\n')
3518 line
[strlen(line
)-1] = 0;
3519 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
3522 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
3525 static enum reclaim_action
3526 reclaim_action_from_string(const char *str
) {
3528 return RECLAIM_NONE
;
3529 else if (!irccasecmp(str
, "warn"))
3530 return RECLAIM_WARN
;
3531 else if (!irccasecmp(str
, "svsnick"))
3532 return RECLAIM_SVSNICK
;
3533 else if (!irccasecmp(str
, "kill"))
3534 return RECLAIM_KILL
;
3536 return RECLAIM_NONE
;
3540 nickserv_conf_read(void)
3542 dict_t conf_node
, child
;
3546 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
3547 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
3550 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
3552 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
3553 if (nickserv_conf
.valid_handle_regex_set
)
3554 regfree(&nickserv_conf
.valid_handle_regex
);
3556 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3557 nickserv_conf
.valid_handle_regex_set
= !err
;
3558 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
3560 nickserv_conf
.valid_handle_regex_set
= 0;
3562 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
3563 if (nickserv_conf
.valid_nick_regex_set
)
3564 regfree(&nickserv_conf
.valid_nick_regex
);
3566 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3567 nickserv_conf
.valid_nick_regex_set
= !err
;
3568 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
3570 nickserv_conf
.valid_nick_regex_set
= 0;
3572 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
3574 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
3575 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
3576 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
3577 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
3578 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
3579 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
3580 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
3581 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
3582 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
3583 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
3584 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
3585 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
3586 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
3587 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
3588 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
3589 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
3590 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
3591 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
3592 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
3593 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
3594 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
3595 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
3596 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
3597 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
3598 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
3600 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
3601 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
3602 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3604 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3605 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
3606 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3608 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3609 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
3610 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
3611 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
3612 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
3613 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
3614 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
3615 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
3616 if (!nickserv_conf
.disable_nicks
) {
3617 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
3618 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3619 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
3620 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
3621 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
3622 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3623 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
3624 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
3626 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
3627 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
3628 const char *key
= iter_key(it
), *value
;
3632 if (!strncasecmp(key
, "uc_", 3))
3633 flag
= toupper(key
[3]);
3634 else if (!strncasecmp(key
, "lc_", 3))
3635 flag
= tolower(key
[3]);
3639 if ((pos
= handle_inverse_flags
[flag
])) {
3640 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
3641 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
3644 if (nickserv_conf
.weak_password_dict
)
3645 dict_delete(nickserv_conf
.weak_password_dict
);
3646 nickserv_conf
.weak_password_dict
= dict_new();
3647 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
3648 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
3649 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
3650 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
3652 nickserv_load_dict(str
);
3653 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
3654 if (nickserv
&& str
)
3655 NickChange(nickserv
, str
, 0);
3656 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
3657 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
3658 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
3659 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
3660 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
3661 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
3662 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
3663 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
3664 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
3665 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
3666 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
3667 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
3668 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
3669 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
3670 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
3671 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
3672 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
3673 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
3674 str
= conf_get_data("server/network", RECDB_QSTRING
);
3675 nickserv_conf
.network_name
= str
? str
: "some IRC network";
3676 if (!nickserv_conf
.auth_policer_params
) {
3677 nickserv_conf
.auth_policer_params
= policer_params_new();
3678 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
3679 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
3681 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
3682 for (it
=dict_first(child
); it
; it
=iter_next(it
))
3683 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
3687 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
3689 char newnick
[NICKLEN
+1];
3698 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3700 case RECLAIM_SVSNICK
:
3702 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
3703 } while (GetUserH(newnick
));
3704 irc_svsnick(nickserv
, user
, newnick
);
3707 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
3708 irc_kill(nickserv
, user
, msg
);
3714 nickserv_reclaim_p(void *data
) {
3715 struct userNode
*user
= data
;
3716 struct nick_info
*ni
= get_nick_info(user
->nick
);
3718 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3722 check_user_nick(struct userNode
*user
) {
3723 struct nick_info
*ni
;
3724 user
->modes
&= ~FLAGS_REGNICK
;
3725 if (!(ni
= get_nick_info(user
->nick
)))
3727 if (user
->handle_info
== ni
->owner
) {
3728 user
->modes
|= FLAGS_REGNICK
;
3732 if (nickserv_conf
.warn_nick_owned
)
3733 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3734 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
3736 if (nickserv_conf
.auto_reclaim_delay
)
3737 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
3739 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3744 handle_new_user(struct userNode
*user
)
3746 return check_user_nick(user
);
3750 handle_account(struct userNode
*user
, const char *stamp
)
3752 struct handle_info
*hi
;
3755 #ifdef WITH_PROTOCOL_P10
3756 time_t timestamp
= 0;
3758 colon
= strchr(stamp
, ':');
3759 if(colon
&& colon
[1])
3762 timestamp
= atoi(colon
+1);
3764 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
3765 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
3767 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
);
3771 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
3772 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
3776 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
3779 set_user_handle_info(user
, hi
, 0);
3781 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
3786 handle_nick_change(struct userNode
*user
, const char *old_nick
)
3788 struct handle_info
*hi
;
3790 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
3791 dict_remove(nickserv_allow_auth_dict
, old_nick
);
3792 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
3794 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3795 check_user_nick(user
);
3799 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
3801 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
3802 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3803 set_user_handle_info(user
, NULL
, 0);
3806 static struct modcmd
*
3807 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
3809 if (min_level
> 0) {
3811 sprintf(buf
, "%u", min_level
);
3812 if (must_be_qualified
) {
3813 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
3815 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
3817 } else if (min_level
== 0) {
3818 if (must_be_qualified
) {
3819 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3821 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3824 if (must_be_qualified
) {
3825 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
3827 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
3833 nickserv_db_cleanup(void)
3835 unreg_del_user_func(nickserv_remove_user
);
3836 userList_clean(&curr_helpers
);
3837 policer_params_delete(nickserv_conf
.auth_policer_params
);
3838 dict_delete(nickserv_handle_dict
);
3839 dict_delete(nickserv_nick_dict
);
3840 dict_delete(nickserv_opt_dict
);
3841 dict_delete(nickserv_allow_auth_dict
);
3842 dict_delete(nickserv_email_dict
);
3843 dict_delete(nickserv_id_dict
);
3844 dict_delete(nickserv_conf
.weak_password_dict
);
3845 free(auth_func_list
);
3846 free(unreg_func_list
);
3848 free(allowauth_func_list
);
3849 free(handle_merge_func_list
);
3850 free(failpw_func_list
);
3851 if (nickserv_conf
.valid_handle_regex_set
)
3852 regfree(&nickserv_conf
.valid_handle_regex
);
3853 if (nickserv_conf
.valid_nick_regex_set
)
3854 regfree(&nickserv_conf
.valid_nick_regex
);
3858 init_nickserv(const char *nick
)
3861 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
3862 reg_new_user_func(handle_new_user
);
3863 reg_nick_change_func(handle_nick_change
);
3864 reg_del_user_func(nickserv_remove_user
);
3865 reg_account_func(handle_account
);
3867 /* set up handle_inverse_flags */
3868 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
3869 for (i
=0; handle_flags
[i
]; i
++) {
3870 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
3871 flag_access_levels
[i
] = 0;
3874 conf_register_reload(nickserv_conf_read
);
3875 nickserv_opt_dict
= dict_new();
3876 nickserv_email_dict
= dict_new();
3877 dict_set_free_keys(nickserv_email_dict
, free
);
3878 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
3880 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
3881 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
3882 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
3883 * a big pain to disable since its nolonger in the config file. ) -Rubin
3885 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
3886 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
3887 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
3888 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
3889 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
3890 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
3891 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
3892 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
3893 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
3894 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
3895 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
3896 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
3897 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
3898 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
3899 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
3900 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
3901 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
3902 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
3903 if (!nickserv_conf
.disable_nicks
) {
3904 /* nick management commands */
3905 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
3906 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
3907 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
3908 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
3909 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
3910 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
3912 if (nickserv_conf
.email_enabled
) {
3913 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
3914 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
3915 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
3916 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
3917 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
3919 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
3920 /* miscellaneous commands */
3921 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
3922 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
3923 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
3924 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
3925 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
3927 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
3928 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
3929 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
3930 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
3931 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
3932 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
3933 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
3934 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
3935 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
3936 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
3937 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
3938 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
3939 if (nickserv_conf
.titlehost_suffix
) {
3940 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
3941 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
3943 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
3944 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
3945 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
3947 nickserv_handle_dict
= dict_new();
3948 dict_set_free_keys(nickserv_handle_dict
, free
);
3949 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
3951 nickserv_id_dict
= dict_new();
3952 dict_set_free_keys(nickserv_id_dict
, free
);
3954 nickserv_nick_dict
= dict_new();
3955 dict_set_free_data(nickserv_nick_dict
, free
);
3957 nickserv_allow_auth_dict
= dict_new();
3959 userList_init(&curr_helpers
);
3962 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
3963 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
3964 nickserv_service
= service_register(nickserv
);
3966 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
3967 reg_exit_func(nickserv_db_cleanup
);
3968 if(nickserv_conf
.handle_expire_frequency
)
3969 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3970 message_register_table(msgtab
);