1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * srvx is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 #include "opserv.h" /* for gag_create(), opserv_bad_channel() */
34 #define NICKSERV_CONF_NAME "services/nickserv"
36 #define KEY_DISABLE_NICKS "disable_nicks"
37 #define KEY_DEFAULT_HOSTMASK "default_hostmask"
38 #define KEY_NICKS_PER_HANDLE "nicks_per_handle"
39 #define KEY_NICKS_PER_ACCOUNT "nicks_per_account"
40 #define KEY_PASSWORD_MIN_LENGTH "password_min_length"
41 #define KEY_PASSWORD_MIN_DIGITS "password_min_digits"
42 #define KEY_PASSWORD_MIN_UPPER "password_min_upper"
43 #define KEY_PASSWORD_MIN_LOWER "password_min_lower"
44 #define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
45 #define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
46 #define KEY_VALID_NICK_REGEX "valid_nick_regex"
47 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
48 #define KEY_MODOPER_LEVEL "modoper_level"
49 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
50 #define KEY_SET_TITLE_LEVEL "set_title_level"
51 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
52 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
53 #define KEY_FLAG_LEVELS "flag_levels"
54 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
55 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
56 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
57 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
58 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
59 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
60 #define KEY_DICT_FILE "dict_file"
61 #define KEY_NICK "nick"
62 #define KEY_LANGUAGE "language"
63 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
64 #define KEY_AUTOGAG_DURATION "autogag_duration"
65 #define KEY_AUTH_POLICER "auth_policer"
66 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
67 #define KEY_EMAIL_ENABLED "email_enabled"
68 #define KEY_EMAIL_REQUIRED "email_required"
69 #define KEY_SYNC_LOG "sync_log"
70 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
71 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
72 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
75 #define KEY_PASSWD "passwd"
76 #define KEY_NICKS "nicks"
77 #define KEY_MASKS "masks"
78 #define KEY_OPSERV_LEVEL "opserv_level"
79 #define KEY_FLAGS "flags"
80 #define KEY_REGISTER_ON "register"
81 #define KEY_LAST_SEEN "lastseen"
82 #define KEY_INFO "info"
83 #define KEY_USERLIST_STYLE "user_style"
84 #define KEY_SCREEN_WIDTH "screen_width"
85 #define KEY_LAST_AUTHED_HOST "last_authed_host"
86 #define KEY_LAST_QUIT_HOST "last_quit_host"
87 #define KEY_EMAIL_ADDR "email_addr"
88 #define KEY_COOKIE "cookie"
89 #define KEY_COOKIE_DATA "data"
90 #define KEY_COOKIE_TYPE "type"
91 #define KEY_COOKIE_EXPIRES "expires"
92 #define KEY_ACTIVATION "activation"
93 #define KEY_PASSWORD_CHANGE "password change"
94 #define KEY_EMAIL_CHANGE "email change"
95 #define KEY_ALLOWAUTH "allowauth"
96 #define KEY_EPITHET "epithet"
97 #define KEY_TABLE_WIDTH "table_width"
98 #define KEY_ANNOUNCEMENTS "announcements"
99 #define KEY_MAXLOGINS "maxlogins"
100 #define KEY_FAKEHOST "fakehost"
102 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
104 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
105 #define OPTION_FUNC(NAME) int NAME(struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
106 typedef OPTION_FUNC(option_func_t
);
108 DEFINE_LIST(handle_info_list
, struct handle_info
*);
110 #define NICKSERV_MIN_PARMS(N) do { \
112 reply("MSG_MISSING_PARAMS", argv[0]); \
113 svccmd_send_help(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_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
155 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
156 { "NSMSG_BAD_COOKIE", "That cookie is not the right one. Please make sure you are copying it EXACTLY from the email; it is case-sensitive, so $bABC$b is different from $babc$b." },
157 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
158 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
159 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
160 { "NSMSG_EMAIL_OVERUSED", "There are already the maximum number of accounts associated with that email address." },
161 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
162 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
163 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
164 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
165 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
166 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
167 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
168 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
169 { "NSMSG_REGISTER_BAD_NICKMASK", "Could not recognize $b%s$b as either a current nick or a hostmask." },
170 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
171 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
172 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
173 { "NSMSG_USE_AUTHCOOKIE", "Your hostmask is not valid for account $b%1$s$b. Please use the $bauthcookie$b command to grant yourself access. (/msg $S authcookie %1$s)" },
174 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
175 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
176 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
177 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
178 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
179 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
180 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
181 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
182 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
183 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
184 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
185 { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
186 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
187 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
188 { "NSMSG_HANDLEINFO_ON", "Account information for $b%s$b:" },
189 { "NSMSG_HANDLEINFO_ID", " Account ID: %lu" },
190 { "NSMSG_HANDLEINFO_REGGED", " Registered on: %s" },
191 { "NSMSG_HANDLEINFO_LASTSEEN", " Last seen: %s" },
192 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", " Last seen: Right now!" },
193 { "NSMSG_HANDLEINFO_VACATION", " On vacation." },
194 { "NSMSG_HANDLEINFO_EMAIL_ADDR", " Email address: %s" },
195 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", " Cookie: There is currently an activation cookie issued for this account" },
196 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", " Cookie: There is currently a password change cookie issued for this account" },
197 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", " Cookie: There is currently an email change cookie issued for this account" },
198 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", " Cookie: There is currently an allowauth cookie issued for this account" },
199 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", " Cookie: There is currently an unknown cookie issued for this account" },
200 { "NSMSG_HANDLEINFO_INFOLINE", " Infoline: %s" },
201 { "NSMSG_HANDLEINFO_FLAGS", " Flags: %s" },
202 { "NSMSG_HANDLEINFO_EPITHET", " Epithet: %s" },
203 { "NSMSG_HANDLEINFO_FAKEHOST", " Fake host: %s" },
204 { "NSMSG_HANDLEINFO_LAST_HOST", " Last quit hostmask: %s" },
205 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", " Last quit hostmask: Unknown" },
206 { "NSMSG_HANDLEINFO_NICKS", " Nickname(s): %s" },
207 { "NSMSG_HANDLEINFO_MASKS", " Hostmask(s): %s" },
208 { "NSMSG_HANDLEINFO_CHANNELS", " Channel(s): %s" },
209 { "NSMSG_HANDLEINFO_CURRENT", " Current nickname(s): %s" },
210 { "NSMSG_HANDLEINFO_DNR", " Do-not-register (by %s): %s" },
211 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
212 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
213 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
214 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
215 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
216 { "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)." },
217 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
218 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
219 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
220 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
221 { "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." },
222 { "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." },
223 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
224 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
225 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
226 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
227 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
228 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
229 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
230 { "NSMSG_PASS_SUCCESS", "Password changed." },
231 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
232 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
233 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
234 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
235 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
236 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
237 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
238 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
239 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
240 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
241 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
242 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
243 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
244 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
245 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
246 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
247 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
248 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
249 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
250 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
251 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
252 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
253 { "NSMSG_NO_ACCESS", "Access denied." },
254 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
255 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
256 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
257 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
258 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
259 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
260 { "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." },
261 { "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." },
262 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
263 { "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." },
264 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
265 { "NSMSG_SEARCH_MATCH", "Match: %s" },
266 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
267 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
268 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
269 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
270 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
271 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
272 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
273 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
274 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
275 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
276 { "NSMSG_SETTING_LIST", "$b$N account settings:$b" },
277 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
278 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
279 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
280 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
281 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
282 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
283 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
284 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
285 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
286 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
287 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
288 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
289 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
290 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
291 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
292 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
293 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
294 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
295 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
296 { "NSEMAIL_ACTIVATION_BODY",
297 "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"
299 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
300 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
301 "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"
302 "/msg %3$s@%4$s AUTH %5$s your-password\n"
303 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
304 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
306 "If you did NOT request this account, you do not need to do anything.\n"
307 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
308 { "NSEMAIL_ACTIVATION_BODY_WEB",
309 "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"
311 "To verify your email address and complete the account registration, visit the following URL:\n"
312 "http://www.afternet.org/play/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
314 "If you did NOT request this account, you do not need to do anything.\n"
315 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
316 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
317 { "NSEMAIL_PASSWORD_CHANGE_BODY",
318 "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"
319 "To complete the password change, log on to %1$s and type the following command:\n"
320 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
321 "If you did NOT request your password to be changed, you do not need to do anything.\n"
322 "Please contact the %1$s staff if you have questions." },
323 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
324 "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"
325 "To complete the password change, click the following URL:\n"
326 "http://www.afternet.org/play/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
327 "If you did NOT request your password to be changed, you do not need to do anything.\n"
328 "Please contact the %1$s staff if you have questions." },
329 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
330 #ifdef stupid_verify_old_email
331 { "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." },
332 { "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." },
334 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
335 { "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." },
336 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
337 { "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." },
338 { "CHECKPASS_YES", "Yes." },
339 { "CHECKPASS_NO", "No." },
343 enum reclaim_action
{
349 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
350 static void nickserv_reclaim_p(void *data
);
353 unsigned int disable_nicks
: 1;
354 unsigned int valid_handle_regex_set
: 1;
355 unsigned int valid_nick_regex_set
: 1;
356 unsigned int autogag_enabled
: 1;
357 unsigned int email_enabled
: 1;
358 unsigned int email_required
: 1;
359 unsigned int default_hostmask
: 1;
360 unsigned int warn_nick_owned
: 1;
361 unsigned int warn_clone_auth
: 1;
362 unsigned int sync_log
: 1;
363 unsigned long nicks_per_handle
;
364 unsigned long password_min_length
;
365 unsigned long password_min_digits
;
366 unsigned long password_min_upper
;
367 unsigned long password_min_lower
;
368 unsigned long db_backup_frequency
;
369 unsigned long handle_expire_frequency
;
370 unsigned long autogag_duration
;
371 unsigned long email_visible_level
;
372 unsigned long cookie_timeout
;
373 unsigned long handle_expire_delay
;
374 unsigned long nochan_handle_expire_delay
;
375 unsigned long modoper_level
;
376 unsigned long set_epithet_level
;
377 unsigned long set_title_level
;
378 unsigned long set_fakehost_level
;
379 unsigned long handles_per_email
;
380 unsigned long email_search_level
;
381 const char *network_name
;
382 const char *titlehost_suffix
;
383 regex_t valid_handle_regex
;
384 regex_t valid_nick_regex
;
385 dict_t weak_password_dict
;
386 struct policer_params
*auth_policer_params
;
387 enum reclaim_action reclaim_action
;
388 enum reclaim_action auto_reclaim_action
;
389 unsigned long auto_reclaim_delay
;
390 unsigned char default_maxlogins
;
391 unsigned char hard_maxlogins
;
394 /* We have 2^32 unique account IDs to use. */
395 unsigned long int highest_id
= 0;
398 canonicalize_hostmask(char *mask
)
400 char *out
= mask
, *temp
;
401 if ((temp
= strchr(mask
, '!'))) {
403 while (*temp
) *out
++ = *temp
++;
409 static struct handle_info
*
410 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
412 struct handle_info
*hi
;
414 #ifdef WITH_PROTOCOL_BAHAMUT
415 char id_base64
[IDLEN
+ 1];
418 /* Assign a unique account ID to the account; note that 0 is
419 an invalid account ID. 1 is therefore the first account ID. */
421 id
= 1 + highest_id
++;
423 /* Note: highest_id is and must always be the highest ID. */
424 if(id
> highest_id
) {
428 inttobase64(id_base64
, id
, IDLEN
);
430 /* Make sure an account with the same ID doesn't exist. If a
431 duplicate is found, log some details and assign a new one.
432 This should be impossible, but it never hurts to expect it. */
433 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
434 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
440 hi
= calloc(1, sizeof(*hi
));
441 hi
->userlist_style
= HI_DEFAULT_STYLE
;
442 hi
->announcements
= '?';
443 hi
->handle
= strdup(handle
);
444 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
446 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
448 #ifdef WITH_PROTOCOL_BAHAMUT
450 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
457 register_nick(const char *nick
, struct handle_info
*owner
)
459 struct nick_info
*ni
;
460 ni
= malloc(sizeof(struct nick_info
));
461 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
463 ni
->next
= owner
->nicks
;
465 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
469 delete_nick(struct nick_info
*ni
)
471 struct nick_info
*last
, *next
;
472 struct userNode
*user
;
473 /* Check to see if we should mark a user as unregistered. */
474 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
475 user
->modes
&= ~FLAGS_REGNICK
;
478 /* Remove ni from the nick_info linked list. */
479 if (ni
== ni
->owner
->nicks
) {
480 ni
->owner
->nicks
= ni
->next
;
482 last
= ni
->owner
->nicks
;
488 last
->next
= next
->next
;
490 dict_remove(nickserv_nick_dict
, ni
->nick
);
493 static unreg_func_t
*unreg_func_list
;
494 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
497 reg_unreg_func(unreg_func_t func
)
499 if (unreg_func_used
== unreg_func_size
) {
500 if (unreg_func_size
) {
501 unreg_func_size
<<= 1;
502 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
505 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
508 unreg_func_list
[unreg_func_used
++] = func
;
512 nickserv_free_cookie(void *data
)
514 struct handle_cookie
*cookie
= data
;
515 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
516 if (cookie
->data
) free(cookie
->data
);
521 free_handle_info(void *vhi
)
523 struct handle_info
*hi
= vhi
;
525 #ifdef WITH_PROTOCOL_BAHAMUT
528 inttobase64(id
, hi
->id
, IDLEN
);
529 dict_remove(nickserv_id_dict
, id
);
532 free_string_list(hi
->masks
);
536 delete_nick(hi
->nicks
);
541 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
542 nickserv_free_cookie(hi
->cookie
);
544 if (hi
->email_addr
) {
545 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
546 handle_info_list_remove(hil
, hi
);
548 dict_remove(nickserv_email_dict
, hi
->email_addr
);
553 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
556 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
)
560 for (n
=0; n
<unreg_func_used
; n
++)
561 unreg_func_list
[n
](notify
, hi
);
563 set_user_handle_info(hi
->users
, NULL
, 0);
565 if (nickserv_conf
.disable_nicks
)
566 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
568 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
571 if (nickserv_conf
.sync_log
)
572 SyncLog("UNREGISTER %s", hi
->handle
);
574 dict_remove(nickserv_handle_dict
, hi
->handle
);
578 get_handle_info(const char *handle
)
580 return dict_find(nickserv_handle_dict
, handle
, 0);
584 get_nick_info(const char *nick
)
586 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
590 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
595 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
596 mn
= channel
->members
.list
[nn
];
597 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
604 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
605 if (!user
->handle_info
) {
607 send_message(user
, bot
, "MSG_AUTHENTICATE");
611 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
613 send_message(user
, bot
, "NSMSG_NO_ACCESS");
617 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
619 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
623 if (user
->handle_info
->opserv_level
< min_level
) {
625 send_message(user
, bot
, "NSMSG_NO_ACCESS");
633 is_valid_handle(const char *handle
)
635 struct userNode
*user
;
636 /* cant register a juped nick/service nick as handle, to prevent confusion */
637 user
= GetUserH(handle
);
638 if (user
&& IsLocal(user
))
640 /* check against maximum length */
641 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
643 /* for consistency, only allow account names that could be nicks */
644 if (!is_valid_nick(handle
))
646 /* disallow account names that look like bad words */
647 if (opserv_bad_channel(handle
))
649 /* test either regex or containing all valid chars */
650 if (nickserv_conf
.valid_handle_regex_set
) {
651 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
654 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
655 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
659 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
664 is_registerable_nick(const char *nick
)
666 /* make sure it could be used as an account name */
667 if (!is_valid_handle(nick
))
670 if (strlen(nick
) > NICKLEN
)
672 /* test either regex or as valid handle */
673 if (nickserv_conf
.valid_nick_regex_set
) {
674 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
677 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
678 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
686 is_valid_email_addr(const char *email
)
688 return strchr(email
, '@') != NULL
;
692 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
694 if (hi
->email_addr
) {
695 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
696 return hi
->email_addr
;
706 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
708 struct handle_info
*hi
;
709 struct userNode
*target
;
713 if (!(hi
= get_handle_info(++name
))) {
714 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
719 if (!(target
= GetUserH(name
))) {
720 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
723 if (IsLocal(target
)) {
724 if (IsService(target
))
725 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
727 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
730 if (!(hi
= target
->handle_info
)) {
731 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
739 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
740 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
742 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
743 if ((user
->handle_info
->opserv_level
== 1000)
744 || (user
->handle_info
== hi
)
745 || ((user
->handle_info
->opserv_level
== 0)
746 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
747 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
751 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
755 static struct handle_info
*
756 get_victim_oper(struct userNode
*user
, const char *target
)
758 struct handle_info
*hi
;
759 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
761 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
762 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
765 return oper_outranks(user
, hi
) ? hi
: NULL
;
769 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
773 /* If no hostmasks on the account, allow it. */
774 if (!hi
->masks
->used
)
776 /* If any hostmask matches, allow it. */
777 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
778 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
780 /* If they are allowauthed to this account, allow it (removing the aa). */
781 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
782 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
785 /* The user is not allowed to use this account. */
790 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
793 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
795 if (len
< nickserv_conf
.password_min_length
) {
797 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
800 if (!irccasecmp(pass
, handle
)) {
802 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
805 dict_find(nickserv_conf
.weak_password_dict
, pass
, &i
);
808 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
811 for (i
=0; i
<len
; i
++) {
812 if (isdigit(pass
[i
]))
814 if (isupper(pass
[i
]))
816 if (islower(pass
[i
]))
819 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
820 || (cnt_upper
< nickserv_conf
.password_min_upper
)
821 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
823 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
829 static auth_func_t
*auth_func_list
;
830 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
833 reg_auth_func(auth_func_t func
)
835 if (auth_func_used
== auth_func_size
) {
836 if (auth_func_size
) {
837 auth_func_size
<<= 1;
838 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
841 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
844 auth_func_list
[auth_func_used
++] = func
;
847 static handle_rename_func_t
*rf_list
;
848 static unsigned int rf_list_size
, rf_list_used
;
851 reg_handle_rename_func(handle_rename_func_t func
)
853 if (rf_list_used
== rf_list_size
) {
856 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
859 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
862 rf_list
[rf_list_used
++] = func
;
866 generate_fakehost(struct handle_info
*handle
)
868 extern const char *hidden_host_suffix
;
869 static char buffer
[HOSTLEN
+1];
871 if (!handle
->fakehost
) {
872 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
874 } else if (handle
->fakehost
[0] == '.') {
875 /* A leading dot indicates the stored value is actually a title. */
876 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
879 return handle
->fakehost
;
883 apply_fakehost(struct handle_info
*handle
)
885 struct userNode
*target
;
890 fake
= generate_fakehost(handle
);
891 for (target
= handle
->users
; target
; target
= target
->next_authed
)
892 assign_fakehost(target
, fake
, 1);
896 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
899 struct handle_info
*old_info
;
901 /* This can happen if somebody uses COOKIE while authed, or if
902 * they re-auth to their current handle (which is silly, but users
904 if (user
->handle_info
== hi
)
907 if (user
->handle_info
) {
908 struct userNode
*other
;
911 userList_remove(&curr_helpers
, user
);
913 /* remove from next_authed linked list */
914 if (user
->handle_info
->users
== user
) {
915 user
->handle_info
->users
= user
->next_authed
;
917 for (other
= user
->handle_info
->users
;
918 other
->next_authed
!= user
;
919 other
= other
->next_authed
) ;
920 other
->next_authed
= user
->next_authed
;
922 /* if nobody left on old handle, and they're not an oper, remove !god */
923 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
924 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
925 /* record them as being last seen at this time */
926 user
->handle_info
->lastseen
= now
;
927 /* and record their hostmask */
928 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
930 old_info
= user
->handle_info
;
931 user
->handle_info
= hi
;
932 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
933 HANDLE_CLEAR_FLAG(hi
, HELPING
);
934 for (n
=0; n
<auth_func_used
; n
++)
935 auth_func_list
[n
](user
, old_info
);
937 struct nick_info
*ni
;
939 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
940 if (nickserv_conf
.warn_clone_auth
) {
941 struct userNode
*other
;
942 for (other
= hi
->users
; other
; other
= other
->next_authed
)
943 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
945 user
->next_authed
= hi
->users
;
949 userList_append(&curr_helpers
, user
);
951 if (hi
->fakehost
|| old_info
)
955 #ifdef WITH_PROTOCOL_BAHAMUT
956 /* Stamp users with their account ID. */
958 inttobase64(id
, hi
->id
, IDLEN
);
959 #elif WITH_PROTOCOL_P10
960 /* Stamp users with their account name. */
961 char *id
= hi
->handle
;
963 const char *id
= "???";
965 if (!nickserv_conf
.disable_nicks
) {
966 struct nick_info
*ni
;
967 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
968 if (!irccasecmp(user
->nick
, ni
->nick
)) {
969 user
->modes
|= FLAGS_REGNICK
;
974 StampUser(user
, id
, hi
->registered
);
977 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
978 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
980 /* We cannot clear the user's account ID, unfortunately. */
981 user
->next_authed
= NULL
;
985 static struct handle_info
*
986 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
988 struct handle_info
*hi
;
989 struct nick_info
*ni
;
990 char crypted
[MD5_CRYPT_LENGTH
];
992 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
993 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
997 if(strlen(handle
) > 15)
999 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1003 if (!is_secure_password(handle
, passwd
, user
))
1006 cryptpass(passwd
, crypted
);
1007 hi
= register_handle(handle
, crypted
, 0);
1008 hi
->masks
= alloc_string_list(1);
1010 hi
->language
= lang_C
;
1011 hi
->registered
= now
;
1013 hi
->flags
= HI_DEFAULT_FLAGS
;
1014 if (settee
&& !no_auth
)
1015 set_user_handle_info(settee
, hi
, 1);
1018 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1019 else if (nickserv_conf
.disable_nicks
)
1020 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1021 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1022 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1024 register_nick(user
->nick
, hi
);
1025 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1027 if (settee
&& (user
!= settee
))
1028 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1033 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1035 cookie
->hi
->cookie
= cookie
;
1036 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1040 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1042 struct handle_cookie
*cookie
;
1043 char subject
[128], body
[4096], *misc
;
1044 const char *netname
, *fmt
;
1048 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1052 cookie
= calloc(1, sizeof(*cookie
));
1054 cookie
->type
= type
;
1055 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1056 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1057 inttobase64(cookie
->cookie
, rand(), 5);
1058 inttobase64(cookie
->cookie
+5, rand(), 5);
1060 netname
= nickserv_conf
.network_name
;
1063 switch (cookie
->type
) {
1065 hi
->passwd
[0] = 0; /* invalidate password */
1066 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1067 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1068 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1071 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1073 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1075 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1078 case PASSWORD_CHANGE
:
1079 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1080 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1081 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1083 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1085 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1086 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1089 misc
= hi
->email_addr
;
1090 hi
->email_addr
= cookie
->data
;
1091 #ifdef stupid_verify_old_email
1093 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1094 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1095 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1096 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1097 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1098 sendmail(nickserv
, hi
, subject
, body
, 1);
1099 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1100 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1103 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1104 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1105 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1106 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1107 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1108 sendmail(nickserv
, hi
, subject
, body
, 1);
1110 #ifdef stupid_verify_old_email
1113 hi
->email_addr
= misc
;
1116 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1117 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1118 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1119 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1120 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1123 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1127 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1128 nickserv_bake_cookie(cookie
);
1132 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1134 cookie
->hi
->cookie
= NULL
;
1135 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1136 nickserv_free_cookie(cookie
);
1140 nickserv_free_email_addr(void *data
)
1142 handle_info_list_clean(data
);
1147 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1149 struct handle_info_list
*hil
;
1150 /* Remove from old handle_info_list ... */
1151 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1152 handle_info_list_remove(hil
, hi
);
1153 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1154 hi
->email_addr
= NULL
;
1156 /* Add to the new list.. */
1157 if (new_email_addr
) {
1158 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1159 hil
= calloc(1, sizeof(*hil
));
1160 hil
->tag
= strdup(new_email_addr
);
1161 handle_info_list_init(hil
);
1162 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1164 handle_info_list_append(hil
, hi
);
1165 hi
->email_addr
= hil
->tag
;
1169 static NICKSERV_FUNC(cmd_register
)
1171 struct handle_info
*hi
;
1172 const char *email_addr
, *password
;
1173 char syncpass
[MD5_CRYPT_LENGTH
];
1174 int no_auth
, weblink
;
1176 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1177 /* Require the first handle registered to belong to someone +o. */
1178 reply("NSMSG_REQUIRE_OPER");
1182 if (user
->handle_info
) {
1183 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1187 if (IsRegistering(user
)) {
1188 reply("NSMSG_ALREADY_REGISTERING");
1192 if (IsStamped(user
)) {
1193 /* Unauthenticated users might still have been stamped
1194 previously and could therefore have a hidden host;
1195 do not allow them to register a new account. */
1196 reply("NSMSG_STAMPED_REGISTER");
1200 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1202 if (!is_valid_handle(argv
[1])) {
1203 reply("NSMSG_BAD_HANDLE", argv
[1]);
1208 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1209 struct handle_info_list
*hil
;
1212 /* Remember email address. */
1213 email_addr
= argv
[3];
1215 /* Check that the email address looks valid.. */
1216 if (!is_valid_email_addr(email_addr
)) {
1217 reply("NSMSG_BAD_EMAIL_ADDR");
1221 /* .. and that we are allowed to send to it. */
1222 if ((str
= sendmail_prohibited_address(email_addr
))) {
1223 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1227 /* If we do email verify, make sure we don't spam the address. */
1228 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1230 for (nn
=0; nn
<hil
->used
; nn
++) {
1231 if (hil
->list
[nn
]->cookie
) {
1232 reply("NSMSG_EMAIL_UNACTIVATED");
1236 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1237 reply("NSMSG_EMAIL_OVERUSED");
1250 /* Webregister hack - send URL instead of IRC cookie
1253 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1257 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1259 /* Add any masks they should get. */
1260 if (nickserv_conf
.default_hostmask
) {
1261 string_list_append(hi
->masks
, strdup("*@*"));
1263 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1264 if (user
->ip
.s_addr
&& user
->hostname
[strspn(user
->hostname
, "0123456789.")])
1265 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1268 /* If they're the first to register, give them level 1000. */
1269 if (dict_size(nickserv_handle_dict
) == 1) {
1270 hi
->opserv_level
= 1000;
1271 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1274 /* Set their email address. */
1276 nickserv_set_email_addr(hi
, email_addr
);
1278 /* If they need to do email verification, tell them. */
1280 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1282 /* Set registering flag.. */
1283 user
->modes
|= FLAGS_REGISTERING
;
1285 if (nickserv_conf
.sync_log
) {
1286 cryptpass(password
, syncpass
);
1288 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1289 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1292 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1298 static NICKSERV_FUNC(cmd_oregister
)
1301 struct userNode
*settee
;
1302 struct handle_info
*hi
;
1304 NICKSERV_MIN_PARMS(4);
1306 if (!is_valid_handle(argv
[1])) {
1307 reply("NSMSG_BAD_HANDLE", argv
[1]);
1311 if (strchr(argv
[3], '@')) {
1312 mask
= canonicalize_hostmask(strdup(argv
[3]));
1314 settee
= GetUserH(argv
[4]);
1316 reply("MSG_NICK_UNKNOWN", argv
[4]);
1323 } else if ((settee
= GetUserH(argv
[3]))) {
1324 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1326 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1329 if (settee
&& settee
->handle_info
) {
1330 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1334 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1338 string_list_append(hi
->masks
, mask
);
1342 static NICKSERV_FUNC(cmd_handleinfo
)
1345 unsigned int i
, pos
=0, herelen
;
1346 struct userNode
*target
, *next_un
;
1347 struct handle_info
*hi
;
1348 const char *nsmsg_none
;
1351 if (!(hi
= user
->handle_info
)) {
1352 reply("NSMSG_MUST_AUTH");
1355 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1359 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1360 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1361 #ifdef WITH_PROTOCOL_BAHAMUT
1362 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1364 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1367 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1368 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1370 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1373 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1374 if (HANDLE_FLAGGED(hi
, FROZEN
))
1375 reply("NSMSG_HANDLEINFO_VACATION");
1377 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1378 struct do_not_register
*dnr
;
1379 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1380 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1381 if (!oper_outranks(user
, hi
))
1383 } else if (hi
!= user
->handle_info
)
1386 if (nickserv_conf
.email_enabled
)
1387 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1391 switch (hi
->cookie
->type
) {
1392 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1393 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1394 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1395 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1396 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1402 unsigned long flen
= 1;
1403 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1405 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1406 if (hi
->flags
& 1 << i
)
1407 flags
[flen
++] = handle_flags
[i
];
1409 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1411 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1414 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1415 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1416 || (hi
->opserv_level
> 0)) {
1417 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1421 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1423 if (hi
->last_quit_host
[0])
1424 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1426 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1428 if (nickserv_conf
.disable_nicks
) {
1429 /* nicks disabled; don't show anything about registered nicks */
1430 } else if (hi
->nicks
) {
1431 struct nick_info
*ni
, *next_ni
;
1432 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1433 herelen
= strlen(ni
->nick
);
1434 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1436 goto print_nicks_buff
;
1440 memcpy(buff
+pos
, ni
->nick
, herelen
);
1441 pos
+= herelen
; buff
[pos
++] = ' ';
1445 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1450 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1453 if (hi
->masks
->used
) {
1454 for (i
=0; i
< hi
->masks
->used
; i
++) {
1455 herelen
= strlen(hi
->masks
->list
[i
]);
1456 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1458 goto print_mask_buff
;
1460 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1461 pos
+= herelen
; buff
[pos
++] = ' ';
1462 if (i
+1 == hi
->masks
->used
) {
1465 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1470 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1474 struct userData
*channel
, *next
;
1477 for (channel
= hi
->channels
; channel
; channel
= next
) {
1478 next
= channel
->u_next
;
1479 name
= channel
->channel
->channel
->name
;
1480 herelen
= strlen(name
);
1481 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1483 goto print_chans_buff
;
1485 if (IsUserSuspended(channel
))
1487 pos
+= sprintf(buff
+pos
, "%d:%s ", channel
->access
, name
);
1491 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1496 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1499 for (target
= hi
->users
; target
; target
= next_un
) {
1500 herelen
= strlen(target
->nick
);
1501 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1503 goto print_cnick_buff
;
1505 next_un
= target
->next_authed
;
1507 memcpy(buff
+pos
, target
->nick
, herelen
);
1508 pos
+= herelen
; buff
[pos
++] = ' ';
1512 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1520 static NICKSERV_FUNC(cmd_userinfo
)
1522 struct userNode
*target
;
1524 NICKSERV_MIN_PARMS(2);
1525 if (!(target
= GetUserH(argv
[1]))) {
1526 reply("MSG_NICK_UNKNOWN", argv
[1]);
1529 if (target
->handle_info
)
1530 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1532 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1536 static NICKSERV_FUNC(cmd_nickinfo
)
1538 struct nick_info
*ni
;
1540 NICKSERV_MIN_PARMS(2);
1541 if (!(ni
= get_nick_info(argv
[1]))) {
1542 reply("MSG_NICK_UNKNOWN", argv
[1]);
1545 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1549 static NICKSERV_FUNC(cmd_rename_handle
)
1551 struct handle_info
*hi
;
1552 char msgbuf
[MAXLEN
], *old_handle
;
1555 NICKSERV_MIN_PARMS(3);
1556 if (!(hi
= get_victim_oper(user
, argv
[1])))
1558 if (!is_valid_handle(argv
[2])) {
1559 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1562 if (get_handle_info(argv
[2])) {
1563 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1566 if(strlen(argv
[2]) > 15)
1568 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1572 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1573 hi
->handle
= strdup(argv
[2]);
1574 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1575 for (nn
=0; nn
<rf_list_used
; nn
++)
1576 rf_list
[nn
](hi
, old_handle
);
1577 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1578 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1579 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1584 static failpw_func_t
*failpw_func_list
;
1585 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1588 reg_failpw_func(failpw_func_t func
)
1590 if (failpw_func_used
== failpw_func_size
) {
1591 if (failpw_func_size
) {
1592 failpw_func_size
<<= 1;
1593 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1595 failpw_func_size
= 8;
1596 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1599 failpw_func_list
[failpw_func_used
++] = func
;
1603 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1605 * called by nefariouses enhanced AC login-on-connect code
1608 struct handle_info
*loc_auth(char *handle
, char *password
)
1610 int pw_arg
, used
, maxlogins
;
1613 struct handle_info
*hi
;
1614 struct userNode
*other
;
1616 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1622 /* We don't know the users hostname, or anything because they
1623 * havn't registered yet. So we can only allow LOC if your
1624 * account has *@* as a hostmask.
1626 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1628 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1637 /* Responses from here on look up the language used by the handle they asked about. */
1638 if (!checkpass(password
, hi
->passwd
)) {
1641 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1644 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1645 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1646 if (++used
>= maxlogins
) {
1653 static NICKSERV_FUNC(cmd_auth
)
1655 int pw_arg
, used
, maxlogins
;
1656 struct handle_info
*hi
;
1658 struct userNode
*other
;
1660 if (user
->handle_info
) {
1661 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1664 if (IsStamped(user
)) {
1665 /* Unauthenticated users might still have been stamped
1666 previously and could therefore have a hidden host;
1667 do not allow them to authenticate. */
1668 reply("NSMSG_STAMPED_AUTH");
1672 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1674 } else if (argc
== 2) {
1675 if (nickserv_conf
.disable_nicks
) {
1676 if (!(hi
= get_handle_info(user
->nick
))) {
1677 reply("NSMSG_HANDLE_NOT_FOUND");
1681 /* try to look up their handle from their nick */
1682 struct nick_info
*ni
;
1683 ni
= get_nick_info(user
->nick
);
1685 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1692 reply("MSG_MISSING_PARAMS", argv
[0]);
1693 svccmd_send_help(user
, nickserv
, cmd
);
1697 reply("NSMSG_HANDLE_NOT_FOUND");
1700 /* Responses from here on look up the language used by the handle they asked about. */
1701 passwd
= argv
[pw_arg
];
1702 if (!valid_user_for(user
, hi
)) {
1703 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1704 send_message_type(4, user
, cmd
->parent
->bot
,
1705 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1708 send_message_type(4, user
, cmd
->parent
->bot
,
1709 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1711 argv
[pw_arg
] = "BADMASK";
1714 if (!checkpass(passwd
, hi
->passwd
)) {
1716 send_message_type(4, user
, cmd
->parent
->bot
,
1717 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1718 argv
[pw_arg
] = "BADPASS";
1719 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1720 if (nickserv_conf
.autogag_enabled
) {
1721 if (!user
->auth_policer
.params
) {
1722 user
->auth_policer
.last_req
= now
;
1723 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1725 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1727 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1728 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1729 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1731 argv
[pw_arg
] = "GAGGED";
1736 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1737 send_message_type(4, user
, cmd
->parent
->bot
,
1738 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1739 argv
[pw_arg
] = "SUSPENDED";
1742 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1743 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1744 if (++used
>= maxlogins
) {
1745 send_message_type(4, user
, cmd
->parent
->bot
,
1746 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1748 argv
[pw_arg
] = "MAXLOGINS";
1753 set_user_handle_info(user
, hi
, 1);
1754 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1755 reply("NSMSG_PLEASE_SET_EMAIL");
1756 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1757 reply("NSMSG_WEAK_PASSWORD");
1758 if (hi
->passwd
[0] != '$')
1759 cryptpass(passwd
, hi
->passwd
);
1760 reply("NSMSG_AUTH_SUCCESS");
1761 argv
[pw_arg
] = "****";
1765 static allowauth_func_t
*allowauth_func_list
;
1766 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
1769 reg_allowauth_func(allowauth_func_t func
)
1771 if (allowauth_func_used
== allowauth_func_size
) {
1772 if (allowauth_func_size
) {
1773 allowauth_func_size
<<= 1;
1774 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
1776 allowauth_func_size
= 8;
1777 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
1780 allowauth_func_list
[allowauth_func_used
++] = func
;
1783 static NICKSERV_FUNC(cmd_allowauth
)
1785 struct userNode
*target
;
1786 struct handle_info
*hi
;
1789 NICKSERV_MIN_PARMS(2);
1790 if (!(target
= GetUserH(argv
[1]))) {
1791 reply("MSG_NICK_UNKNOWN", argv
[1]);
1794 if (target
->handle_info
) {
1795 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
1798 if (IsStamped(target
)) {
1799 /* Unauthenticated users might still have been stamped
1800 previously and could therefore have a hidden host;
1801 do not allow them to authenticate to an account. */
1802 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
1807 else if (!(hi
= get_handle_info(argv
[2]))) {
1808 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
1812 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
1813 reply("MSG_USER_OUTRANKED", hi
->handle
);
1816 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
1817 || (hi
->opserv_level
> 0))
1818 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
1819 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
1822 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
1823 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
1824 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
1825 if (nickserv_conf
.email_enabled
)
1826 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
1828 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
1829 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
1831 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
1833 for (n
=0; n
<allowauth_func_used
; n
++)
1834 allowauth_func_list
[n
](user
, target
, hi
);
1838 static NICKSERV_FUNC(cmd_authcookie
)
1840 struct handle_info
*hi
;
1842 NICKSERV_MIN_PARMS(2);
1843 if (user
->handle_info
) {
1844 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1847 if (IsStamped(user
)) {
1848 /* Unauthenticated users might still have been stamped
1849 previously and could therefore have a hidden host;
1850 do not allow them to authenticate to an account. */
1851 reply("NSMSG_STAMPED_AUTHCOOKIE");
1854 if (!(hi
= get_handle_info(argv
[1]))) {
1855 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1858 if (!hi
->email_addr
) {
1859 reply("MSG_SET_EMAIL_ADDR");
1862 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
1866 static NICKSERV_FUNC(cmd_delcookie
)
1868 struct handle_info
*hi
;
1870 hi
= user
->handle_info
;
1872 reply("NSMSG_NO_COOKIE");
1875 switch (hi
->cookie
->type
) {
1878 reply("NSMSG_MUST_TIME_OUT");
1881 nickserv_eat_cookie(hi
->cookie
);
1882 reply("NSMSG_ATE_COOKIE");
1888 static NICKSERV_FUNC(cmd_odelcookie
)
1890 struct handle_info
*hi
;
1892 NICKSERV_MIN_PARMS(2);
1894 if (!(hi
= get_victim_oper(user
, argv
[1])))
1898 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
1902 nickserv_eat_cookie(hi
->cookie
);
1903 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
1908 static NICKSERV_FUNC(cmd_resetpass
)
1910 struct handle_info
*hi
;
1911 char crypted
[MD5_CRYPT_LENGTH
];
1914 NICKSERV_MIN_PARMS(3);
1915 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
1919 if (user
->handle_info
) {
1920 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1923 if (IsStamped(user
)) {
1924 /* Unauthenticated users might still have been stamped
1925 previously and could therefore have a hidden host;
1926 do not allow them to activate an account. */
1927 reply("NSMSG_STAMPED_RESETPASS");
1930 if (!(hi
= get_handle_info(argv
[1]))) {
1931 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1934 if (!hi
->email_addr
) {
1935 reply("MSG_SET_EMAIL_ADDR");
1938 cryptpass(argv
[2], crypted
);
1940 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
1944 static NICKSERV_FUNC(cmd_cookie
)
1946 struct handle_info
*hi
;
1949 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
1952 NICKSERV_MIN_PARMS(3);
1953 if (!(hi
= get_handle_info(argv
[1]))) {
1954 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1960 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1961 reply("NSMSG_HANDLE_SUSPENDED");
1966 reply("NSMSG_NO_COOKIE");
1970 /* Check validity of operation before comparing cookie to
1971 * prohibit guessing by authed users. */
1972 if (user
->handle_info
1973 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
1974 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
1975 reply("NSMSG_CANNOT_COOKIE");
1979 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
1980 reply("NSMSG_BAD_COOKIE");
1984 switch (hi
->cookie
->type
) {
1986 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
1987 set_user_handle_info(user
, hi
, 1);
1988 reply("NSMSG_HANDLE_ACTIVATED");
1989 if (nickserv_conf
.sync_log
)
1990 SyncLog("ACCOUNTACC %s", hi
->handle
);
1992 case PASSWORD_CHANGE
:
1993 set_user_handle_info(user
, hi
, 1);
1994 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
1995 reply("NSMSG_PASSWORD_CHANGED");
1996 if (nickserv_conf
.sync_log
)
1997 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2000 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2002 * This should only happen if an OREGISTER was sent. Require
2003 * email must be enabled! - SiRVulcaN
2005 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2007 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2008 reply("NSMSG_EMAIL_CHANGED");
2009 if (nickserv_conf
.sync_log
)
2010 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2013 set_user_handle_info(user
, hi
, 1);
2014 reply("NSMSG_AUTH_SUCCESS");
2017 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2018 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2022 nickserv_eat_cookie(hi
->cookie
);
2027 static NICKSERV_FUNC(cmd_oregnick
) {
2029 struct handle_info
*target
;
2030 struct nick_info
*ni
;
2032 NICKSERV_MIN_PARMS(3);
2033 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2036 if (!is_registerable_nick(nick
)) {
2037 reply("NSMSG_BAD_NICK", nick
);
2040 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2042 reply("NSMSG_NICK_EXISTS", nick
);
2045 register_nick(nick
, target
);
2046 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2050 static NICKSERV_FUNC(cmd_regnick
) {
2052 struct nick_info
*ni
;
2054 if (!is_registerable_nick(user
->nick
)) {
2055 reply("NSMSG_BAD_NICK", user
->nick
);
2058 /* count their nicks, see if it's too many */
2059 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2060 if (n
>= nickserv_conf
.nicks_per_handle
) {
2061 reply("NSMSG_TOO_MANY_NICKS");
2064 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2066 reply("NSMSG_NICK_EXISTS", user
->nick
);
2069 register_nick(user
->nick
, user
->handle_info
);
2070 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2074 static NICKSERV_FUNC(cmd_pass
)
2076 struct handle_info
*hi
;
2077 const char *old_pass
, *new_pass
;
2079 NICKSERV_MIN_PARMS(3);
2080 hi
= user
->handle_info
;
2084 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2085 if (!checkpass(old_pass
, hi
->passwd
)) {
2086 argv
[1] = "BADPASS";
2087 reply("NSMSG_PASSWORD_INVALID");
2090 cryptpass(new_pass
, hi
->passwd
);
2091 if (nickserv_conf
.sync_log
)
2092 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2094 reply("NSMSG_PASS_SUCCESS");
2099 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2102 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2103 for (i
=0; i
<hi
->masks
->used
; i
++) {
2104 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2105 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2110 string_list_append(hi
->masks
, new_mask
);
2111 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2115 static NICKSERV_FUNC(cmd_addmask
)
2118 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2119 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2123 if (!is_gline(argv
[1])) {
2124 reply("NSMSG_MASK_INVALID", argv
[1]);
2127 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2131 static NICKSERV_FUNC(cmd_oaddmask
)
2133 struct handle_info
*hi
;
2135 NICKSERV_MIN_PARMS(3);
2136 if (!(hi
= get_victim_oper(user
, argv
[1])))
2138 return nickserv_addmask(user
, hi
, argv
[2]);
2142 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2145 for (i
=0; i
<hi
->masks
->used
; i
++) {
2146 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2147 char *old_mask
= hi
->masks
->list
[i
];
2148 if (hi
->masks
->used
== 1) {
2149 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2152 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2153 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2158 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2162 static NICKSERV_FUNC(cmd_delmask
)
2164 NICKSERV_MIN_PARMS(2);
2165 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2168 static NICKSERV_FUNC(cmd_odelmask
)
2170 struct handle_info
*hi
;
2171 NICKSERV_MIN_PARMS(3);
2172 if (!(hi
= get_victim_oper(user
, argv
[1])))
2174 return nickserv_delmask(user
, hi
, argv
[2]);
2178 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2179 unsigned int nn
, add
= 1, pos
;
2180 unsigned long added
, removed
, flag
;
2182 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2184 case '+': add
= 1; break;
2185 case '-': add
= 0; break;
2187 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2188 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2191 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2192 /* cheesy avoidance of looking up the flag name.. */
2193 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2196 flag
= 1 << (pos
- 1);
2198 added
|= flag
, removed
&= ~flag
;
2200 removed
|= flag
, added
&= ~flag
;
2205 *premoved
= removed
;
2210 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2212 unsigned long before
, after
, added
, removed
;
2213 struct userNode
*uNode
;
2215 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2216 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2218 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2219 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2221 /* Strip helping flag if they're only a support helper and not
2222 * currently in #support. */
2223 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2224 struct channelList
*schannels
;
2226 schannels
= chanserv_support_channels();
2227 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2228 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2229 if (GetUserMode(schannels
->list
[ii
], uNode
))
2231 if (ii
< schannels
->used
)
2235 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2238 if (after
&& !before
) {
2239 /* Add user to current helper list. */
2240 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2241 userList_append(&curr_helpers
, uNode
);
2242 } else if (!after
&& before
) {
2243 /* Remove user from current helper list. */
2244 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2245 userList_remove(&curr_helpers
, uNode
);
2252 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2256 char *set_display
[] = {
2257 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2258 "EMAIL", "ANNOUNCEMENTS", "MAXLOGINS", "LANGUAGE"
2261 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2263 /* Do this so options are presented in a consistent order. */
2264 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2265 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2266 opt(user
, hi
, override
, 0, NULL
);
2269 static NICKSERV_FUNC(cmd_set
)
2271 struct handle_info
*hi
;
2274 hi
= user
->handle_info
;
2276 set_list(user
, hi
, 0);
2279 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2280 reply("NSMSG_INVALID_OPTION", argv
[1]);
2283 return opt(user
, hi
, 0, argc
-1, argv
+1);
2286 static NICKSERV_FUNC(cmd_oset
)
2288 struct handle_info
*hi
;
2291 NICKSERV_MIN_PARMS(2);
2293 if (!(hi
= get_victim_oper(user
, argv
[1])))
2297 set_list(user
, hi
, 0);
2301 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2302 reply("NSMSG_INVALID_OPTION", argv
[2]);
2306 return opt(user
, hi
, 1, argc
-2, argv
+2);
2309 static OPTION_FUNC(opt_info
)
2313 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2315 hi
->infoline
= NULL
;
2317 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2321 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2322 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2326 static OPTION_FUNC(opt_width
)
2329 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2331 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2332 hi
->screen_width
= MIN_LINE_SIZE
;
2333 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2334 hi
->screen_width
= MAX_LINE_SIZE
;
2336 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2340 static OPTION_FUNC(opt_tablewidth
)
2343 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2345 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2346 hi
->table_width
= MIN_LINE_SIZE
;
2347 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2348 hi
->table_width
= MAX_LINE_SIZE
;
2350 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2354 static OPTION_FUNC(opt_color
)
2357 if (enabled_string(argv
[1]))
2358 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2359 else if (disabled_string(argv
[1]))
2360 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2362 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2367 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2371 static OPTION_FUNC(opt_privmsg
)
2374 if (enabled_string(argv
[1]))
2375 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2376 else if (disabled_string(argv
[1]))
2377 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2379 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2384 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2388 static OPTION_FUNC(opt_style
)
2393 if (!irccasecmp(argv
[1], "Zoot"))
2394 hi
->userlist_style
= HI_STYLE_ZOOT
;
2395 else if (!irccasecmp(argv
[1], "def"))
2396 hi
->userlist_style
= HI_STYLE_DEF
;
2399 switch (hi
->userlist_style
) {
2408 send_message(user
, nickserv
, "NSMSG_SET_STYLE", style
);
2412 static OPTION_FUNC(opt_announcements
)
2417 if (enabled_string(argv
[1]))
2418 hi
->announcements
= 'y';
2419 else if (disabled_string(argv
[1]))
2420 hi
->announcements
= 'n';
2421 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2422 hi
->announcements
= '?';
2424 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2429 switch (hi
->announcements
) {
2430 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2431 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2432 case '?': choice
= "default"; break;
2433 default: choice
= "unknown"; break;
2435 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2439 static OPTION_FUNC(opt_password
)
2442 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2447 cryptpass(argv
[1], hi
->passwd
);
2449 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2453 static OPTION_FUNC(opt_flags
)
2456 unsigned int ii
, flen
;
2459 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2464 nickserv_apply_flags(user
, hi
, argv
[1]);
2466 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2467 if (hi
->flags
& (1 << ii
))
2468 flags
[flen
++] = handle_flags
[ii
];
2471 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2473 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2477 static OPTION_FUNC(opt_email
)
2481 if (!is_valid_email_addr(argv
[1])) {
2482 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2485 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2486 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2489 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2490 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2492 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2494 nickserv_set_email_addr(hi
, argv
[1]);
2496 nickserv_eat_cookie(hi
->cookie
);
2497 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2500 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2504 static OPTION_FUNC(opt_maxlogins
)
2506 unsigned char maxlogins
;
2508 maxlogins
= strtoul(argv
[1], NULL
, 0);
2509 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2510 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2513 hi
->maxlogins
= maxlogins
;
2515 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2516 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2520 static OPTION_FUNC(opt_language
)
2522 struct language
*lang
;
2524 lang
= language_find(argv
[1]);
2525 if (irccasecmp(lang
->name
, argv
[1]))
2526 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2527 hi
->language
= lang
;
2529 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2534 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2535 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2537 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2538 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2539 && (user
->handle_info
->opserv_level
< 1000))) {
2540 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2543 if ((user
->handle_info
->opserv_level
< new_level
)
2544 || ((user
->handle_info
->opserv_level
== new_level
)
2545 && (user
->handle_info
->opserv_level
< 1000))) {
2546 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2549 if (user
->handle_info
== target
) {
2550 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2553 if (target
->opserv_level
== new_level
)
2555 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2556 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2557 target
->opserv_level
= new_level
;
2561 static OPTION_FUNC(opt_level
)
2566 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2570 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2571 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2575 static OPTION_FUNC(opt_epithet
)
2578 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2582 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2583 char *epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2586 if ((epithet
[0] == '*') && !epithet
[1])
2589 hi
->epithet
= strdup(epithet
);
2593 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2595 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2599 static OPTION_FUNC(opt_title
)
2604 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2608 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2610 if (strchr(title
, '.')) {
2611 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2614 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2615 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2616 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2621 if (!strcmp(title
, "*")) {
2622 hi
->fakehost
= NULL
;
2624 hi
->fakehost
= malloc(strlen(title
)+2);
2625 hi
->fakehost
[0] = '.';
2626 strcpy(hi
->fakehost
+1, title
);
2629 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2630 title
= hi
->fakehost
+ 1;
2634 title
= user_find_message(user
, "MSG_NONE");
2635 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2639 static OPTION_FUNC(opt_fakehost
)
2644 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2648 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2650 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
2651 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
2655 if (!strcmp(fake
, "*"))
2656 hi
->fakehost
= NULL
;
2658 hi
->fakehost
= strdup(fake
);
2659 fake
= hi
->fakehost
;
2662 fake
= generate_fakehost(hi
);
2664 fake
= user_find_message(user
, "MSG_NONE");
2665 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
2669 static NICKSERV_FUNC(cmd_reclaim
)
2671 struct handle_info
*hi
;
2672 struct nick_info
*ni
;
2673 struct userNode
*victim
;
2675 NICKSERV_MIN_PARMS(2);
2676 hi
= user
->handle_info
;
2677 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
2679 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
2682 if (ni
->owner
!= user
->handle_info
) {
2683 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
2686 victim
= GetUserH(ni
->nick
);
2688 reply("MSG_NICK_UNKNOWN", ni
->nick
);
2691 if (victim
== user
) {
2692 reply("NSMSG_NICK_USER_YOU");
2695 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
2696 switch (nickserv_conf
.reclaim_action
) {
2697 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
2698 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
2699 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
2700 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
2705 static NICKSERV_FUNC(cmd_unregnick
)
2708 struct handle_info
*hi
;
2709 struct nick_info
*ni
;
2711 hi
= user
->handle_info
;
2712 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
2713 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2715 reply("NSMSG_UNKNOWN_NICK", nick
);
2718 if (hi
!= ni
->owner
) {
2719 reply("NSMSG_NOT_YOUR_NICK", nick
);
2722 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2727 static NICKSERV_FUNC(cmd_ounregnick
)
2729 struct nick_info
*ni
;
2731 NICKSERV_MIN_PARMS(2);
2732 if (!(ni
= get_nick_info(argv
[1]))) {
2733 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
2736 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
2737 reply("MSG_USER_OUTRANKED", ni
->nick
);
2740 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2745 static NICKSERV_FUNC(cmd_unregister
)
2747 struct handle_info
*hi
;
2750 NICKSERV_MIN_PARMS(2);
2751 hi
= user
->handle_info
;
2754 if (checkpass(passwd
, hi
->passwd
)) {
2755 nickserv_unregister_handle(hi
, user
);
2758 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
2759 reply("NSMSG_PASSWORD_INVALID");
2764 static NICKSERV_FUNC(cmd_ounregister
)
2766 struct handle_info
*hi
;
2768 NICKSERV_MIN_PARMS(2);
2769 if (!(hi
= get_victim_oper(user
, argv
[1])))
2771 nickserv_unregister_handle(hi
, user
);
2775 static NICKSERV_FUNC(cmd_status
)
2777 if (nickserv_conf
.disable_nicks
) {
2778 reply("NSMSG_GLOBAL_STATS_NONICK",
2779 dict_size(nickserv_handle_dict
));
2781 if (user
->handle_info
) {
2783 struct nick_info
*ni
;
2784 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
2785 reply("NSMSG_HANDLE_STATS", cnt
);
2787 reply("NSMSG_HANDLE_NONE");
2789 reply("NSMSG_GLOBAL_STATS",
2790 dict_size(nickserv_handle_dict
),
2791 dict_size(nickserv_nick_dict
));
2796 static NICKSERV_FUNC(cmd_ghost
)
2798 struct userNode
*target
;
2799 char reason
[MAXLEN
];
2801 NICKSERV_MIN_PARMS(2);
2802 if (!(target
= GetUserH(argv
[1]))) {
2803 reply("MSG_NICK_UNKNOWN", argv
[1]);
2806 if (target
== user
) {
2807 reply("NSMSG_CANNOT_GHOST_SELF");
2810 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
2811 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
2814 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
2815 DelUser(target
, nickserv
, 1, reason
);
2816 reply("NSMSG_GHOST_KILLED", argv
[1]);
2820 static NICKSERV_FUNC(cmd_vacation
)
2822 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
2823 reply("NSMSG_ON_VACATION");
2828 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
2830 struct handle_info
*hi
;
2833 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
2835 #ifdef WITH_PROTOCOL_BAHAMUT
2838 saxdb_start_record(ctx
, iter_key(it
), 0);
2839 if (hi
->announcements
!= '?') {
2840 flags
[0] = hi
->announcements
;
2842 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
2845 struct handle_cookie
*cookie
= hi
->cookie
;
2848 switch (cookie
->type
) {
2849 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
2850 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
2851 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
2852 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
2853 default: type
= NULL
; break;
2856 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
2857 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
2858 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
2860 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
2861 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
2862 saxdb_end_record(ctx
);
2866 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
2868 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
2870 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
2874 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
2875 if (hi
->flags
& (1 << ii
))
2876 flags
[flen
++] = handle_flags
[ii
];
2878 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
2880 #ifdef WITH_PROTOCOL_BAHAMUT
2881 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
2884 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
2885 if (hi
->last_quit_host
[0])
2886 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
2887 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
2888 if (hi
->masks
->used
)
2889 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
2891 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
2893 struct string_list
*slist
;
2894 struct nick_info
*ni
;
2896 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
2897 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
2898 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
2902 if (hi
->opserv_level
)
2903 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
2904 if (hi
->language
!= lang_C
)
2905 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
2906 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
2907 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
2908 if (hi
->screen_width
)
2909 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
2910 if (hi
->table_width
)
2911 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
2912 flags
[0] = hi
->userlist_style
;
2914 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
2915 saxdb_end_record(ctx
);
2920 static handle_merge_func_t
*handle_merge_func_list
;
2921 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
2924 reg_handle_merge_func(handle_merge_func_t func
)
2926 if (handle_merge_func_used
== handle_merge_func_size
) {
2927 if (handle_merge_func_size
) {
2928 handle_merge_func_size
<<= 1;
2929 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
2931 handle_merge_func_size
= 8;
2932 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
2935 handle_merge_func_list
[handle_merge_func_used
++] = func
;
2938 static NICKSERV_FUNC(cmd_merge
)
2940 struct handle_info
*hi_from
, *hi_to
;
2941 struct userNode
*last_user
;
2942 struct userData
*cList
, *cListNext
;
2943 unsigned int ii
, jj
, n
;
2944 char buffer
[MAXLEN
];
2946 NICKSERV_MIN_PARMS(3);
2948 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
2950 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
2952 if (hi_to
== hi_from
) {
2953 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
2957 for (n
=0; n
<handle_merge_func_used
; n
++)
2958 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
2960 /* Append "from" handle's nicks to "to" handle's nick list. */
2962 struct nick_info
*last_ni
;
2963 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
2964 last_ni
->next
= hi_from
->nicks
;
2966 while (hi_from
->nicks
) {
2967 hi_from
->nicks
->owner
= hi_to
;
2968 hi_from
->nicks
= hi_from
->nicks
->next
;
2971 /* Merge the hostmasks. */
2972 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
2973 char *mask
= hi_from
->masks
->list
[ii
];
2974 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
2975 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
2977 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
2978 string_list_append(hi_to
->masks
, strdup(mask
));
2981 /* Merge the lists of authed users. */
2983 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
2984 last_user
->next_authed
= hi_from
->users
;
2986 hi_to
->users
= hi_from
->users
;
2988 /* Repoint the old "from" handle's users. */
2989 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
2990 last_user
->handle_info
= hi_to
;
2992 hi_from
->users
= NULL
;
2994 /* Merge channel userlists. */
2995 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
2996 struct userData
*cList2
;
2997 cListNext
= cList
->u_next
;
2998 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
2999 if (cList
->channel
== cList2
->channel
)
3001 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3002 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
);
3003 /* keep cList2 in hi_to; remove cList from hi_from */
3004 del_channel_user(cList
, 1);
3007 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
);
3008 /* remove the lower-ranking cList2 from hi_to */
3009 del_channel_user(cList2
, 1);
3011 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3013 /* cList needs to be moved from hi_from to hi_to */
3014 cList
->handle
= hi_to
;
3015 /* Remove from linked list for hi_from */
3016 assert(!cList
->u_prev
);
3017 hi_from
->channels
= cList
->u_next
;
3019 cList
->u_next
->u_prev
= cList
->u_prev
;
3020 /* Add to linked list for hi_to */
3021 cList
->u_prev
= NULL
;
3022 cList
->u_next
= hi_to
->channels
;
3023 if (hi_to
->channels
)
3024 hi_to
->channels
->u_prev
= cList
;
3025 hi_to
->channels
= cList
;
3029 /* Do they get an OpServ level promotion? */
3030 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3031 hi_to
->opserv_level
= hi_from
->opserv_level
;
3033 /* What about last seen time? */
3034 if (hi_from
->lastseen
> hi_to
->lastseen
)
3035 hi_to
->lastseen
= hi_from
->lastseen
;
3037 /* Does a fakehost carry over? (This intentionally doesn't set it
3038 * for users previously attached to hi_to. They'll just have to
3041 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3042 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3044 /* Notify of success. */
3045 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3046 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3047 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3049 /* Unregister the "from" handle. */
3050 nickserv_unregister_handle(hi_from
, NULL
);
3055 struct nickserv_discrim
{
3056 unsigned int limit
, min_level
, max_level
;
3057 unsigned long flags_on
, flags_off
;
3058 time_t min_registered
, max_registered
;
3060 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3061 const char *nickmask
;
3062 const char *hostmask
;
3063 const char *handlemask
;
3064 const char *emailmask
;
3067 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3069 struct discrim_apply_info
{
3070 struct nickserv_discrim
*discrim
;
3071 discrim_search_func func
;
3072 struct userNode
*source
;
3073 unsigned int matched
;
3076 static struct nickserv_discrim
*
3077 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3080 struct nickserv_discrim
*discrim
;
3082 discrim
= malloc(sizeof(*discrim
));
3083 memset(discrim
, 0, sizeof(*discrim
));
3084 discrim
->min_level
= 0;
3085 discrim
->max_level
= ~0;
3086 discrim
->limit
= 50;
3087 discrim
->min_registered
= 0;
3088 discrim
->max_registered
= INT_MAX
;
3089 discrim
->lastseen
= now
;
3091 for (i
=0; i
<argc
; i
++) {
3092 if (i
== argc
- 1) {
3093 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3096 if (!irccasecmp(argv
[i
], "limit")) {
3097 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3098 } else if (!irccasecmp(argv
[i
], "flags")) {
3099 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3100 } else if (!irccasecmp(argv
[i
], "registered")) {
3101 const char *cmp
= argv
[++i
];
3102 if (cmp
[0] == '<') {
3103 if (cmp
[1] == '=') {
3104 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3106 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3108 } else if (cmp
[0] == '=') {
3109 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3110 } else if (cmp
[0] == '>') {
3111 if (cmp
[1] == '=') {
3112 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3114 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3117 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3119 } else if (!irccasecmp(argv
[i
], "seen")) {
3120 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3121 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3122 discrim
->nickmask
= argv
[++i
];
3123 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3125 if (!irccasecmp(argv
[i
], "exact")) {
3126 if (i
== argc
- 1) {
3127 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3130 discrim
->hostmask_type
= EXACT
;
3131 } else if (!irccasecmp(argv
[i
], "subset")) {
3132 if (i
== argc
- 1) {
3133 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3136 discrim
->hostmask_type
= SUBSET
;
3137 } else if (!irccasecmp(argv
[i
], "superset")) {
3138 if (i
== argc
- 1) {
3139 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3142 discrim
->hostmask_type
= SUPERSET
;
3143 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3144 if (i
== argc
- 1) {
3145 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3148 discrim
->hostmask_type
= LASTQUIT
;
3151 discrim
->hostmask_type
= SUPERSET
;
3153 discrim
->hostmask
= argv
[++i
];
3154 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3155 if (!irccasecmp(argv
[++i
], "*")) {
3156 discrim
->handlemask
= 0;
3158 discrim
->handlemask
= argv
[i
];
3160 } else if (!irccasecmp(argv
[i
], "email")) {
3161 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3162 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3164 } else if (!irccasecmp(argv
[++i
], "*")) {
3165 discrim
->emailmask
= 0;
3167 discrim
->emailmask
= argv
[i
];
3169 } else if (!irccasecmp(argv
[i
], "access")) {
3170 const char *cmp
= argv
[++i
];
3171 if (cmp
[0] == '<') {
3172 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3173 if (cmp
[1] == '=') {
3174 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3176 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3178 } else if (cmp
[0] == '=') {
3179 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3180 } else if (cmp
[0] == '>') {
3181 if (cmp
[1] == '=') {
3182 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3184 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3187 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3190 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3201 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3203 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3204 || (discrim
->flags_off
& hi
->flags
)
3205 || (discrim
->min_registered
> hi
->registered
)
3206 || (discrim
->max_registered
< hi
->registered
)
3207 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3208 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3209 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3210 || (discrim
->min_level
> hi
->opserv_level
)
3211 || (discrim
->max_level
< hi
->opserv_level
)) {
3214 if (discrim
->hostmask
) {
3216 for (i
=0; i
<hi
->masks
->used
; i
++) {
3217 const char *mask
= hi
->masks
->list
[i
];
3218 if ((discrim
->hostmask_type
== SUBSET
)
3219 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3220 else if ((discrim
->hostmask_type
== EXACT
)
3221 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3222 else if ((discrim
->hostmask_type
== SUPERSET
)
3223 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3224 else if ((discrim
->hostmask_type
== LASTQUIT
)
3225 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3227 if (i
==hi
->masks
->used
) return 0;
3229 if (discrim
->nickmask
) {
3230 struct nick_info
*nick
= hi
->nicks
;
3232 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3235 if (!nick
) return 0;
3241 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3243 dict_iterator_t it
, next
;
3244 unsigned int matched
;
3246 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3247 it
&& (matched
< discrim
->limit
);
3249 next
= iter_next(it
);
3250 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3251 dsf(source
, iter_data(it
));
3259 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3261 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3265 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3270 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3272 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3273 nickserv_unregister_handle(match
, source
);
3277 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3279 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3280 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3281 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3282 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3283 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3287 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3289 struct handle_info_list hil
;
3290 struct helpfile_table tbl
;
3295 memset(&hil
, 0, sizeof(hil
));
3296 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3297 struct handle_info
*hi
= iter_data(it
);
3298 if (hi
->opserv_level
)
3299 handle_info_list_append(&hil
, hi
);
3301 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3302 tbl
.length
= hil
.used
+ 1;
3304 tbl
.flags
= TABLE_NO_FREE
;
3305 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3306 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3309 for (ii
= 0; ii
< hil
.used
; ) {
3310 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3311 ary
[0] = hil
.list
[ii
]->handle
;
3312 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3313 tbl
.contents
[++ii
] = ary
;
3315 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3316 reply("MSG_MATCH_COUNT", hil
.used
);
3317 for (ii
= 0; ii
< hil
.used
; ii
++)
3318 free(tbl
.contents
[ii
]);
3323 static NICKSERV_FUNC(cmd_search
)
3325 struct nickserv_discrim
*discrim
;
3326 discrim_search_func action
;
3327 struct svccmd
*subcmd
;
3328 unsigned int matches
;
3331 NICKSERV_MIN_PARMS(3);
3332 sprintf(buf
, "search %s", argv
[1]);
3333 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3334 if (!irccasecmp(argv
[1], "print"))
3335 action
= search_print_func
;
3336 else if (!irccasecmp(argv
[1], "count"))
3337 action
= search_count_func
;
3338 else if (!irccasecmp(argv
[1], "unregister"))
3339 action
= search_unregister_func
;
3341 reply("NSMSG_INVALID_ACTION", argv
[1]);
3345 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3348 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3352 if (action
== search_print_func
)
3353 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3354 else if (action
== search_count_func
)
3355 discrim
->limit
= INT_MAX
;
3357 matches
= nickserv_discrim_search(discrim
, action
, user
);
3360 reply("MSG_MATCH_COUNT", matches
);
3362 reply("MSG_NO_MATCHES");
3368 static MODCMD_FUNC(cmd_checkpass
)
3370 struct handle_info
*hi
;
3372 NICKSERV_MIN_PARMS(3);
3373 if (!(hi
= get_handle_info(argv
[1]))) {
3374 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3377 if (checkpass(argv
[2], hi
->passwd
))
3378 reply("CHECKPASS_YES");
3380 reply("CHECKPASS_NO");
3386 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3389 struct string_list
*masks
, *slist
;
3390 struct handle_info
*hi
;
3391 struct userNode
*authed_users
;
3392 unsigned long int id
;
3396 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3397 id
= str
? strtoul(str
, NULL
, 0) : 0;
3398 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3400 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3403 if ((hi
= get_handle_info(handle
))) {
3404 authed_users
= hi
->users
;
3406 dict_remove(nickserv_handle_dict
, hi
->handle
);
3408 authed_users
= NULL
;
3410 hi
= register_handle(handle
, str
, id
);
3412 hi
->users
= authed_users
;
3413 while (authed_users
) {
3414 authed_users
->handle_info
= hi
;
3415 authed_users
= authed_users
->next_authed
;
3418 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3419 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3420 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3421 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3422 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3423 hi
->language
= language_find(str
? str
: "C");
3424 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3425 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3426 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3428 hi
->infoline
= strdup(str
);
3429 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3430 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3431 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3432 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3433 /* We want to read the nicks even if disable_nicks is set. This is so
3434 * that we don't lose the nick data entirely. */
3435 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3437 for (ii
=0; ii
<slist
->used
; ii
++)
3438 register_nick(slist
->list
[ii
], hi
);
3440 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3442 for (ii
=0; str
[ii
]; ii
++)
3443 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3445 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3446 hi
->userlist_style
= str
? str
[0] : HI_STYLE_ZOOT
;
3447 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3448 hi
->announcements
= str
? str
[0] : '?';
3449 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3450 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3451 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3452 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3453 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3455 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3457 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3458 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3460 nickserv_set_email_addr(hi
, str
);
3461 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3463 hi
->epithet
= strdup(str
);
3464 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3466 hi
->fakehost
= strdup(str
);
3467 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3469 const char *data
, *type
, *expires
, *cookie_str
;
3470 struct handle_cookie
*cookie
;
3472 cookie
= calloc(1, sizeof(*cookie
));
3473 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3474 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3475 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3476 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3477 if (!type
|| !expires
|| !cookie_str
) {
3478 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3481 if (!irccasecmp(type
, KEY_ACTIVATION
))
3482 cookie
->type
= ACTIVATION
;
3483 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3484 cookie
->type
= PASSWORD_CHANGE
;
3485 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3486 cookie
->type
= EMAIL_CHANGE
;
3487 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3488 cookie
->type
= ALLOWAUTH
;
3490 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3493 cookie
->expires
= strtoul(expires
, NULL
, 0);
3494 if (cookie
->expires
< now
)
3497 cookie
->data
= strdup(data
);
3498 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3502 nickserv_bake_cookie(cookie
);
3504 nickserv_free_cookie(cookie
);
3509 nickserv_saxdb_read(dict_t db
) {
3511 struct record_data
*rd
;
3513 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3515 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3520 static NICKSERV_FUNC(cmd_mergedb
)
3522 struct timeval start
, stop
;
3525 NICKSERV_MIN_PARMS(2);
3526 gettimeofday(&start
, NULL
);
3527 if (!(db
= parse_database(argv
[1]))) {
3528 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3531 nickserv_saxdb_read(db
);
3533 gettimeofday(&stop
, NULL
);
3534 stop
.tv_sec
-= start
.tv_sec
;
3535 stop
.tv_usec
-= start
.tv_usec
;
3536 if (stop
.tv_usec
< 0) {
3538 stop
.tv_usec
+= 1000000;
3540 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3545 expire_handles(UNUSED_ARG(void *data
))
3547 dict_iterator_t it
, next
;
3549 struct handle_info
*hi
;
3551 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3552 next
= iter_next(it
);
3554 if ((hi
->opserv_level
> 0)
3556 || HANDLE_FLAGGED(hi
, FROZEN
)
3557 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3560 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3561 if ((now
- hi
->lastseen
) > expiry
) {
3562 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3563 nickserv_unregister_handle(hi
, NULL
);
3567 if (nickserv_conf
.handle_expire_frequency
)
3568 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3572 nickserv_load_dict(const char *fname
)
3576 if (!(file
= fopen(fname
, "r"))) {
3577 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
3580 while (!feof(file
)) {
3581 fgets(line
, sizeof(line
), file
);
3584 if (line
[strlen(line
)-1] == '\n')
3585 line
[strlen(line
)-1] = 0;
3586 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
3589 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
3592 static enum reclaim_action
3593 reclaim_action_from_string(const char *str
) {
3595 return RECLAIM_NONE
;
3596 else if (!irccasecmp(str
, "warn"))
3597 return RECLAIM_WARN
;
3598 else if (!irccasecmp(str
, "svsnick"))
3599 return RECLAIM_SVSNICK
;
3600 else if (!irccasecmp(str
, "kill"))
3601 return RECLAIM_KILL
;
3603 return RECLAIM_NONE
;
3607 nickserv_conf_read(void)
3609 dict_t conf_node
, child
;
3613 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
3614 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
3617 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
3619 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
3620 if (nickserv_conf
.valid_handle_regex_set
)
3621 regfree(&nickserv_conf
.valid_handle_regex
);
3623 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3624 nickserv_conf
.valid_handle_regex_set
= !err
;
3625 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
3627 nickserv_conf
.valid_handle_regex_set
= 0;
3629 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
3630 if (nickserv_conf
.valid_nick_regex_set
)
3631 regfree(&nickserv_conf
.valid_nick_regex
);
3633 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3634 nickserv_conf
.valid_nick_regex_set
= !err
;
3635 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
3637 nickserv_conf
.valid_nick_regex_set
= 0;
3639 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
3641 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
3642 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
3643 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
3644 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
3645 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
3646 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
3647 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
3648 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
3649 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
3650 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
3651 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
3652 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
3653 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
3654 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
3655 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
3656 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
3657 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
3658 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
3659 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
3660 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
3661 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
3662 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
3663 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
3664 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
3665 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
3667 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
3668 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
3669 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3671 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3672 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
3673 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3675 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3676 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
3677 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
3678 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
3679 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
3680 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
3681 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
3682 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
3683 if (!nickserv_conf
.disable_nicks
) {
3684 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
3685 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3686 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
3687 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
3688 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
3689 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3690 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
3691 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
3693 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
3694 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
3695 const char *key
= iter_key(it
), *value
;
3699 if (!strncasecmp(key
, "uc_", 3))
3700 flag
= toupper(key
[3]);
3701 else if (!strncasecmp(key
, "lc_", 3))
3702 flag
= tolower(key
[3]);
3706 if ((pos
= handle_inverse_flags
[flag
])) {
3707 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
3708 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
3711 if (nickserv_conf
.weak_password_dict
)
3712 dict_delete(nickserv_conf
.weak_password_dict
);
3713 nickserv_conf
.weak_password_dict
= dict_new();
3714 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
3715 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
3716 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
3717 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
3719 nickserv_load_dict(str
);
3720 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
3721 if (nickserv
&& str
)
3722 NickChange(nickserv
, str
, 0);
3723 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
3724 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
3725 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
3726 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
3727 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
3728 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
3729 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
3730 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
3731 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
3732 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
3733 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
3734 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
3735 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
3736 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
3737 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
3738 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
3739 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
3740 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
3741 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
3742 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
3743 str
= conf_get_data("server/network", RECDB_QSTRING
);
3744 nickserv_conf
.network_name
= str
? str
: "some IRC network";
3745 if (!nickserv_conf
.auth_policer_params
) {
3746 nickserv_conf
.auth_policer_params
= policer_params_new();
3747 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
3748 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
3750 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
3751 for (it
=dict_first(child
); it
; it
=iter_next(it
))
3752 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
3756 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
3758 char newnick
[NICKLEN
+1];
3767 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3769 case RECLAIM_SVSNICK
:
3771 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
3772 } while (GetUserH(newnick
));
3773 irc_svsnick(nickserv
, user
, newnick
);
3776 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
3777 irc_kill(nickserv
, user
, msg
);
3783 nickserv_reclaim_p(void *data
) {
3784 struct userNode
*user
= data
;
3785 struct nick_info
*ni
= get_nick_info(user
->nick
);
3787 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3791 check_user_nick(struct userNode
*user
) {
3792 struct nick_info
*ni
;
3793 user
->modes
&= ~FLAGS_REGNICK
;
3794 if (!(ni
= get_nick_info(user
->nick
)))
3796 if (user
->handle_info
== ni
->owner
) {
3797 user
->modes
|= FLAGS_REGNICK
;
3801 if (nickserv_conf
.warn_nick_owned
)
3802 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3803 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
3805 if (nickserv_conf
.auto_reclaim_delay
)
3806 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
3808 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3813 handle_new_user(struct userNode
*user
)
3815 return check_user_nick(user
);
3819 handle_account(struct userNode
*user
, const char *stamp
)
3821 struct handle_info
*hi
;
3824 #ifdef WITH_PROTOCOL_P10
3825 time_t timestamp
= 0;
3827 colon
= strchr(stamp
, ':');
3828 if(colon
&& colon
[1])
3831 timestamp
= atoi(colon
+1);
3833 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
3834 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
3836 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
);
3840 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
3841 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
3845 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
3848 set_user_handle_info(user
, hi
, 0);
3850 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
3855 handle_nick_change(struct userNode
*user
, const char *old_nick
)
3857 struct handle_info
*hi
;
3859 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
3860 dict_remove(nickserv_allow_auth_dict
, old_nick
);
3861 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
3863 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3864 check_user_nick(user
);
3868 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
3870 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
3871 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3872 set_user_handle_info(user
, NULL
, 0);
3875 static struct modcmd
*
3876 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
3878 if (min_level
> 0) {
3880 sprintf(buf
, "%u", min_level
);
3881 if (must_be_qualified
) {
3882 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
3884 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
3886 } else if (min_level
== 0) {
3887 if (must_be_qualified
) {
3888 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3890 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3893 if (must_be_qualified
) {
3894 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
3896 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
3902 nickserv_db_cleanup(void)
3904 unreg_del_user_func(nickserv_remove_user
);
3905 userList_clean(&curr_helpers
);
3906 policer_params_delete(nickserv_conf
.auth_policer_params
);
3907 dict_delete(nickserv_handle_dict
);
3908 dict_delete(nickserv_nick_dict
);
3909 dict_delete(nickserv_opt_dict
);
3910 dict_delete(nickserv_allow_auth_dict
);
3911 dict_delete(nickserv_email_dict
);
3912 dict_delete(nickserv_id_dict
);
3913 dict_delete(nickserv_conf
.weak_password_dict
);
3914 free(auth_func_list
);
3915 free(unreg_func_list
);
3917 free(allowauth_func_list
);
3918 free(handle_merge_func_list
);
3919 free(failpw_func_list
);
3920 if (nickserv_conf
.valid_handle_regex_set
)
3921 regfree(&nickserv_conf
.valid_handle_regex
);
3922 if (nickserv_conf
.valid_nick_regex_set
)
3923 regfree(&nickserv_conf
.valid_nick_regex
);
3927 init_nickserv(const char *nick
)
3930 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
3931 reg_new_user_func(handle_new_user
);
3932 reg_nick_change_func(handle_nick_change
);
3933 reg_del_user_func(nickserv_remove_user
);
3934 reg_account_func(handle_account
);
3936 /* set up handle_inverse_flags */
3937 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
3938 for (i
=0; handle_flags
[i
]; i
++) {
3939 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
3940 flag_access_levels
[i
] = 0;
3943 conf_register_reload(nickserv_conf_read
);
3944 nickserv_opt_dict
= dict_new();
3945 nickserv_email_dict
= dict_new();
3946 dict_set_free_keys(nickserv_email_dict
, free
);
3947 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
3949 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
3950 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
3951 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
3952 * a big pain to disable since its nolonger in the config file. ) -Rubin
3954 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
3955 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
3956 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
3957 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
3958 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
3959 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
3960 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
3961 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
3962 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
3963 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
3964 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
3965 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
3966 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
3967 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
3968 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
3969 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
3970 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
3971 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
3972 if (!nickserv_conf
.disable_nicks
) {
3973 /* nick management commands */
3974 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
3975 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
3976 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
3977 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
3978 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
3979 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
3981 if (nickserv_conf
.email_enabled
) {
3982 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
3983 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
3984 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
3985 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
3986 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
3987 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
3989 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
3990 /* miscellaneous commands */
3991 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
3992 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
3993 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
3994 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
3995 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
3997 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
3998 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
3999 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4000 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4001 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4002 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
4003 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4004 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4005 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4006 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4007 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4008 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4009 if (nickserv_conf
.titlehost_suffix
) {
4010 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4011 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4013 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4014 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4015 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4017 nickserv_handle_dict
= dict_new();
4018 dict_set_free_keys(nickserv_handle_dict
, free
);
4019 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4021 nickserv_id_dict
= dict_new();
4022 dict_set_free_keys(nickserv_id_dict
, free
);
4024 nickserv_nick_dict
= dict_new();
4025 dict_set_free_data(nickserv_nick_dict
, free
);
4027 nickserv_allow_auth_dict
= dict_new();
4029 userList_init(&curr_helpers
);
4032 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4033 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4034 nickserv_service
= service_register(nickserv
);
4036 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4037 reg_exit_func(nickserv_db_cleanup
);
4038 if(nickserv_conf
.handle_expire_frequency
)
4039 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4040 message_register_table(msgtab
);