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_SYNC_LOG "sync_log"
70 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
71 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
72 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
75 #define KEY_PASSWD "passwd"
76 #define KEY_NICKS "nicks"
77 #define KEY_MASKS "masks"
78 #define KEY_OPSERV_LEVEL "opserv_level"
79 #define KEY_FLAGS "flags"
80 #define KEY_REGISTER_ON "register"
81 #define KEY_LAST_SEEN "lastseen"
82 #define KEY_INFO "info"
83 #define KEY_USERLIST_STYLE "user_style"
84 #define KEY_SCREEN_WIDTH "screen_width"
85 #define KEY_LAST_AUTHED_HOST "last_authed_host"
86 #define KEY_LAST_QUIT_HOST "last_quit_host"
87 #define KEY_EMAIL_ADDR "email_addr"
88 #define KEY_COOKIE "cookie"
89 #define KEY_COOKIE_DATA "data"
90 #define KEY_COOKIE_TYPE "type"
91 #define KEY_COOKIE_EXPIRES "expires"
92 #define KEY_ACTIVATION "activation"
93 #define KEY_PASSWORD_CHANGE "password change"
94 #define KEY_EMAIL_CHANGE "email change"
95 #define KEY_ALLOWAUTH "allowauth"
96 #define KEY_EPITHET "epithet"
97 #define KEY_TABLE_WIDTH "table_width"
98 #define KEY_ANNOUNCEMENTS "announcements"
99 #define KEY_MAXLOGINS "maxlogins"
100 #define KEY_FAKEHOST "fakehost"
102 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
104 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
105 #define OPTION_FUNC(NAME) int NAME(struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
106 typedef OPTION_FUNC(option_func_t
);
108 DEFINE_LIST(handle_info_list
, struct handle_info
*);
110 #define NICKSERV_MIN_PARMS(N) do { \
112 reply("MSG_MISSING_PARAMS", argv[0]); \
113 svccmd_send_help(user, nickserv, cmd); \
117 struct userNode
*nickserv
;
118 struct userList curr_helpers
;
119 const char *handle_flags
= HANDLE_FLAGS
;
121 static struct module *nickserv_module
;
122 static struct service
*nickserv_service
;
123 static struct log_type
*NS_LOG
;
124 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
125 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
126 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
127 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
128 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
129 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
130 static char handle_inverse_flags
[256];
131 static unsigned int flag_access_levels
[32];
132 static const struct message_entry msgtab
[] = {
133 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
134 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu charactors or less."},
135 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
136 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
137 { "NSMSG_PASSWORD_DICTIONARY", "Your password should not be the word \"password\", or any other dictionary word." },
138 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
139 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
140 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
141 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
142 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
143 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
144 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
145 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
146 { "NSMSG_USE_COOKIE_REGISTER", "To activate your account, you must check your email for the \"cookie\" that has been mailed to it. When you have it, use the $bcookie$b command to complete registration." },
147 { "NSMSG_USE_COOKIE_RESETPASS", "A cookie has been mailed to your account's email address. You must check your email and use the $bcookie$b command to confirm the password change." },
148 { "NSMSG_USE_COOKIE_EMAIL_1", "A cookie has been mailed to the new address you requested. To finish setting your email address, please check your email for the cookie and use the $bcookie$b command to verify." },
149 { "NSMSG_USE_COOKIE_EMAIL_2", "A cookie has been generated, and half mailed to each your old and new addresses. To finish changing your email address, please check your email for the cookie and use the $bcookie$b command to verify." },
150 { "NSMSG_USE_COOKIE_AUTH", "A cookie has been generated and sent to your email address. Once you have checked your email and received the cookie, auth using the $bcookie$b command." },
151 { "NSMSG_COOKIE_LIVE", "Account $b%s$b already has a cookie active. Please either finish using that cookie, wait for it to expire, or auth to the account and use the $bdelcookie$b command." },
152 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
153 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
154 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
155 { "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." },
156 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
157 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
158 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
159 { "NSMSG_EMAIL_OVERUSED", "There are already the maximum number of accounts associated with that email address." },
160 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
161 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
162 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
163 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
164 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
165 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
166 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
167 { "NSMSG_REGISTER_BAD_NICKMASK", "Could not recognize $b%s$b as either a current nick or a hostmask." },
168 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
169 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
170 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
171 { "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)" },
172 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
173 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
174 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
175 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
176 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
177 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
178 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
179 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
180 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
181 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
182 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
183 { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
184 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
185 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
186 { "NSMSG_HANDLEINFO_ON", "Account information for $b%s$b:" },
187 { "NSMSG_HANDLEINFO_ID", " Account ID: %lu" },
188 { "NSMSG_HANDLEINFO_REGGED", " Registered on: %s" },
189 { "NSMSG_HANDLEINFO_LASTSEEN", " Last seen: %s" },
190 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", " Last seen: Right now!" },
191 { "NSMSG_HANDLEINFO_VACATION", " On vacation." },
192 { "NSMSG_HANDLEINFO_EMAIL_ADDR", " Email address: %s" },
193 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", " Cookie: There is currently an activation cookie issued for this account" },
194 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", " Cookie: There is currently a password change cookie issued for this account" },
195 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", " Cookie: There is currently an email change cookie issued for this account" },
196 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", " Cookie: There is currently an allowauth cookie issued for this account" },
197 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", " Cookie: There is currently an unknown cookie issued for this account" },
198 { "NSMSG_HANDLEINFO_INFOLINE", " Infoline: %s" },
199 { "NSMSG_HANDLEINFO_FLAGS", " Flags: %s" },
200 { "NSMSG_HANDLEINFO_EPITHET", " Epithet: %s" },
201 { "NSMSG_HANDLEINFO_FAKEHOST", " Fake host: %s" },
202 { "NSMSG_HANDLEINFO_LAST_HOST", " Last quit hostmask: %s" },
203 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", " Last quit hostmask: Unknown" },
204 { "NSMSG_HANDLEINFO_NICKS", " Nickname(s): %s" },
205 { "NSMSG_HANDLEINFO_MASKS", " Hostmask(s): %s" },
206 { "NSMSG_HANDLEINFO_CHANNELS", " Channel(s): %s" },
207 { "NSMSG_HANDLEINFO_CURRENT", " Current nickname(s): %s" },
208 { "NSMSG_HANDLEINFO_DNR", " Do-not-register (by %s): %s" },
209 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
210 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
211 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
212 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
213 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
214 { "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)." },
215 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
216 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
217 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
218 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
219 { "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." },
220 { "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." },
221 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
222 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
223 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
224 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
225 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
226 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
227 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
228 { "NSMSG_PASS_SUCCESS", "Password changed." },
229 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
230 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
231 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
232 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
233 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
234 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
235 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
236 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
237 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
238 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
239 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
240 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
241 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
242 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
243 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
244 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
245 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
246 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
247 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
248 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
249 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
250 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
251 { "NSMSG_NO_ACCESS", "Access denied." },
252 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
253 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
254 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
255 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
256 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
257 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
258 { "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." },
259 { "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." },
260 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
261 { "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." },
262 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
263 { "NSMSG_SEARCH_MATCH", "Match: %s" },
264 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
265 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
266 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
267 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
268 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
269 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
270 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
271 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
272 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
273 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
274 { "NSMSG_SETTING_LIST", "$b$N account settings:$b" },
275 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
276 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
277 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
278 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
279 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
280 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
281 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
282 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
283 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
284 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
285 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
286 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
287 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
288 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
289 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
290 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
291 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
292 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
293 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
294 { "NSEMAIL_ACTIVATION_BODY",
295 "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"
297 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
298 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
299 "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"
300 "/msg %3$s@%4$s AUTH %5$s your-password\n"
301 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
302 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
304 "If you did NOT request this account, you do not need to do anything.\n"
305 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
306 { "NSEMAIL_ACTIVATION_BODY_WEB",
307 "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n"
309 "To verify your email address and complete the account registration, visit the following URL:\n"
310 "http://www.afternet.org/play/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
312 "If you did NOT request this account, you do not need to do anything.\n"
313 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
314 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
315 { "NSEMAIL_PASSWORD_CHANGE_BODY",
316 "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"
317 "To complete the password change, log on to %1$s and type the following command:\n"
318 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
319 "If you did NOT request your password to be changed, you do not need to do anything.\n"
320 "Please contact the %1$s staff if you have questions." },
321 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
322 "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"
323 "To complete the password change, click the following URL:\n"
324 "http://www.afternet.org/play/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
325 "If you did NOT request your password to be changed, you do not need to do anything.\n"
326 "Please contact the %1$s staff if you have questions." },
327 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
328 { "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." },
329 { "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." },
330 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
331 { "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." },
332 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
333 { "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." },
334 { "CHECKPASS_YES", "Yes." },
335 { "CHECKPASS_NO", "No." },
339 enum reclaim_action
{
345 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
346 static void nickserv_reclaim_p(void *data
);
349 unsigned int disable_nicks
: 1;
350 unsigned int valid_handle_regex_set
: 1;
351 unsigned int valid_nick_regex_set
: 1;
352 unsigned int autogag_enabled
: 1;
353 unsigned int email_enabled
: 1;
354 unsigned int email_required
: 1;
355 unsigned int default_hostmask
: 1;
356 unsigned int warn_nick_owned
: 1;
357 unsigned int warn_clone_auth
: 1;
358 unsigned int sync_log
: 1;
359 unsigned long nicks_per_handle
;
360 unsigned long password_min_length
;
361 unsigned long password_min_digits
;
362 unsigned long password_min_upper
;
363 unsigned long password_min_lower
;
364 unsigned long db_backup_frequency
;
365 unsigned long handle_expire_frequency
;
366 unsigned long autogag_duration
;
367 unsigned long email_visible_level
;
368 unsigned long cookie_timeout
;
369 unsigned long handle_expire_delay
;
370 unsigned long nochan_handle_expire_delay
;
371 unsigned long modoper_level
;
372 unsigned long set_epithet_level
;
373 unsigned long set_title_level
;
374 unsigned long set_fakehost_level
;
375 unsigned long handles_per_email
;
376 unsigned long email_search_level
;
377 const char *network_name
;
378 const char *titlehost_suffix
;
379 regex_t valid_handle_regex
;
380 regex_t valid_nick_regex
;
381 dict_t weak_password_dict
;
382 struct policer_params
*auth_policer_params
;
383 enum reclaim_action reclaim_action
;
384 enum reclaim_action auto_reclaim_action
;
385 unsigned long auto_reclaim_delay
;
386 unsigned char default_maxlogins
;
387 unsigned char hard_maxlogins
;
390 /* We have 2^32 unique account IDs to use. */
391 unsigned long int highest_id
= 0;
394 canonicalize_hostmask(char *mask
)
396 char *out
= mask
, *temp
;
397 if ((temp
= strchr(mask
, '!'))) {
399 while (*temp
) *out
++ = *temp
++;
405 static struct handle_info
*
406 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
408 struct handle_info
*hi
;
410 #ifdef WITH_PROTOCOL_BAHAMUT
411 char id_base64
[IDLEN
+ 1];
414 /* Assign a unique account ID to the account; note that 0 is
415 an invalid account ID. 1 is therefore the first account ID. */
417 id
= 1 + highest_id
++;
419 /* Note: highest_id is and must always be the highest ID. */
420 if(id
> highest_id
) {
424 inttobase64(id_base64
, id
, IDLEN
);
426 /* Make sure an account with the same ID doesn't exist. If a
427 duplicate is found, log some details and assign a new one.
428 This should be impossible, but it never hurts to expect it. */
429 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
430 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
436 hi
= calloc(1, sizeof(*hi
));
437 hi
->userlist_style
= HI_DEFAULT_STYLE
;
438 hi
->announcements
= '?';
439 hi
->handle
= strdup(handle
);
440 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
442 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
444 #ifdef WITH_PROTOCOL_BAHAMUT
446 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
453 register_nick(const char *nick
, struct handle_info
*owner
)
455 struct nick_info
*ni
;
456 ni
= malloc(sizeof(struct nick_info
));
457 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
459 ni
->next
= owner
->nicks
;
461 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
465 delete_nick(struct nick_info
*ni
)
467 struct nick_info
*last
, *next
;
468 struct userNode
*user
;
469 /* Check to see if we should mark a user as unregistered. */
470 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
471 user
->modes
&= ~FLAGS_REGNICK
;
474 /* Remove ni from the nick_info linked list. */
475 if (ni
== ni
->owner
->nicks
) {
476 ni
->owner
->nicks
= ni
->next
;
478 last
= ni
->owner
->nicks
;
484 last
->next
= next
->next
;
486 dict_remove(nickserv_nick_dict
, ni
->nick
);
489 static unreg_func_t
*unreg_func_list
;
490 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
493 reg_unreg_func(unreg_func_t func
)
495 if (unreg_func_used
== unreg_func_size
) {
496 if (unreg_func_size
) {
497 unreg_func_size
<<= 1;
498 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
501 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
504 unreg_func_list
[unreg_func_used
++] = func
;
508 nickserv_free_cookie(void *data
)
510 struct handle_cookie
*cookie
= data
;
511 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
512 if (cookie
->data
) free(cookie
->data
);
517 free_handle_info(void *vhi
)
519 struct handle_info
*hi
= vhi
;
521 #ifdef WITH_PROTOCOL_BAHAMUT
524 inttobase64(id
, hi
->id
, IDLEN
);
525 dict_remove(nickserv_id_dict
, id
);
528 free_string_list(hi
->masks
);
532 delete_nick(hi
->nicks
);
537 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
538 nickserv_free_cookie(hi
->cookie
);
540 if (hi
->email_addr
) {
541 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
542 handle_info_list_remove(hil
, hi
);
544 dict_remove(nickserv_email_dict
, hi
->email_addr
);
549 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
552 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
)
556 for (n
=0; n
<unreg_func_used
; n
++)
557 unreg_func_list
[n
](notify
, hi
);
559 set_user_handle_info(hi
->users
, NULL
, 0);
561 if (nickserv_conf
.disable_nicks
)
562 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
564 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
567 if (nickserv_conf
.sync_log
)
568 SyncLog("UNREGISTER %s", hi
->handle
);
570 dict_remove(nickserv_handle_dict
, hi
->handle
);
574 get_handle_info(const char *handle
)
576 return dict_find(nickserv_handle_dict
, handle
, 0);
580 get_nick_info(const char *nick
)
582 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
586 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
591 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
592 mn
= channel
->members
.list
[nn
];
593 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
600 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
601 if (!user
->handle_info
) {
603 send_message(user
, bot
, "MSG_AUTHENTICATE");
607 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
609 send_message(user
, bot
, "NSMSG_NO_ACCESS");
613 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
615 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
619 if (user
->handle_info
->opserv_level
< min_level
) {
621 send_message(user
, bot
, "NSMSG_NO_ACCESS");
629 is_valid_handle(const char *handle
)
631 struct userNode
*user
;
632 /* cant register a juped nick/service nick as handle, to prevent confusion */
633 user
= GetUserH(handle
);
634 if (user
&& IsLocal(user
))
636 /* check against maximum length */
637 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
639 /* for consistency, only allow account names that could be nicks */
640 if (!is_valid_nick(handle
))
642 /* disallow account names that look like bad words */
643 if (opserv_bad_channel(handle
))
645 /* test either regex or containing all valid chars */
646 if (nickserv_conf
.valid_handle_regex_set
) {
647 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
650 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
651 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
655 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
660 is_registerable_nick(const char *nick
)
662 /* make sure it could be used as an account name */
663 if (!is_valid_handle(nick
))
666 if (strlen(nick
) > NICKLEN
)
668 /* test either regex or as valid handle */
669 if (nickserv_conf
.valid_nick_regex_set
) {
670 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
673 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
674 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
682 is_valid_email_addr(const char *email
)
684 return strchr(email
, '@') != NULL
;
688 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
690 if (hi
->email_addr
) {
691 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
692 return hi
->email_addr
;
702 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
704 struct handle_info
*hi
;
705 struct userNode
*target
;
709 if (!(hi
= get_handle_info(++name
))) {
710 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
715 if (!(target
= GetUserH(name
))) {
716 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
719 if (IsLocal(target
)) {
720 if (IsService(target
))
721 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
723 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
726 if (!(hi
= target
->handle_info
)) {
727 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
735 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
736 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
738 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
739 if ((user
->handle_info
->opserv_level
== 1000)
740 || (user
->handle_info
== hi
)
741 || ((user
->handle_info
->opserv_level
== 0)
742 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
743 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
747 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
751 static struct handle_info
*
752 get_victim_oper(struct userNode
*user
, const char *target
)
754 struct handle_info
*hi
;
755 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
757 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
758 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
761 return oper_outranks(user
, hi
) ? hi
: NULL
;
765 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
769 /* If no hostmasks on the account, allow it. */
770 if (!hi
->masks
->used
)
772 /* If any hostmask matches, allow it. */
773 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
774 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
776 /* If they are allowauthed to this account, allow it (removing the aa). */
777 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
778 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
781 /* The user is not allowed to use this account. */
786 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
789 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
791 if (len
< nickserv_conf
.password_min_length
) {
793 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
796 if (!irccasecmp(pass
, handle
)) {
798 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
801 dict_find(nickserv_conf
.weak_password_dict
, pass
, &i
);
804 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
807 for (i
=0; i
<len
; i
++) {
808 if (isdigit(pass
[i
]))
810 if (isupper(pass
[i
]))
812 if (islower(pass
[i
]))
815 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
816 || (cnt_upper
< nickserv_conf
.password_min_upper
)
817 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
819 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
825 static auth_func_t
*auth_func_list
;
826 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
829 reg_auth_func(auth_func_t func
)
831 if (auth_func_used
== auth_func_size
) {
832 if (auth_func_size
) {
833 auth_func_size
<<= 1;
834 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
837 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
840 auth_func_list
[auth_func_used
++] = func
;
843 static handle_rename_func_t
*rf_list
;
844 static unsigned int rf_list_size
, rf_list_used
;
847 reg_handle_rename_func(handle_rename_func_t func
)
849 if (rf_list_used
== rf_list_size
) {
852 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
855 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
858 rf_list
[rf_list_used
++] = func
;
862 generate_fakehost(struct handle_info
*handle
)
864 extern const char *hidden_host_suffix
;
865 static char buffer
[HOSTLEN
+1];
867 if (!handle
->fakehost
) {
868 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
870 } else if (handle
->fakehost
[0] == '.') {
871 /* A leading dot indicates the stored value is actually a title. */
872 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
875 return handle
->fakehost
;
879 apply_fakehost(struct handle_info
*handle
)
881 struct userNode
*target
;
886 fake
= generate_fakehost(handle
);
887 for (target
= handle
->users
; target
; target
= target
->next_authed
)
888 assign_fakehost(target
, fake
, 1);
892 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
895 struct handle_info
*old_info
;
897 /* This can happen if somebody uses COOKIE while authed, or if
898 * they re-auth to their current handle (which is silly, but users
900 if (user
->handle_info
== hi
)
903 if (user
->handle_info
) {
904 struct userNode
*other
;
907 userList_remove(&curr_helpers
, user
);
909 /* remove from next_authed linked list */
910 if (user
->handle_info
->users
== user
) {
911 user
->handle_info
->users
= user
->next_authed
;
913 for (other
= user
->handle_info
->users
;
914 other
->next_authed
!= user
;
915 other
= other
->next_authed
) ;
916 other
->next_authed
= user
->next_authed
;
918 /* if nobody left on old handle, and they're not an oper, remove !god */
919 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
920 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
921 /* record them as being last seen at this time */
922 user
->handle_info
->lastseen
= now
;
923 /* and record their hostmask */
924 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
926 old_info
= user
->handle_info
;
927 user
->handle_info
= hi
;
928 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
929 HANDLE_CLEAR_FLAG(hi
, HELPING
);
930 for (n
=0; n
<auth_func_used
; n
++)
931 auth_func_list
[n
](user
, old_info
);
933 struct nick_info
*ni
;
935 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
936 if (nickserv_conf
.warn_clone_auth
) {
937 struct userNode
*other
;
938 for (other
= hi
->users
; other
; other
= other
->next_authed
)
939 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
941 user
->next_authed
= hi
->users
;
945 userList_append(&curr_helpers
, user
);
947 if (hi
->fakehost
|| old_info
)
951 #ifdef WITH_PROTOCOL_BAHAMUT
952 /* Stamp users with their account ID. */
954 inttobase64(id
, hi
->id
, IDLEN
);
955 #elif WITH_PROTOCOL_P10
956 /* Stamp users with their account name. */
957 char *id
= hi
->handle
;
959 const char *id
= "???";
961 if (!nickserv_conf
.disable_nicks
) {
962 struct nick_info
*ni
;
963 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
964 if (!irccasecmp(user
->nick
, ni
->nick
)) {
965 user
->modes
|= FLAGS_REGNICK
;
970 StampUser(user
, id
, hi
->registered
);
973 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
974 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
976 /* We cannot clear the user's account ID, unfortunately. */
977 user
->next_authed
= NULL
;
981 static struct handle_info
*
982 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
984 struct handle_info
*hi
;
985 struct nick_info
*ni
;
986 char crypted
[MD5_CRYPT_LENGTH
];
988 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
989 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
993 if(strlen(handle
) > 15)
995 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
999 if (!is_secure_password(handle
, passwd
, user
))
1002 cryptpass(passwd
, crypted
);
1003 hi
= register_handle(handle
, crypted
, 0);
1004 hi
->masks
= alloc_string_list(1);
1006 hi
->language
= lang_C
;
1007 hi
->registered
= now
;
1009 hi
->flags
= HI_DEFAULT_FLAGS
;
1010 if (settee
&& !no_auth
)
1011 set_user_handle_info(settee
, hi
, 1);
1014 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1015 else if (nickserv_conf
.disable_nicks
)
1016 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1017 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1018 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1020 register_nick(user
->nick
, hi
);
1021 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1023 if (settee
&& (user
!= settee
))
1024 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1029 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1031 cookie
->hi
->cookie
= cookie
;
1032 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1036 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1038 struct handle_cookie
*cookie
;
1039 char subject
[128], body
[4096], *misc
;
1040 const char *netname
, *fmt
;
1044 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1048 cookie
= calloc(1, sizeof(*cookie
));
1050 cookie
->type
= type
;
1051 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1052 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1053 inttobase64(cookie
->cookie
, rand(), 5);
1054 inttobase64(cookie
->cookie
+5, rand(), 5);
1056 netname
= nickserv_conf
.network_name
;
1059 switch (cookie
->type
) {
1061 hi
->passwd
[0] = 0; /* invalidate password */
1062 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1063 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1064 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1067 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1069 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1071 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1074 case PASSWORD_CHANGE
:
1075 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1076 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1077 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1079 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1081 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1082 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1085 misc
= hi
->email_addr
;
1086 hi
->email_addr
= cookie
->data
;
1088 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1089 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1090 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1091 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1092 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1093 sendmail(nickserv
, hi
, subject
, body
, 1);
1094 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1095 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1097 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1098 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1099 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1100 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1101 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1102 sendmail(nickserv
, hi
, subject
, body
, 1);
1105 hi
->email_addr
= misc
;
1108 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1109 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1110 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1111 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1112 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1115 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1119 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1120 nickserv_bake_cookie(cookie
);
1124 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1126 cookie
->hi
->cookie
= NULL
;
1127 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1128 nickserv_free_cookie(cookie
);
1132 nickserv_free_email_addr(void *data
)
1134 handle_info_list_clean(data
);
1139 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1141 struct handle_info_list
*hil
;
1142 /* Remove from old handle_info_list ... */
1143 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1144 handle_info_list_remove(hil
, hi
);
1145 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1146 hi
->email_addr
= NULL
;
1148 /* Add to the new list.. */
1149 if (new_email_addr
) {
1150 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1151 hil
= calloc(1, sizeof(*hil
));
1152 hil
->tag
= strdup(new_email_addr
);
1153 handle_info_list_init(hil
);
1154 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1156 handle_info_list_append(hil
, hi
);
1157 hi
->email_addr
= hil
->tag
;
1161 static NICKSERV_FUNC(cmd_register
)
1163 struct handle_info
*hi
;
1164 const char *email_addr
, *password
;
1165 char syncpass
[MD5_CRYPT_LENGTH
];
1166 int no_auth
, weblink
;
1168 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1169 /* Require the first handle registered to belong to someone +o. */
1170 reply("NSMSG_REQUIRE_OPER");
1174 if (user
->handle_info
) {
1175 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1179 if (IsRegistering(user
)) {
1180 reply("NSMSG_ALREADY_REGISTERING");
1184 if (IsStamped(user
)) {
1185 /* Unauthenticated users might still have been stamped
1186 previously and could therefore have a hidden host;
1187 do not allow them to register a new account. */
1188 reply("NSMSG_STAMPED_REGISTER");
1192 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1194 if (!is_valid_handle(argv
[1])) {
1195 reply("NSMSG_BAD_HANDLE", argv
[1]);
1200 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1201 struct handle_info_list
*hil
;
1204 /* Remember email address. */
1205 email_addr
= argv
[3];
1207 /* Check that the email address looks valid.. */
1208 if (!is_valid_email_addr(email_addr
)) {
1209 reply("NSMSG_BAD_EMAIL_ADDR");
1213 /* .. and that we are allowed to send to it. */
1214 if ((str
= sendmail_prohibited_address(email_addr
))) {
1215 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1219 /* If we do email verify, make sure we don't spam the address. */
1220 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1222 for (nn
=0; nn
<hil
->used
; nn
++) {
1223 if (hil
->list
[nn
]->cookie
) {
1224 reply("NSMSG_EMAIL_UNACTIVATED");
1228 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1229 reply("NSMSG_EMAIL_OVERUSED");
1242 /* Webregister hack - send URL instead of IRC cookie
1245 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1249 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1251 /* Add any masks they should get. */
1252 if (nickserv_conf
.default_hostmask
) {
1253 string_list_append(hi
->masks
, strdup("*@*"));
1255 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1256 if (user
->ip
.s_addr
&& user
->hostname
[strspn(user
->hostname
, "0123456789.")])
1257 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1260 /* If they're the first to register, give them level 1000. */
1261 if (dict_size(nickserv_handle_dict
) == 1) {
1262 hi
->opserv_level
= 1000;
1263 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1266 /* Set their email address. */
1268 nickserv_set_email_addr(hi
, email_addr
);
1270 /* If they need to do email verification, tell them. */
1272 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1274 /* Set registering flag.. */
1275 user
->modes
|= FLAGS_REGISTERING
;
1277 if (nickserv_conf
.sync_log
) {
1278 cryptpass(password
, syncpass
);
1280 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1281 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1284 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1290 static NICKSERV_FUNC(cmd_oregister
)
1293 struct userNode
*settee
;
1294 struct handle_info
*hi
;
1296 NICKSERV_MIN_PARMS(4);
1298 if (!is_valid_handle(argv
[1])) {
1299 reply("NSMSG_BAD_HANDLE", argv
[1]);
1303 if (strchr(argv
[3], '@')) {
1304 mask
= canonicalize_hostmask(strdup(argv
[3]));
1306 settee
= GetUserH(argv
[4]);
1308 reply("MSG_NICK_UNKNOWN", argv
[4]);
1315 } else if ((settee
= GetUserH(argv
[3]))) {
1316 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1318 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1321 if (settee
&& settee
->handle_info
) {
1322 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1326 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1330 string_list_append(hi
->masks
, mask
);
1334 static NICKSERV_FUNC(cmd_handleinfo
)
1337 unsigned int i
, pos
=0, herelen
;
1338 struct userNode
*target
, *next_un
;
1339 struct handle_info
*hi
;
1340 const char *nsmsg_none
;
1343 if (!(hi
= user
->handle_info
)) {
1344 reply("NSMSG_MUST_AUTH");
1347 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1351 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1352 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1353 #ifdef WITH_PROTOCOL_BAHAMUT
1354 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1356 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1359 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1360 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1362 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1365 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1366 if (HANDLE_FLAGGED(hi
, FROZEN
))
1367 reply("NSMSG_HANDLEINFO_VACATION");
1369 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1370 struct do_not_register
*dnr
;
1371 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1372 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1373 if (!oper_outranks(user
, hi
))
1375 } else if (hi
!= user
->handle_info
)
1378 if (nickserv_conf
.email_enabled
)
1379 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1383 switch (hi
->cookie
->type
) {
1384 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1385 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1386 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1387 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1388 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1394 unsigned long flen
= 1;
1395 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1397 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1398 if (hi
->flags
& 1 << i
)
1399 flags
[flen
++] = handle_flags
[i
];
1401 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1403 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1406 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1407 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1408 || (hi
->opserv_level
> 0)) {
1409 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1413 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1415 if (hi
->last_quit_host
[0])
1416 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1418 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1420 if (nickserv_conf
.disable_nicks
) {
1421 /* nicks disabled; don't show anything about registered nicks */
1422 } else if (hi
->nicks
) {
1423 struct nick_info
*ni
, *next_ni
;
1424 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1425 herelen
= strlen(ni
->nick
);
1426 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1428 goto print_nicks_buff
;
1432 memcpy(buff
+pos
, ni
->nick
, herelen
);
1433 pos
+= herelen
; buff
[pos
++] = ' ';
1437 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1442 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1445 if (hi
->masks
->used
) {
1446 for (i
=0; i
< hi
->masks
->used
; i
++) {
1447 herelen
= strlen(hi
->masks
->list
[i
]);
1448 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1450 goto print_mask_buff
;
1452 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1453 pos
+= herelen
; buff
[pos
++] = ' ';
1454 if (i
+1 == hi
->masks
->used
) {
1457 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1462 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1466 struct userData
*channel
, *next
;
1469 for (channel
= hi
->channels
; channel
; channel
= next
) {
1470 next
= channel
->u_next
;
1471 name
= channel
->channel
->channel
->name
;
1472 herelen
= strlen(name
);
1473 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1475 goto print_chans_buff
;
1477 if (IsUserSuspended(channel
))
1479 pos
+= sprintf(buff
+pos
, "%d:%s ", channel
->access
, name
);
1483 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1488 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1491 for (target
= hi
->users
; target
; target
= next_un
) {
1492 herelen
= strlen(target
->nick
);
1493 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1495 goto print_cnick_buff
;
1497 next_un
= target
->next_authed
;
1499 memcpy(buff
+pos
, target
->nick
, herelen
);
1500 pos
+= herelen
; buff
[pos
++] = ' ';
1504 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1512 static NICKSERV_FUNC(cmd_userinfo
)
1514 struct userNode
*target
;
1516 NICKSERV_MIN_PARMS(2);
1517 if (!(target
= GetUserH(argv
[1]))) {
1518 reply("MSG_NICK_UNKNOWN", argv
[1]);
1521 if (target
->handle_info
)
1522 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1524 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1528 static NICKSERV_FUNC(cmd_nickinfo
)
1530 struct nick_info
*ni
;
1532 NICKSERV_MIN_PARMS(2);
1533 if (!(ni
= get_nick_info(argv
[1]))) {
1534 reply("MSG_NICK_UNKNOWN", argv
[1]);
1537 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1541 static NICKSERV_FUNC(cmd_rename_handle
)
1543 struct handle_info
*hi
;
1544 char msgbuf
[MAXLEN
], *old_handle
;
1547 NICKSERV_MIN_PARMS(3);
1548 if (!(hi
= get_victim_oper(user
, argv
[1])))
1550 if (!is_valid_handle(argv
[2])) {
1551 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1554 if (get_handle_info(argv
[2])) {
1555 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1558 if(strlen(argv
[2]) > 15)
1560 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1564 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1565 hi
->handle
= strdup(argv
[2]);
1566 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1567 for (nn
=0; nn
<rf_list_used
; nn
++)
1568 rf_list
[nn
](hi
, old_handle
);
1569 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1570 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1571 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1576 static failpw_func_t
*failpw_func_list
;
1577 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1580 reg_failpw_func(failpw_func_t func
)
1582 if (failpw_func_used
== failpw_func_size
) {
1583 if (failpw_func_size
) {
1584 failpw_func_size
<<= 1;
1585 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1587 failpw_func_size
= 8;
1588 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1591 failpw_func_list
[failpw_func_used
++] = func
;
1595 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1597 * called by nefariouses enhanced AC login-on-connect code
1600 struct handle_info
*loc_auth(char *handle
, char *password
)
1602 int pw_arg
, used
, maxlogins
;
1605 struct handle_info
*hi
;
1606 struct userNode
*other
;
1608 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1614 /* We don't know the users hostname, or anything because they
1615 * havn't registered yet. So we can only allow LOC if your
1616 * account has *@* as a hostmask.
1618 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1620 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1629 /* Responses from here on look up the language used by the handle they asked about. */
1630 if (!checkpass(password
, hi
->passwd
)) {
1633 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1636 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1637 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1638 if (++used
>= maxlogins
) {
1645 static NICKSERV_FUNC(cmd_auth
)
1647 int pw_arg
, used
, maxlogins
;
1648 struct handle_info
*hi
;
1650 struct userNode
*other
;
1652 if (user
->handle_info
) {
1653 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1656 if (IsStamped(user
)) {
1657 /* Unauthenticated users might still have been stamped
1658 previously and could therefore have a hidden host;
1659 do not allow them to authenticate. */
1660 reply("NSMSG_STAMPED_AUTH");
1664 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1666 } else if (argc
== 2) {
1667 if (nickserv_conf
.disable_nicks
) {
1668 if (!(hi
= get_handle_info(user
->nick
))) {
1669 reply("NSMSG_HANDLE_NOT_FOUND");
1673 /* try to look up their handle from their nick */
1674 struct nick_info
*ni
;
1675 ni
= get_nick_info(user
->nick
);
1677 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1684 reply("MSG_MISSING_PARAMS", argv
[0]);
1685 svccmd_send_help(user
, nickserv
, cmd
);
1689 reply("NSMSG_HANDLE_NOT_FOUND");
1692 /* Responses from here on look up the language used by the handle they asked about. */
1693 passwd
= argv
[pw_arg
];
1694 if (!valid_user_for(user
, hi
)) {
1695 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1696 send_message_type(4, user
, cmd
->parent
->bot
,
1697 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1700 send_message_type(4, user
, cmd
->parent
->bot
,
1701 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1703 argv
[pw_arg
] = "BADMASK";
1706 if (!checkpass(passwd
, hi
->passwd
)) {
1708 send_message_type(4, user
, cmd
->parent
->bot
,
1709 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1710 argv
[pw_arg
] = "BADPASS";
1711 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1712 if (nickserv_conf
.autogag_enabled
) {
1713 if (!user
->auth_policer
.params
) {
1714 user
->auth_policer
.last_req
= now
;
1715 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1717 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1719 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1720 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1721 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1723 argv
[pw_arg
] = "GAGGED";
1728 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1729 send_message_type(4, user
, cmd
->parent
->bot
,
1730 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1731 argv
[pw_arg
] = "SUSPENDED";
1734 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1735 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1736 if (++used
>= maxlogins
) {
1737 send_message_type(4, user
, cmd
->parent
->bot
,
1738 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1740 argv
[pw_arg
] = "MAXLOGINS";
1745 set_user_handle_info(user
, hi
, 1);
1746 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1747 reply("NSMSG_PLEASE_SET_EMAIL");
1748 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1749 reply("NSMSG_WEAK_PASSWORD");
1750 if (hi
->passwd
[0] != '$')
1751 cryptpass(passwd
, hi
->passwd
);
1752 reply("NSMSG_AUTH_SUCCESS");
1753 argv
[pw_arg
] = "****";
1757 static allowauth_func_t
*allowauth_func_list
;
1758 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
1761 reg_allowauth_func(allowauth_func_t func
)
1763 if (allowauth_func_used
== allowauth_func_size
) {
1764 if (allowauth_func_size
) {
1765 allowauth_func_size
<<= 1;
1766 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
1768 allowauth_func_size
= 8;
1769 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
1772 allowauth_func_list
[allowauth_func_used
++] = func
;
1775 static NICKSERV_FUNC(cmd_allowauth
)
1777 struct userNode
*target
;
1778 struct handle_info
*hi
;
1781 NICKSERV_MIN_PARMS(2);
1782 if (!(target
= GetUserH(argv
[1]))) {
1783 reply("MSG_NICK_UNKNOWN", argv
[1]);
1786 if (target
->handle_info
) {
1787 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
1790 if (IsStamped(target
)) {
1791 /* Unauthenticated users might still have been stamped
1792 previously and could therefore have a hidden host;
1793 do not allow them to authenticate to an account. */
1794 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
1799 else if (!(hi
= get_handle_info(argv
[2]))) {
1800 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
1804 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
1805 reply("MSG_USER_OUTRANKED", hi
->handle
);
1808 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
1809 || (hi
->opserv_level
> 0))
1810 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
1811 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
1814 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
1815 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
1816 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
1817 if (nickserv_conf
.email_enabled
)
1818 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
1820 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
1821 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
1823 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
1825 for (n
=0; n
<allowauth_func_used
; n
++)
1826 allowauth_func_list
[n
](user
, target
, hi
);
1830 static NICKSERV_FUNC(cmd_authcookie
)
1832 struct handle_info
*hi
;
1834 NICKSERV_MIN_PARMS(2);
1835 if (user
->handle_info
) {
1836 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1839 if (IsStamped(user
)) {
1840 /* Unauthenticated users might still have been stamped
1841 previously and could therefore have a hidden host;
1842 do not allow them to authenticate to an account. */
1843 reply("NSMSG_STAMPED_AUTHCOOKIE");
1846 if (!(hi
= get_handle_info(argv
[1]))) {
1847 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1850 if (!hi
->email_addr
) {
1851 reply("MSG_SET_EMAIL_ADDR");
1854 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
1858 static NICKSERV_FUNC(cmd_delcookie
)
1860 struct handle_info
*hi
;
1862 hi
= user
->handle_info
;
1864 reply("NSMSG_NO_COOKIE");
1867 switch (hi
->cookie
->type
) {
1870 reply("NSMSG_MUST_TIME_OUT");
1873 nickserv_eat_cookie(hi
->cookie
);
1874 reply("NSMSG_ATE_COOKIE");
1880 static NICKSERV_FUNC(cmd_resetpass
)
1882 struct handle_info
*hi
;
1883 char crypted
[MD5_CRYPT_LENGTH
];
1886 NICKSERV_MIN_PARMS(3);
1887 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
1891 if (user
->handle_info
) {
1892 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1895 if (IsStamped(user
)) {
1896 /* Unauthenticated users might still have been stamped
1897 previously and could therefore have a hidden host;
1898 do not allow them to activate an account. */
1899 reply("NSMSG_STAMPED_RESETPASS");
1902 if (!(hi
= get_handle_info(argv
[1]))) {
1903 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1906 if (!hi
->email_addr
) {
1907 reply("MSG_SET_EMAIL_ADDR");
1910 cryptpass(argv
[2], crypted
);
1912 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
1916 static NICKSERV_FUNC(cmd_cookie
)
1918 struct handle_info
*hi
;
1921 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
1924 NICKSERV_MIN_PARMS(3);
1925 if (!(hi
= get_handle_info(argv
[1]))) {
1926 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1932 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1933 reply("NSMSG_HANDLE_SUSPENDED");
1938 reply("NSMSG_NO_COOKIE");
1942 /* Check validity of operation before comparing cookie to
1943 * prohibit guessing by authed users. */
1944 if (user
->handle_info
1945 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
1946 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
1947 reply("NSMSG_CANNOT_COOKIE");
1951 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
1952 reply("NSMSG_BAD_COOKIE");
1956 switch (hi
->cookie
->type
) {
1958 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
1959 set_user_handle_info(user
, hi
, 1);
1960 reply("NSMSG_HANDLE_ACTIVATED");
1961 if (nickserv_conf
.sync_log
)
1962 SyncLog("ACCOUNTACC %s", hi
->handle
);
1964 case PASSWORD_CHANGE
:
1965 set_user_handle_info(user
, hi
, 1);
1966 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
1967 reply("NSMSG_PASSWORD_CHANGED");
1968 if (nickserv_conf
.sync_log
)
1969 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
1972 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
1974 * This should only happen if an OREGISTER was sent. Require
1975 * email must be enabled! - SiRVulcaN
1977 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
1979 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
1980 reply("NSMSG_EMAIL_CHANGED");
1981 if (nickserv_conf
.sync_log
)
1982 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
1985 set_user_handle_info(user
, hi
, 1);
1986 reply("NSMSG_AUTH_SUCCESS");
1989 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
1990 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
1994 nickserv_eat_cookie(hi
->cookie
);
1999 static NICKSERV_FUNC(cmd_oregnick
) {
2001 struct handle_info
*target
;
2002 struct nick_info
*ni
;
2004 NICKSERV_MIN_PARMS(3);
2005 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2008 if (!is_registerable_nick(nick
)) {
2009 reply("NSMSG_BAD_NICK", nick
);
2012 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2014 reply("NSMSG_NICK_EXISTS", nick
);
2017 register_nick(nick
, target
);
2018 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2022 static NICKSERV_FUNC(cmd_regnick
) {
2024 struct nick_info
*ni
;
2026 if (!is_registerable_nick(user
->nick
)) {
2027 reply("NSMSG_BAD_NICK", user
->nick
);
2030 /* count their nicks, see if it's too many */
2031 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2032 if (n
>= nickserv_conf
.nicks_per_handle
) {
2033 reply("NSMSG_TOO_MANY_NICKS");
2036 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2038 reply("NSMSG_NICK_EXISTS", user
->nick
);
2041 register_nick(user
->nick
, user
->handle_info
);
2042 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2046 static NICKSERV_FUNC(cmd_pass
)
2048 struct handle_info
*hi
;
2049 const char *old_pass
, *new_pass
;
2051 NICKSERV_MIN_PARMS(3);
2052 hi
= user
->handle_info
;
2056 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2057 if (!checkpass(old_pass
, hi
->passwd
)) {
2058 argv
[1] = "BADPASS";
2059 reply("NSMSG_PASSWORD_INVALID");
2062 cryptpass(new_pass
, hi
->passwd
);
2063 if (nickserv_conf
.sync_log
)
2064 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2066 reply("NSMSG_PASS_SUCCESS");
2071 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2074 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2075 for (i
=0; i
<hi
->masks
->used
; i
++) {
2076 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2077 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2082 string_list_append(hi
->masks
, new_mask
);
2083 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2087 static NICKSERV_FUNC(cmd_addmask
)
2090 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2091 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2095 if (!is_gline(argv
[1])) {
2096 reply("NSMSG_MASK_INVALID", argv
[1]);
2099 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2103 static NICKSERV_FUNC(cmd_oaddmask
)
2105 struct handle_info
*hi
;
2107 NICKSERV_MIN_PARMS(3);
2108 if (!(hi
= get_victim_oper(user
, argv
[1])))
2110 return nickserv_addmask(user
, hi
, argv
[2]);
2114 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2117 for (i
=0; i
<hi
->masks
->used
; i
++) {
2118 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2119 char *old_mask
= hi
->masks
->list
[i
];
2120 if (hi
->masks
->used
== 1) {
2121 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2124 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2125 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2130 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2134 static NICKSERV_FUNC(cmd_delmask
)
2136 NICKSERV_MIN_PARMS(2);
2137 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2140 static NICKSERV_FUNC(cmd_odelmask
)
2142 struct handle_info
*hi
;
2143 NICKSERV_MIN_PARMS(3);
2144 if (!(hi
= get_victim_oper(user
, argv
[1])))
2146 return nickserv_delmask(user
, hi
, argv
[2]);
2150 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2151 unsigned int nn
, add
= 1, pos
;
2152 unsigned long added
, removed
, flag
;
2154 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2156 case '+': add
= 1; break;
2157 case '-': add
= 0; break;
2159 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2160 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2163 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2164 /* cheesy avoidance of looking up the flag name.. */
2165 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2168 flag
= 1 << (pos
- 1);
2170 added
|= flag
, removed
&= ~flag
;
2172 removed
|= flag
, added
&= ~flag
;
2177 *premoved
= removed
;
2182 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2184 unsigned long before
, after
, added
, removed
;
2185 struct userNode
*uNode
;
2187 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2188 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2190 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2191 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2193 /* Strip helping flag if they're only a support helper and not
2194 * currently in #support. */
2195 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2196 struct channelList
*schannels
;
2198 schannels
= chanserv_support_channels();
2199 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2200 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2201 if (GetUserMode(schannels
->list
[ii
], uNode
))
2203 if (ii
< schannels
->used
)
2207 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2210 if (after
&& !before
) {
2211 /* Add user to current helper list. */
2212 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2213 userList_append(&curr_helpers
, uNode
);
2214 } else if (!after
&& before
) {
2215 /* Remove user from current helper list. */
2216 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2217 userList_remove(&curr_helpers
, uNode
);
2224 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2228 char *set_display
[] = {
2229 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2230 "EMAIL", "ANNOUNCEMENTS", "MAXLOGINS", "LANGUAGE"
2233 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2235 /* Do this so options are presented in a consistent order. */
2236 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2237 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2238 opt(user
, hi
, override
, 0, NULL
);
2241 static NICKSERV_FUNC(cmd_set
)
2243 struct handle_info
*hi
;
2246 hi
= user
->handle_info
;
2248 set_list(user
, hi
, 0);
2251 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2252 reply("NSMSG_INVALID_OPTION", argv
[1]);
2255 return opt(user
, hi
, 0, argc
-1, argv
+1);
2258 static NICKSERV_FUNC(cmd_oset
)
2260 struct handle_info
*hi
;
2263 NICKSERV_MIN_PARMS(2);
2265 if (!(hi
= get_victim_oper(user
, argv
[1])))
2269 set_list(user
, hi
, 0);
2273 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2274 reply("NSMSG_INVALID_OPTION", argv
[2]);
2278 return opt(user
, hi
, 1, argc
-2, argv
+2);
2281 static OPTION_FUNC(opt_info
)
2285 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2287 hi
->infoline
= NULL
;
2289 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2293 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2294 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2298 static OPTION_FUNC(opt_width
)
2301 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2303 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2304 hi
->screen_width
= MIN_LINE_SIZE
;
2305 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2306 hi
->screen_width
= MAX_LINE_SIZE
;
2308 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2312 static OPTION_FUNC(opt_tablewidth
)
2315 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2317 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2318 hi
->table_width
= MIN_LINE_SIZE
;
2319 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2320 hi
->table_width
= MAX_LINE_SIZE
;
2322 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2326 static OPTION_FUNC(opt_color
)
2329 if (enabled_string(argv
[1]))
2330 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2331 else if (disabled_string(argv
[1]))
2332 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2334 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2339 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2343 static OPTION_FUNC(opt_privmsg
)
2346 if (enabled_string(argv
[1]))
2347 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2348 else if (disabled_string(argv
[1]))
2349 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2351 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2356 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2360 static OPTION_FUNC(opt_style
)
2365 if (!irccasecmp(argv
[1], "Zoot"))
2366 hi
->userlist_style
= HI_STYLE_ZOOT
;
2367 else if (!irccasecmp(argv
[1], "def"))
2368 hi
->userlist_style
= HI_STYLE_DEF
;
2371 switch (hi
->userlist_style
) {
2380 send_message(user
, nickserv
, "NSMSG_SET_STYLE", style
);
2384 static OPTION_FUNC(opt_announcements
)
2389 if (enabled_string(argv
[1]))
2390 hi
->announcements
= 'y';
2391 else if (disabled_string(argv
[1]))
2392 hi
->announcements
= 'n';
2393 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2394 hi
->announcements
= '?';
2396 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2401 switch (hi
->announcements
) {
2402 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2403 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2404 case '?': choice
= "default"; break;
2405 default: choice
= "unknown"; break;
2407 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2411 static OPTION_FUNC(opt_password
)
2414 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2419 cryptpass(argv
[1], hi
->passwd
);
2421 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2425 static OPTION_FUNC(opt_flags
)
2428 unsigned int ii
, flen
;
2431 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2436 nickserv_apply_flags(user
, hi
, argv
[1]);
2438 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2439 if (hi
->flags
& (1 << ii
))
2440 flags
[flen
++] = handle_flags
[ii
];
2443 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2445 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2449 static OPTION_FUNC(opt_email
)
2453 if (!is_valid_email_addr(argv
[1])) {
2454 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2457 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2458 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2461 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2462 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2464 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2466 nickserv_set_email_addr(hi
, argv
[1]);
2468 nickserv_eat_cookie(hi
->cookie
);
2469 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2472 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2476 static OPTION_FUNC(opt_maxlogins
)
2478 unsigned char maxlogins
;
2480 maxlogins
= strtoul(argv
[1], NULL
, 0);
2481 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2482 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2485 hi
->maxlogins
= maxlogins
;
2487 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2488 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2492 static OPTION_FUNC(opt_language
)
2494 struct language
*lang
;
2496 lang
= language_find(argv
[1]);
2497 if (irccasecmp(lang
->name
, argv
[1]))
2498 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2499 hi
->language
= lang
;
2501 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2506 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2507 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2509 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2510 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2511 && (user
->handle_info
->opserv_level
< 1000))) {
2512 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2515 if ((user
->handle_info
->opserv_level
< new_level
)
2516 || ((user
->handle_info
->opserv_level
== new_level
)
2517 && (user
->handle_info
->opserv_level
< 1000))) {
2518 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2521 if (user
->handle_info
== target
) {
2522 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2525 if (target
->opserv_level
== new_level
)
2527 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2528 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2529 target
->opserv_level
= new_level
;
2533 static OPTION_FUNC(opt_level
)
2538 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2542 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2543 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2547 static OPTION_FUNC(opt_epithet
)
2550 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2554 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2555 char *epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2558 if ((epithet
[0] == '*') && !epithet
[1])
2561 hi
->epithet
= strdup(epithet
);
2565 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2567 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2571 static OPTION_FUNC(opt_title
)
2576 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2580 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2582 if (strchr(title
, '.')) {
2583 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2586 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2587 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2588 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2593 if (!strcmp(title
, "*")) {
2594 hi
->fakehost
= NULL
;
2596 hi
->fakehost
= malloc(strlen(title
)+2);
2597 hi
->fakehost
[0] = '.';
2598 strcpy(hi
->fakehost
+1, title
);
2601 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2602 title
= hi
->fakehost
+ 1;
2606 title
= user_find_message(user
, "MSG_NONE");
2607 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2611 static OPTION_FUNC(opt_fakehost
)
2616 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2620 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2622 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
2623 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
2627 if (!strcmp(fake
, "*"))
2628 hi
->fakehost
= NULL
;
2630 hi
->fakehost
= strdup(fake
);
2631 fake
= hi
->fakehost
;
2634 fake
= generate_fakehost(hi
);
2636 fake
= user_find_message(user
, "MSG_NONE");
2637 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
2641 static NICKSERV_FUNC(cmd_reclaim
)
2643 struct handle_info
*hi
;
2644 struct nick_info
*ni
;
2645 struct userNode
*victim
;
2647 NICKSERV_MIN_PARMS(2);
2648 hi
= user
->handle_info
;
2649 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
2651 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
2654 if (ni
->owner
!= user
->handle_info
) {
2655 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
2658 victim
= GetUserH(ni
->nick
);
2660 reply("MSG_NICK_UNKNOWN", ni
->nick
);
2663 if (victim
== user
) {
2664 reply("NSMSG_NICK_USER_YOU");
2667 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
2668 switch (nickserv_conf
.reclaim_action
) {
2669 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
2670 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
2671 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
2672 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
2677 static NICKSERV_FUNC(cmd_unregnick
)
2680 struct handle_info
*hi
;
2681 struct nick_info
*ni
;
2683 hi
= user
->handle_info
;
2684 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
2685 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2687 reply("NSMSG_UNKNOWN_NICK", nick
);
2690 if (hi
!= ni
->owner
) {
2691 reply("NSMSG_NOT_YOUR_NICK", nick
);
2694 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2699 static NICKSERV_FUNC(cmd_ounregnick
)
2701 struct nick_info
*ni
;
2703 NICKSERV_MIN_PARMS(2);
2704 if (!(ni
= get_nick_info(argv
[1]))) {
2705 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
2708 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
2709 reply("MSG_USER_OUTRANKED", ni
->nick
);
2712 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2717 static NICKSERV_FUNC(cmd_unregister
)
2719 struct handle_info
*hi
;
2722 NICKSERV_MIN_PARMS(2);
2723 hi
= user
->handle_info
;
2726 if (checkpass(passwd
, hi
->passwd
)) {
2727 nickserv_unregister_handle(hi
, user
);
2730 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
2731 reply("NSMSG_PASSWORD_INVALID");
2736 static NICKSERV_FUNC(cmd_ounregister
)
2738 struct handle_info
*hi
;
2740 NICKSERV_MIN_PARMS(2);
2741 if (!(hi
= get_victim_oper(user
, argv
[1])))
2743 nickserv_unregister_handle(hi
, user
);
2747 static NICKSERV_FUNC(cmd_status
)
2749 if (nickserv_conf
.disable_nicks
) {
2750 reply("NSMSG_GLOBAL_STATS_NONICK",
2751 dict_size(nickserv_handle_dict
));
2753 if (user
->handle_info
) {
2755 struct nick_info
*ni
;
2756 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
2757 reply("NSMSG_HANDLE_STATS", cnt
);
2759 reply("NSMSG_HANDLE_NONE");
2761 reply("NSMSG_GLOBAL_STATS",
2762 dict_size(nickserv_handle_dict
),
2763 dict_size(nickserv_nick_dict
));
2768 static NICKSERV_FUNC(cmd_ghost
)
2770 struct userNode
*target
;
2771 char reason
[MAXLEN
];
2773 NICKSERV_MIN_PARMS(2);
2774 if (!(target
= GetUserH(argv
[1]))) {
2775 reply("MSG_NICK_UNKNOWN", argv
[1]);
2778 if (target
== user
) {
2779 reply("NSMSG_CANNOT_GHOST_SELF");
2782 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
2783 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
2786 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
2787 DelUser(target
, nickserv
, 1, reason
);
2788 reply("NSMSG_GHOST_KILLED", argv
[1]);
2792 static NICKSERV_FUNC(cmd_vacation
)
2794 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
2795 reply("NSMSG_ON_VACATION");
2800 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
2802 struct handle_info
*hi
;
2805 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
2807 #ifdef WITH_PROTOCOL_BAHAMUT
2810 saxdb_start_record(ctx
, iter_key(it
), 0);
2811 if (hi
->announcements
!= '?') {
2812 flags
[0] = hi
->announcements
;
2814 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
2817 struct handle_cookie
*cookie
= hi
->cookie
;
2820 switch (cookie
->type
) {
2821 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
2822 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
2823 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
2824 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
2825 default: type
= NULL
; break;
2828 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
2829 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
2830 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
2832 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
2833 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
2834 saxdb_end_record(ctx
);
2838 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
2840 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
2842 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
2846 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
2847 if (hi
->flags
& (1 << ii
))
2848 flags
[flen
++] = handle_flags
[ii
];
2850 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
2852 #ifdef WITH_PROTOCOL_BAHAMUT
2853 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
2856 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
2857 if (hi
->last_quit_host
[0])
2858 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
2859 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
2860 if (hi
->masks
->used
)
2861 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
2863 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
2865 struct string_list
*slist
;
2866 struct nick_info
*ni
;
2868 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
2869 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
2870 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
2874 if (hi
->opserv_level
)
2875 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
2876 if (hi
->language
!= lang_C
)
2877 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
2878 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
2879 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
2880 if (hi
->screen_width
)
2881 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
2882 if (hi
->table_width
)
2883 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
2884 flags
[0] = hi
->userlist_style
;
2886 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
2887 saxdb_end_record(ctx
);
2892 static handle_merge_func_t
*handle_merge_func_list
;
2893 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
2896 reg_handle_merge_func(handle_merge_func_t func
)
2898 if (handle_merge_func_used
== handle_merge_func_size
) {
2899 if (handle_merge_func_size
) {
2900 handle_merge_func_size
<<= 1;
2901 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
2903 handle_merge_func_size
= 8;
2904 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
2907 handle_merge_func_list
[handle_merge_func_used
++] = func
;
2910 static NICKSERV_FUNC(cmd_merge
)
2912 struct handle_info
*hi_from
, *hi_to
;
2913 struct userNode
*last_user
;
2914 struct userData
*cList
, *cListNext
;
2915 unsigned int ii
, jj
, n
;
2916 char buffer
[MAXLEN
];
2918 NICKSERV_MIN_PARMS(3);
2920 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
2922 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
2924 if (hi_to
== hi_from
) {
2925 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
2929 for (n
=0; n
<handle_merge_func_used
; n
++)
2930 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
2932 /* Append "from" handle's nicks to "to" handle's nick list. */
2934 struct nick_info
*last_ni
;
2935 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
2936 last_ni
->next
= hi_from
->nicks
;
2938 while (hi_from
->nicks
) {
2939 hi_from
->nicks
->owner
= hi_to
;
2940 hi_from
->nicks
= hi_from
->nicks
->next
;
2943 /* Merge the hostmasks. */
2944 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
2945 char *mask
= hi_from
->masks
->list
[ii
];
2946 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
2947 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
2949 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
2950 string_list_append(hi_to
->masks
, strdup(mask
));
2953 /* Merge the lists of authed users. */
2955 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
2956 last_user
->next_authed
= hi_from
->users
;
2958 hi_to
->users
= hi_from
->users
;
2960 /* Repoint the old "from" handle's users. */
2961 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
2962 last_user
->handle_info
= hi_to
;
2964 hi_from
->users
= NULL
;
2966 /* Merge channel userlists. */
2967 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
2968 struct userData
*cList2
;
2969 cListNext
= cList
->u_next
;
2970 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
2971 if (cList
->channel
== cList2
->channel
)
2973 if (cList2
&& (cList2
->access
>= cList
->access
)) {
2974 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
);
2975 /* keep cList2 in hi_to; remove cList from hi_from */
2976 del_channel_user(cList
, 1);
2979 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
);
2980 /* remove the lower-ranking cList2 from hi_to */
2981 del_channel_user(cList2
, 1);
2983 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
2985 /* cList needs to be moved from hi_from to hi_to */
2986 cList
->handle
= hi_to
;
2987 /* Remove from linked list for hi_from */
2988 assert(!cList
->u_prev
);
2989 hi_from
->channels
= cList
->u_next
;
2991 cList
->u_next
->u_prev
= cList
->u_prev
;
2992 /* Add to linked list for hi_to */
2993 cList
->u_prev
= NULL
;
2994 cList
->u_next
= hi_to
->channels
;
2995 if (hi_to
->channels
)
2996 hi_to
->channels
->u_prev
= cList
;
2997 hi_to
->channels
= cList
;
3001 /* Do they get an OpServ level promotion? */
3002 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3003 hi_to
->opserv_level
= hi_from
->opserv_level
;
3005 /* What about last seen time? */
3006 if (hi_from
->lastseen
> hi_to
->lastseen
)
3007 hi_to
->lastseen
= hi_from
->lastseen
;
3009 /* Notify of success. */
3010 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3011 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3012 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3014 /* Unregister the "from" handle. */
3015 nickserv_unregister_handle(hi_from
, NULL
);
3020 struct nickserv_discrim
{
3021 unsigned int limit
, min_level
, max_level
;
3022 unsigned long flags_on
, flags_off
;
3023 time_t min_registered
, max_registered
;
3025 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3026 const char *nickmask
;
3027 const char *hostmask
;
3028 const char *handlemask
;
3029 const char *emailmask
;
3032 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3034 struct discrim_apply_info
{
3035 struct nickserv_discrim
*discrim
;
3036 discrim_search_func func
;
3037 struct userNode
*source
;
3038 unsigned int matched
;
3041 static struct nickserv_discrim
*
3042 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3045 struct nickserv_discrim
*discrim
;
3047 discrim
= malloc(sizeof(*discrim
));
3048 memset(discrim
, 0, sizeof(*discrim
));
3049 discrim
->min_level
= 0;
3050 discrim
->max_level
= ~0;
3051 discrim
->limit
= 50;
3052 discrim
->min_registered
= 0;
3053 discrim
->max_registered
= INT_MAX
;
3054 discrim
->lastseen
= now
;
3056 for (i
=0; i
<argc
; i
++) {
3057 if (i
== argc
- 1) {
3058 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3061 if (!irccasecmp(argv
[i
], "limit")) {
3062 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3063 } else if (!irccasecmp(argv
[i
], "flags")) {
3064 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3065 } else if (!irccasecmp(argv
[i
], "registered")) {
3066 const char *cmp
= argv
[++i
];
3067 if (cmp
[0] == '<') {
3068 if (cmp
[1] == '=') {
3069 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3071 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3073 } else if (cmp
[0] == '=') {
3074 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3075 } else if (cmp
[0] == '>') {
3076 if (cmp
[1] == '=') {
3077 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3079 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3082 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3084 } else if (!irccasecmp(argv
[i
], "seen")) {
3085 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3086 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3087 discrim
->nickmask
= argv
[++i
];
3088 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3090 if (!irccasecmp(argv
[i
], "exact")) {
3091 if (i
== argc
- 1) {
3092 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3095 discrim
->hostmask_type
= EXACT
;
3096 } else if (!irccasecmp(argv
[i
], "subset")) {
3097 if (i
== argc
- 1) {
3098 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3101 discrim
->hostmask_type
= SUBSET
;
3102 } else if (!irccasecmp(argv
[i
], "superset")) {
3103 if (i
== argc
- 1) {
3104 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3107 discrim
->hostmask_type
= SUPERSET
;
3108 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3109 if (i
== argc
- 1) {
3110 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3113 discrim
->hostmask_type
= LASTQUIT
;
3116 discrim
->hostmask_type
= SUPERSET
;
3118 discrim
->hostmask
= argv
[++i
];
3119 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3120 if (!irccasecmp(argv
[++i
], "*")) {
3121 discrim
->handlemask
= 0;
3123 discrim
->handlemask
= argv
[i
];
3125 } else if (!irccasecmp(argv
[i
], "email")) {
3126 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3127 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3129 } else if (!irccasecmp(argv
[++i
], "*")) {
3130 discrim
->emailmask
= 0;
3132 discrim
->emailmask
= argv
[i
];
3134 } else if (!irccasecmp(argv
[i
], "access")) {
3135 const char *cmp
= argv
[++i
];
3136 if (cmp
[0] == '<') {
3137 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3138 if (cmp
[1] == '=') {
3139 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3141 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3143 } else if (cmp
[0] == '=') {
3144 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3145 } else if (cmp
[0] == '>') {
3146 if (cmp
[1] == '=') {
3147 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3149 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3152 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3155 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3166 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3168 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3169 || (discrim
->flags_off
& hi
->flags
)
3170 || (discrim
->min_registered
> hi
->registered
)
3171 || (discrim
->max_registered
< hi
->registered
)
3172 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3173 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3174 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3175 || (discrim
->min_level
> hi
->opserv_level
)
3176 || (discrim
->max_level
< hi
->opserv_level
)) {
3179 if (discrim
->hostmask
) {
3181 for (i
=0; i
<hi
->masks
->used
; i
++) {
3182 const char *mask
= hi
->masks
->list
[i
];
3183 if ((discrim
->hostmask_type
== SUBSET
)
3184 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3185 else if ((discrim
->hostmask_type
== EXACT
)
3186 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3187 else if ((discrim
->hostmask_type
== SUPERSET
)
3188 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3189 else if ((discrim
->hostmask_type
== LASTQUIT
)
3190 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3192 if (i
==hi
->masks
->used
) return 0;
3194 if (discrim
->nickmask
) {
3195 struct nick_info
*nick
= hi
->nicks
;
3197 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3200 if (!nick
) return 0;
3206 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3208 dict_iterator_t it
, next
;
3209 unsigned int matched
;
3211 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3212 it
&& (matched
< discrim
->limit
);
3214 next
= iter_next(it
);
3215 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3216 dsf(source
, iter_data(it
));
3224 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3226 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3230 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3235 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3237 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3238 nickserv_unregister_handle(match
, source
);
3242 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3244 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3245 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3246 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3247 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3248 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3252 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3254 struct handle_info_list hil
;
3255 struct helpfile_table tbl
;
3260 memset(&hil
, 0, sizeof(hil
));
3261 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3262 struct handle_info
*hi
= iter_data(it
);
3263 if (hi
->opserv_level
)
3264 handle_info_list_append(&hil
, hi
);
3266 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3267 tbl
.length
= hil
.used
+ 1;
3269 tbl
.flags
= TABLE_NO_FREE
;
3270 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3271 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3274 for (ii
= 0; ii
< hil
.used
; ) {
3275 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3276 ary
[0] = hil
.list
[ii
]->handle
;
3277 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3278 tbl
.contents
[++ii
] = ary
;
3280 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3281 reply("MSG_MATCH_COUNT", hil
.used
);
3282 for (ii
= 0; ii
< hil
.used
; ii
++)
3283 free(tbl
.contents
[ii
]);
3288 static NICKSERV_FUNC(cmd_search
)
3290 struct nickserv_discrim
*discrim
;
3291 discrim_search_func action
;
3292 struct svccmd
*subcmd
;
3293 unsigned int matches
;
3296 NICKSERV_MIN_PARMS(3);
3297 sprintf(buf
, "search %s", argv
[1]);
3298 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3299 if (!irccasecmp(argv
[1], "print"))
3300 action
= search_print_func
;
3301 else if (!irccasecmp(argv
[1], "count"))
3302 action
= search_count_func
;
3303 else if (!irccasecmp(argv
[1], "unregister"))
3304 action
= search_unregister_func
;
3306 reply("NSMSG_INVALID_ACTION", argv
[1]);
3310 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3313 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3317 if (action
== search_print_func
)
3318 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3319 else if (action
== search_count_func
)
3320 discrim
->limit
= INT_MAX
;
3322 matches
= nickserv_discrim_search(discrim
, action
, user
);
3325 reply("MSG_MATCH_COUNT", matches
);
3327 reply("MSG_NO_MATCHES");
3333 static MODCMD_FUNC(cmd_checkpass
)
3335 struct handle_info
*hi
;
3337 NICKSERV_MIN_PARMS(3);
3338 if (!(hi
= get_handle_info(argv
[1]))) {
3339 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3342 if (checkpass(argv
[2], hi
->passwd
))
3343 reply("CHECKPASS_YES");
3345 reply("CHECKPASS_NO");
3351 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3354 struct string_list
*masks
, *slist
;
3355 struct handle_info
*hi
;
3356 struct userNode
*authed_users
;
3357 unsigned long int id
;
3361 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3362 id
= str
? strtoul(str
, NULL
, 0) : 0;
3363 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3365 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3368 if ((hi
= get_handle_info(handle
))) {
3369 authed_users
= hi
->users
;
3371 dict_remove(nickserv_handle_dict
, hi
->handle
);
3373 authed_users
= NULL
;
3375 hi
= register_handle(handle
, str
, id
);
3377 hi
->users
= authed_users
;
3378 while (authed_users
) {
3379 authed_users
->handle_info
= hi
;
3380 authed_users
= authed_users
->next_authed
;
3383 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3384 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3385 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3386 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3387 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3388 hi
->language
= language_find(str
? str
: "C");
3389 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3390 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3391 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3393 hi
->infoline
= strdup(str
);
3394 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3395 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3396 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3397 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3398 /* We want to read the nicks even if disable_nicks is set. This is so
3399 * that we don't lose the nick data entirely. */
3400 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3402 for (ii
=0; ii
<slist
->used
; ii
++)
3403 register_nick(slist
->list
[ii
], hi
);
3405 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3407 for (ii
=0; str
[ii
]; ii
++)
3408 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3410 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3411 hi
->userlist_style
= str
? str
[0] : HI_STYLE_ZOOT
;
3412 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3413 hi
->announcements
= str
? str
[0] : '?';
3414 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3415 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3416 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3417 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3418 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3420 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3422 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3423 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3425 nickserv_set_email_addr(hi
, str
);
3426 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3428 hi
->epithet
= strdup(str
);
3429 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3431 hi
->fakehost
= strdup(str
);
3432 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3434 const char *data
, *type
, *expires
, *cookie_str
;
3435 struct handle_cookie
*cookie
;
3437 cookie
= calloc(1, sizeof(*cookie
));
3438 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3439 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3440 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3441 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3442 if (!type
|| !expires
|| !cookie_str
) {
3443 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3446 if (!irccasecmp(type
, KEY_ACTIVATION
))
3447 cookie
->type
= ACTIVATION
;
3448 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3449 cookie
->type
= PASSWORD_CHANGE
;
3450 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3451 cookie
->type
= EMAIL_CHANGE
;
3452 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3453 cookie
->type
= ALLOWAUTH
;
3455 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3458 cookie
->expires
= strtoul(expires
, NULL
, 0);
3459 if (cookie
->expires
< now
)
3462 cookie
->data
= strdup(data
);
3463 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3467 nickserv_bake_cookie(cookie
);
3469 nickserv_free_cookie(cookie
);
3474 nickserv_saxdb_read(dict_t db
) {
3476 struct record_data
*rd
;
3478 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3480 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3485 static NICKSERV_FUNC(cmd_mergedb
)
3487 struct timeval start
, stop
;
3490 NICKSERV_MIN_PARMS(2);
3491 gettimeofday(&start
, NULL
);
3492 if (!(db
= parse_database(argv
[1]))) {
3493 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3496 nickserv_saxdb_read(db
);
3498 gettimeofday(&stop
, NULL
);
3499 stop
.tv_sec
-= start
.tv_sec
;
3500 stop
.tv_usec
-= start
.tv_usec
;
3501 if (stop
.tv_usec
< 0) {
3503 stop
.tv_usec
+= 1000000;
3505 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3510 expire_handles(UNUSED_ARG(void *data
))
3512 dict_iterator_t it
, next
;
3514 struct handle_info
*hi
;
3516 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3517 next
= iter_next(it
);
3519 if ((hi
->opserv_level
> 0)
3521 || HANDLE_FLAGGED(hi
, FROZEN
)
3522 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3525 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3526 if ((now
- hi
->lastseen
) > expiry
) {
3527 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3528 nickserv_unregister_handle(hi
, NULL
);
3532 if (nickserv_conf
.handle_expire_frequency
)
3533 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3537 nickserv_load_dict(const char *fname
)
3541 if (!(file
= fopen(fname
, "r"))) {
3542 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
3545 while (!feof(file
)) {
3546 fgets(line
, sizeof(line
), file
);
3549 if (line
[strlen(line
)-1] == '\n')
3550 line
[strlen(line
)-1] = 0;
3551 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
3554 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
3557 static enum reclaim_action
3558 reclaim_action_from_string(const char *str
) {
3560 return RECLAIM_NONE
;
3561 else if (!irccasecmp(str
, "warn"))
3562 return RECLAIM_WARN
;
3563 else if (!irccasecmp(str
, "svsnick"))
3564 return RECLAIM_SVSNICK
;
3565 else if (!irccasecmp(str
, "kill"))
3566 return RECLAIM_KILL
;
3568 return RECLAIM_NONE
;
3572 nickserv_conf_read(void)
3574 dict_t conf_node
, child
;
3578 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
3579 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
3582 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
3584 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
3585 if (nickserv_conf
.valid_handle_regex_set
)
3586 regfree(&nickserv_conf
.valid_handle_regex
);
3588 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3589 nickserv_conf
.valid_handle_regex_set
= !err
;
3590 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
3592 nickserv_conf
.valid_handle_regex_set
= 0;
3594 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
3595 if (nickserv_conf
.valid_nick_regex_set
)
3596 regfree(&nickserv_conf
.valid_nick_regex
);
3598 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3599 nickserv_conf
.valid_nick_regex_set
= !err
;
3600 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
3602 nickserv_conf
.valid_nick_regex_set
= 0;
3604 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
3606 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
3607 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
3608 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
3609 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
3610 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
3611 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
3612 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
3613 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
3614 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
3615 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
3616 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
3617 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
3618 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
3619 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
3620 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
3621 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
3622 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
3623 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
3624 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
3625 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
3626 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
3627 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
3628 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
3629 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
3630 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
3632 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
3633 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
3634 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3636 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3637 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
3638 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3640 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3641 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
3642 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
3643 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
3644 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
3645 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
3646 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
3647 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
3648 if (!nickserv_conf
.disable_nicks
) {
3649 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
3650 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3651 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
3652 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
3653 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
3654 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3655 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
3656 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
3658 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
3659 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
3660 const char *key
= iter_key(it
), *value
;
3664 if (!strncasecmp(key
, "uc_", 3))
3665 flag
= toupper(key
[3]);
3666 else if (!strncasecmp(key
, "lc_", 3))
3667 flag
= tolower(key
[3]);
3671 if ((pos
= handle_inverse_flags
[flag
])) {
3672 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
3673 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
3676 if (nickserv_conf
.weak_password_dict
)
3677 dict_delete(nickserv_conf
.weak_password_dict
);
3678 nickserv_conf
.weak_password_dict
= dict_new();
3679 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
3680 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
3681 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
3682 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
3684 nickserv_load_dict(str
);
3685 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
3686 if (nickserv
&& str
)
3687 NickChange(nickserv
, str
, 0);
3688 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
3689 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
3690 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
3691 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
3692 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
3693 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
3694 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
3695 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
3696 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
3697 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
3698 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
3699 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
3700 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
3701 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
3702 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
3703 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
3704 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
3705 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
3706 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
3707 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
3708 str
= conf_get_data("server/network", RECDB_QSTRING
);
3709 nickserv_conf
.network_name
= str
? str
: "some IRC network";
3710 if (!nickserv_conf
.auth_policer_params
) {
3711 nickserv_conf
.auth_policer_params
= policer_params_new();
3712 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
3713 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
3715 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
3716 for (it
=dict_first(child
); it
; it
=iter_next(it
))
3717 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
3721 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
3723 char newnick
[NICKLEN
+1];
3732 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3734 case RECLAIM_SVSNICK
:
3736 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
3737 } while (GetUserH(newnick
));
3738 irc_svsnick(nickserv
, user
, newnick
);
3741 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
3742 irc_kill(nickserv
, user
, msg
);
3748 nickserv_reclaim_p(void *data
) {
3749 struct userNode
*user
= data
;
3750 struct nick_info
*ni
= get_nick_info(user
->nick
);
3752 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3756 check_user_nick(struct userNode
*user
) {
3757 struct nick_info
*ni
;
3758 user
->modes
&= ~FLAGS_REGNICK
;
3759 if (!(ni
= get_nick_info(user
->nick
)))
3761 if (user
->handle_info
== ni
->owner
) {
3762 user
->modes
|= FLAGS_REGNICK
;
3766 if (nickserv_conf
.warn_nick_owned
)
3767 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3768 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
3770 if (nickserv_conf
.auto_reclaim_delay
)
3771 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
3773 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3778 handle_new_user(struct userNode
*user
)
3780 return check_user_nick(user
);
3784 handle_account(struct userNode
*user
, const char *stamp
)
3786 struct handle_info
*hi
;
3789 #ifdef WITH_PROTOCOL_P10
3790 time_t timestamp
= 0;
3792 colon
= strchr(stamp
, ':');
3793 if(colon
&& colon
[1])
3796 timestamp
= atoi(colon
+1);
3798 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
3799 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
3801 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
);
3805 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
3806 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
3810 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
3813 set_user_handle_info(user
, hi
, 0);
3815 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
3820 handle_nick_change(struct userNode
*user
, const char *old_nick
)
3822 struct handle_info
*hi
;
3824 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
3825 dict_remove(nickserv_allow_auth_dict
, old_nick
);
3826 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
3828 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3829 check_user_nick(user
);
3833 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
3835 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
3836 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3837 set_user_handle_info(user
, NULL
, 0);
3840 static struct modcmd
*
3841 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
3843 if (min_level
> 0) {
3845 sprintf(buf
, "%u", min_level
);
3846 if (must_be_qualified
) {
3847 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
3849 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
3851 } else if (min_level
== 0) {
3852 if (must_be_qualified
) {
3853 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3855 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3858 if (must_be_qualified
) {
3859 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
3861 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
3867 nickserv_db_cleanup(void)
3869 unreg_del_user_func(nickserv_remove_user
);
3870 userList_clean(&curr_helpers
);
3871 policer_params_delete(nickserv_conf
.auth_policer_params
);
3872 dict_delete(nickserv_handle_dict
);
3873 dict_delete(nickserv_nick_dict
);
3874 dict_delete(nickserv_opt_dict
);
3875 dict_delete(nickserv_allow_auth_dict
);
3876 dict_delete(nickserv_email_dict
);
3877 dict_delete(nickserv_id_dict
);
3878 dict_delete(nickserv_conf
.weak_password_dict
);
3879 free(auth_func_list
);
3880 free(unreg_func_list
);
3882 free(allowauth_func_list
);
3883 free(handle_merge_func_list
);
3884 free(failpw_func_list
);
3885 if (nickserv_conf
.valid_handle_regex_set
)
3886 regfree(&nickserv_conf
.valid_handle_regex
);
3887 if (nickserv_conf
.valid_nick_regex_set
)
3888 regfree(&nickserv_conf
.valid_nick_regex
);
3892 init_nickserv(const char *nick
)
3895 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
3896 reg_new_user_func(handle_new_user
);
3897 reg_nick_change_func(handle_nick_change
);
3898 reg_del_user_func(nickserv_remove_user
);
3899 reg_account_func(handle_account
);
3901 /* set up handle_inverse_flags */
3902 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
3903 for (i
=0; handle_flags
[i
]; i
++) {
3904 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
3905 flag_access_levels
[i
] = 0;
3908 conf_register_reload(nickserv_conf_read
);
3909 nickserv_opt_dict
= dict_new();
3910 nickserv_email_dict
= dict_new();
3911 dict_set_free_keys(nickserv_email_dict
, free
);
3912 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
3914 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
3915 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
3916 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
3917 * a big pain to disable since its nolonger in the config file. ) -Rubin
3919 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
3920 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
3921 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
3922 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
3923 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
3924 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
3925 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
3926 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
3927 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
3928 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
3929 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
3930 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
3931 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
3932 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
3933 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
3934 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
3935 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
3936 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
3937 if (!nickserv_conf
.disable_nicks
) {
3938 /* nick management commands */
3939 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
3940 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
3941 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
3942 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
3943 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
3944 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
3946 if (nickserv_conf
.email_enabled
) {
3947 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
3948 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
3949 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
3950 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
3951 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
3953 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
3954 /* miscellaneous commands */
3955 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
3956 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
3957 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
3958 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
3959 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
3961 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
3962 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
3963 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
3964 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
3965 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
3966 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
3967 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
3968 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
3969 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
3970 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
3971 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
3972 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
3973 if (nickserv_conf
.titlehost_suffix
) {
3974 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
3975 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
3977 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
3978 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
3979 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
3981 nickserv_handle_dict
= dict_new();
3982 dict_set_free_keys(nickserv_handle_dict
, free
);
3983 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
3985 nickserv_id_dict
= dict_new();
3986 dict_set_free_keys(nickserv_id_dict
, free
);
3988 nickserv_nick_dict
= dict_new();
3989 dict_set_free_data(nickserv_nick_dict
, free
);
3991 nickserv_allow_auth_dict
= dict_new();
3993 userList_init(&curr_helpers
);
3996 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
3997 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
3998 nickserv_service
= service_register(nickserv
);
4000 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4001 reg_exit_func(nickserv_db_cleanup
);
4002 if(nickserv_conf
.handle_expire_frequency
)
4003 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4004 message_register_table(msgtab
);