1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of srvx.
6 * srvx is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 #include "opserv.h" /* for gag_create(), opserv_bad_channel() */
34 #define NICKSERV_CONF_NAME "services/nickserv"
36 #define KEY_DISABLE_NICKS "disable_nicks"
37 #define KEY_DEFAULT_HOSTMASK "default_hostmask"
38 #define KEY_NICKS_PER_HANDLE "nicks_per_handle"
39 #define KEY_NICKS_PER_ACCOUNT "nicks_per_account"
40 #define KEY_PASSWORD_MIN_LENGTH "password_min_length"
41 #define KEY_PASSWORD_MIN_DIGITS "password_min_digits"
42 #define KEY_PASSWORD_MIN_UPPER "password_min_upper"
43 #define KEY_PASSWORD_MIN_LOWER "password_min_lower"
44 #define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
45 #define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
46 #define KEY_VALID_NICK_REGEX "valid_nick_regex"
47 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
48 #define KEY_MODOPER_LEVEL "modoper_level"
49 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
50 #define KEY_SET_TITLE_LEVEL "set_title_level"
51 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
52 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
53 #define KEY_FLAG_LEVELS "flag_levels"
54 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
55 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
56 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
57 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
58 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
59 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
60 #define KEY_DICT_FILE "dict_file"
61 #define KEY_NICK "nick"
62 #define KEY_LANGUAGE "language"
63 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
64 #define KEY_AUTOGAG_DURATION "autogag_duration"
65 #define KEY_AUTH_POLICER "auth_policer"
66 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
67 #define KEY_EMAIL_ENABLED "email_enabled"
68 #define KEY_EMAIL_REQUIRED "email_required"
69 #define KEY_SYNC_LOG "sync_log"
70 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
71 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
72 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
75 #define KEY_PASSWD "passwd"
76 #define KEY_NICKS "nicks"
77 #define KEY_MASKS "masks"
78 #define KEY_OPSERV_LEVEL "opserv_level"
79 #define KEY_FLAGS "flags"
80 #define KEY_REGISTER_ON "register"
81 #define KEY_LAST_SEEN "lastseen"
82 #define KEY_INFO "info"
83 #define KEY_USERLIST_STYLE "user_style"
84 #define KEY_SCREEN_WIDTH "screen_width"
85 #define KEY_LAST_AUTHED_HOST "last_authed_host"
86 #define KEY_LAST_QUIT_HOST "last_quit_host"
87 #define KEY_EMAIL_ADDR "email_addr"
88 #define KEY_COOKIE "cookie"
89 #define KEY_COOKIE_DATA "data"
90 #define KEY_COOKIE_TYPE "type"
91 #define KEY_COOKIE_EXPIRES "expires"
92 #define KEY_ACTIVATION "activation"
93 #define KEY_PASSWORD_CHANGE "password change"
94 #define KEY_EMAIL_CHANGE "email change"
95 #define KEY_ALLOWAUTH "allowauth"
96 #define KEY_EPITHET "epithet"
97 #define KEY_TABLE_WIDTH "table_width"
98 #define KEY_ANNOUNCEMENTS "announcements"
99 #define KEY_MAXLOGINS "maxlogins"
100 #define KEY_FAKEHOST "fakehost"
102 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
104 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
105 #define OPTION_FUNC(NAME) int NAME(struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
106 typedef OPTION_FUNC(option_func_t
);
108 DEFINE_LIST(handle_info_list
, struct handle_info
*);
110 #define NICKSERV_MIN_PARMS(N) do { \
112 reply("MSG_MISSING_PARAMS", argv[0]); \
113 svccmd_send_help(user, nickserv, cmd); \
117 struct userNode
*nickserv
;
118 struct userList curr_helpers
;
119 const char *handle_flags
= HANDLE_FLAGS
;
121 static struct module *nickserv_module
;
122 static struct service
*nickserv_service
;
123 static struct log_type
*NS_LOG
;
124 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
125 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
126 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
127 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
128 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
129 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
130 static char handle_inverse_flags
[256];
131 static unsigned int flag_access_levels
[32];
132 static const struct message_entry msgtab
[] = {
133 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
134 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu charactors or less."},
135 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
136 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
137 { "NSMSG_PASSWORD_DICTIONARY", "Your password should not be the word \"password\", or any other dictionary word." },
138 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
139 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
140 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
141 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
142 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
143 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
144 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
145 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
146 { "NSMSG_USE_COOKIE_REGISTER", "To activate your account, you must check your email for the \"cookie\" that has been mailed to it. When you have it, use the $bcookie$b command to complete registration." },
147 { "NSMSG_USE_COOKIE_RESETPASS", "A cookie has been mailed to your account's email address. You must check your email and use the $bcookie$b command to confirm the password change." },
148 { "NSMSG_USE_COOKIE_EMAIL_1", "A cookie has been mailed to the new address you requested. To finish setting your email address, please check your email for the cookie and use the $bcookie$b command to verify." },
149 { "NSMSG_USE_COOKIE_EMAIL_2", "A cookie has been generated, and half mailed to each your old and new addresses. To finish changing your email address, please check your email for the cookie and use the $bcookie$b command to verify." },
150 { "NSMSG_USE_COOKIE_AUTH", "A cookie has been generated and sent to your email address. Once you have checked your email and received the cookie, auth using the $bcookie$b command." },
151 { "NSMSG_COOKIE_LIVE", "Account $b%s$b already has a cookie active. Please either finish using that cookie, wait for it to expire, or auth to the account and use the $bdelcookie$b command." },
152 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
153 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
154 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
155 { "NSMSG_BAD_COOKIE", "That cookie is not the right one. Please make sure you are copying it EXACTLY from the email; it is case-sensitive, so $bABC$b is different from $babc$b." },
156 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
157 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
158 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
159 { "NSMSG_EMAIL_OVERUSED", "There are already the maximum number of accounts associated with that email address." },
160 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
161 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
162 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
163 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
164 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
165 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
166 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
167 { "NSMSG_REGISTER_BAD_NICKMASK", "Could not recognize $b%s$b as either a current nick or a hostmask." },
168 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
169 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
170 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
171 { "NSMSG_USE_AUTHCOOKIE", "Your hostmask is not valid for account $b%1$s$b. Please use the $bauthcookie$b command to grant yourself access. (/msg $S authcookie %1$s)" },
172 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
173 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
174 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
175 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
176 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
177 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
178 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
179 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
180 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
181 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
182 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
183 { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
184 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
185 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
186 { "NSMSG_HANDLEINFO_ON", "Account information for $b%s$b:" },
187 { "NSMSG_HANDLEINFO_ID", " Account ID: %lu" },
188 { "NSMSG_HANDLEINFO_REGGED", " Registered on: %s" },
189 { "NSMSG_HANDLEINFO_LASTSEEN", " Last seen: %s" },
190 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", " Last seen: Right now!" },
191 { "NSMSG_HANDLEINFO_VACATION", " On vacation." },
192 { "NSMSG_HANDLEINFO_EMAIL_ADDR", " Email address: %s" },
193 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", " Cookie: There is currently an activation cookie issued for this account" },
194 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", " Cookie: There is currently a password change cookie issued for this account" },
195 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", " Cookie: There is currently an email change cookie issued for this account" },
196 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", " Cookie: There is currently an allowauth cookie issued for this account" },
197 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", " Cookie: There is currently an unknown cookie issued for this account" },
198 { "NSMSG_HANDLEINFO_INFOLINE", " Infoline: %s" },
199 { "NSMSG_HANDLEINFO_FLAGS", " Flags: %s" },
200 { "NSMSG_HANDLEINFO_EPITHET", " Epithet: %s" },
201 { "NSMSG_HANDLEINFO_FAKEHOST", " Fake host: %s" },
202 { "NSMSG_HANDLEINFO_LAST_HOST", " Last quit hostmask: %s" },
203 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", " Last quit hostmask: Unknown" },
204 { "NSMSG_HANDLEINFO_NICKS", " Nickname(s): %s" },
205 { "NSMSG_HANDLEINFO_MASKS", " Hostmask(s): %s" },
206 { "NSMSG_HANDLEINFO_CHANNELS", " Channel(s): %s" },
207 { "NSMSG_HANDLEINFO_CURRENT", " Current nickname(s): %s" },
208 { "NSMSG_HANDLEINFO_DNR", " Do-not-register (by %s): %s" },
209 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
210 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
211 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
212 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
213 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
214 { "NSMSG_WEAK_PASSWORD", "WARNING: You are using a password that is considered weak (easy to guess). It is STRONGLY recommended you change it (now, if not sooner) by typing \"/msg $S@$s PASS oldpass newpass\" (with your current password and a new password)." },
215 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
216 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
217 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
218 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
219 { "NSMSG_AUTH_ALLOWED_MSG", "You may now authenticate to account $b%s$b by typing $b/msg $N@$s auth %s password$b (using your password). If you will be using this computer regularly, please type $b/msg $N addmask$b (AFTER you auth) to permanently add your hostmask." },
220 { "NSMSG_AUTH_ALLOWED_EMAIL", "You may also (after you auth) type $b/msg $N set email user@your.isp$b to set an email address. This will let you use the $bauthcookie$b command to be authenticated in the future." },
221 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
222 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
223 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
224 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
225 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
226 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
227 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
228 { "NSMSG_PASS_SUCCESS", "Password changed." },
229 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
230 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
231 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
232 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
233 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
234 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
235 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
236 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
237 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
238 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
239 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
240 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
241 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
242 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
243 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
244 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
245 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
246 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
247 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
248 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
249 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
250 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
251 { "NSMSG_NO_ACCESS", "Access denied." },
252 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
253 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
254 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
255 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
256 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
257 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
258 { "NSMSG_BAD_HANDLE", "Account $b%s$b not registered because it is in use by a network service, is too long, or contains invalid characters." },
259 { "NSMSG_BAD_NICK", "Nickname $b%s$b not registered because it is in use by a network service, is too long, or contains invalid characters." },
260 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
261 { "NSMSG_FAIL_RENAME", "Account $b%s$b not renamed to $b%s$b because it is in use by a network services, or contains invalid characters." },
262 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
263 { "NSMSG_SEARCH_MATCH", "Match: %s" },
264 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
265 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
266 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
267 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
268 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
269 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
270 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
271 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
272 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
273 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
274 { "NSMSG_SETTING_LIST", "$b$N account settings:$b" },
275 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
276 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
277 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
278 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
279 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
280 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
281 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
282 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
283 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
284 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
285 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
286 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
287 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
288 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
289 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
290 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
291 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
292 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
293 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
294 { "NSEMAIL_ACTIVATION_BODY",
295 "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n"
297 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
298 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
299 "This command is only used once to complete your account registration, and never again. Once you have run this command, you will need to authenticate everytime you reconnect to the network. To do this, you will have to type this command every time you reconnect:\n"
300 "/msg %3$s@%4$s AUTH %5$s your-password\n"
301 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
302 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
304 "If you did NOT request this account, you do not need to do anything.\n"
305 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
306 { "NSEMAIL_ACTIVATION_BODY_WEB",
307 "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n"
309 "To verify your email address and complete the account registration, visit the following URL:\n"
310 "http://www.afternet.org/play/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
312 "If you did NOT request this account, you do not need to do anything.\n"
313 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
314 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
315 { "NSEMAIL_PASSWORD_CHANGE_BODY",
316 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
317 "To complete the password change, log on to %1$s and type the following command:\n"
318 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
319 "If you did NOT request your password to be changed, you do not need to do anything.\n"
320 "Please contact the %1$s staff if you have questions." },
321 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
322 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
323 "To complete the password change, click the following URL:\n"
324 "http://www.afternet.org/play/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
325 "If you did NOT request your password to be changed, you do not need to do anything.\n"
326 "Please contact the %1$s staff if you have questions." },
327 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
328 #ifdef stupid_verify_old_email
329 { "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." },
330 { "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." },
332 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
333 { "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." },
334 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
335 { "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." },
336 { "CHECKPASS_YES", "Yes." },
337 { "CHECKPASS_NO", "No." },
341 enum reclaim_action
{
347 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
348 static void nickserv_reclaim_p(void *data
);
351 unsigned int disable_nicks
: 1;
352 unsigned int valid_handle_regex_set
: 1;
353 unsigned int valid_nick_regex_set
: 1;
354 unsigned int autogag_enabled
: 1;
355 unsigned int email_enabled
: 1;
356 unsigned int email_required
: 1;
357 unsigned int default_hostmask
: 1;
358 unsigned int warn_nick_owned
: 1;
359 unsigned int warn_clone_auth
: 1;
360 unsigned int sync_log
: 1;
361 unsigned long nicks_per_handle
;
362 unsigned long password_min_length
;
363 unsigned long password_min_digits
;
364 unsigned long password_min_upper
;
365 unsigned long password_min_lower
;
366 unsigned long db_backup_frequency
;
367 unsigned long handle_expire_frequency
;
368 unsigned long autogag_duration
;
369 unsigned long email_visible_level
;
370 unsigned long cookie_timeout
;
371 unsigned long handle_expire_delay
;
372 unsigned long nochan_handle_expire_delay
;
373 unsigned long modoper_level
;
374 unsigned long set_epithet_level
;
375 unsigned long set_title_level
;
376 unsigned long set_fakehost_level
;
377 unsigned long handles_per_email
;
378 unsigned long email_search_level
;
379 const char *network_name
;
380 const char *titlehost_suffix
;
381 regex_t valid_handle_regex
;
382 regex_t valid_nick_regex
;
383 dict_t weak_password_dict
;
384 struct policer_params
*auth_policer_params
;
385 enum reclaim_action reclaim_action
;
386 enum reclaim_action auto_reclaim_action
;
387 unsigned long auto_reclaim_delay
;
388 unsigned char default_maxlogins
;
389 unsigned char hard_maxlogins
;
392 /* We have 2^32 unique account IDs to use. */
393 unsigned long int highest_id
= 0;
396 canonicalize_hostmask(char *mask
)
398 char *out
= mask
, *temp
;
399 if ((temp
= strchr(mask
, '!'))) {
401 while (*temp
) *out
++ = *temp
++;
407 static struct handle_info
*
408 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
410 struct handle_info
*hi
;
412 #ifdef WITH_PROTOCOL_BAHAMUT
413 char id_base64
[IDLEN
+ 1];
416 /* Assign a unique account ID to the account; note that 0 is
417 an invalid account ID. 1 is therefore the first account ID. */
419 id
= 1 + highest_id
++;
421 /* Note: highest_id is and must always be the highest ID. */
422 if(id
> highest_id
) {
426 inttobase64(id_base64
, id
, IDLEN
);
428 /* Make sure an account with the same ID doesn't exist. If a
429 duplicate is found, log some details and assign a new one.
430 This should be impossible, but it never hurts to expect it. */
431 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
432 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
438 hi
= calloc(1, sizeof(*hi
));
439 hi
->userlist_style
= HI_DEFAULT_STYLE
;
440 hi
->announcements
= '?';
441 hi
->handle
= strdup(handle
);
442 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
444 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
446 #ifdef WITH_PROTOCOL_BAHAMUT
448 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
455 register_nick(const char *nick
, struct handle_info
*owner
)
457 struct nick_info
*ni
;
458 ni
= malloc(sizeof(struct nick_info
));
459 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
461 ni
->next
= owner
->nicks
;
463 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
467 delete_nick(struct nick_info
*ni
)
469 struct nick_info
*last
, *next
;
470 struct userNode
*user
;
471 /* Check to see if we should mark a user as unregistered. */
472 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
473 user
->modes
&= ~FLAGS_REGNICK
;
476 /* Remove ni from the nick_info linked list. */
477 if (ni
== ni
->owner
->nicks
) {
478 ni
->owner
->nicks
= ni
->next
;
480 last
= ni
->owner
->nicks
;
486 last
->next
= next
->next
;
488 dict_remove(nickserv_nick_dict
, ni
->nick
);
491 static unreg_func_t
*unreg_func_list
;
492 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
495 reg_unreg_func(unreg_func_t func
)
497 if (unreg_func_used
== unreg_func_size
) {
498 if (unreg_func_size
) {
499 unreg_func_size
<<= 1;
500 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
503 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
506 unreg_func_list
[unreg_func_used
++] = func
;
510 nickserv_free_cookie(void *data
)
512 struct handle_cookie
*cookie
= data
;
513 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
514 if (cookie
->data
) free(cookie
->data
);
519 free_handle_info(void *vhi
)
521 struct handle_info
*hi
= vhi
;
523 #ifdef WITH_PROTOCOL_BAHAMUT
526 inttobase64(id
, hi
->id
, IDLEN
);
527 dict_remove(nickserv_id_dict
, id
);
530 free_string_list(hi
->masks
);
534 delete_nick(hi
->nicks
);
539 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
540 nickserv_free_cookie(hi
->cookie
);
542 if (hi
->email_addr
) {
543 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
544 handle_info_list_remove(hil
, hi
);
546 dict_remove(nickserv_email_dict
, hi
->email_addr
);
551 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
554 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
)
558 for (n
=0; n
<unreg_func_used
; n
++)
559 unreg_func_list
[n
](notify
, hi
);
561 set_user_handle_info(hi
->users
, NULL
, 0);
563 if (nickserv_conf
.disable_nicks
)
564 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
566 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
569 if (nickserv_conf
.sync_log
)
570 SyncLog("UNREGISTER %s", hi
->handle
);
572 dict_remove(nickserv_handle_dict
, hi
->handle
);
576 get_handle_info(const char *handle
)
578 return dict_find(nickserv_handle_dict
, handle
, 0);
582 get_nick_info(const char *nick
)
584 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
588 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
593 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
594 mn
= channel
->members
.list
[nn
];
595 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
602 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
603 if (!user
->handle_info
) {
605 send_message(user
, bot
, "MSG_AUTHENTICATE");
609 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
611 send_message(user
, bot
, "NSMSG_NO_ACCESS");
615 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
617 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
621 if (user
->handle_info
->opserv_level
< min_level
) {
623 send_message(user
, bot
, "NSMSG_NO_ACCESS");
631 is_valid_handle(const char *handle
)
633 struct userNode
*user
;
634 /* cant register a juped nick/service nick as handle, to prevent confusion */
635 user
= GetUserH(handle
);
636 if (user
&& IsLocal(user
))
638 /* check against maximum length */
639 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
641 /* for consistency, only allow account names that could be nicks */
642 if (!is_valid_nick(handle
))
644 /* disallow account names that look like bad words */
645 if (opserv_bad_channel(handle
))
647 /* test either regex or containing all valid chars */
648 if (nickserv_conf
.valid_handle_regex_set
) {
649 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
652 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
653 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
657 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
662 is_registerable_nick(const char *nick
)
664 /* make sure it could be used as an account name */
665 if (!is_valid_handle(nick
))
668 if (strlen(nick
) > NICKLEN
)
670 /* test either regex or as valid handle */
671 if (nickserv_conf
.valid_nick_regex_set
) {
672 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
675 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
676 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
684 is_valid_email_addr(const char *email
)
686 return strchr(email
, '@') != NULL
;
690 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
692 if (hi
->email_addr
) {
693 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
694 return hi
->email_addr
;
704 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
706 struct handle_info
*hi
;
707 struct userNode
*target
;
711 if (!(hi
= get_handle_info(++name
))) {
712 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
717 if (!(target
= GetUserH(name
))) {
718 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
721 if (IsLocal(target
)) {
722 if (IsService(target
))
723 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
725 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
728 if (!(hi
= target
->handle_info
)) {
729 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
737 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
738 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
740 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
741 if ((user
->handle_info
->opserv_level
== 1000)
742 || (user
->handle_info
== hi
)
743 || ((user
->handle_info
->opserv_level
== 0)
744 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
745 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
749 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
753 static struct handle_info
*
754 get_victim_oper(struct userNode
*user
, const char *target
)
756 struct handle_info
*hi
;
757 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
759 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
760 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
763 return oper_outranks(user
, hi
) ? hi
: NULL
;
767 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
771 /* If no hostmasks on the account, allow it. */
772 if (!hi
->masks
->used
)
774 /* If any hostmask matches, allow it. */
775 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
776 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
778 /* If they are allowauthed to this account, allow it (removing the aa). */
779 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
780 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
783 /* The user is not allowed to use this account. */
788 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
791 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
793 if (len
< nickserv_conf
.password_min_length
) {
795 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
798 if (!irccasecmp(pass
, handle
)) {
800 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
803 dict_find(nickserv_conf
.weak_password_dict
, pass
, &i
);
806 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
809 for (i
=0; i
<len
; i
++) {
810 if (isdigit(pass
[i
]))
812 if (isupper(pass
[i
]))
814 if (islower(pass
[i
]))
817 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
818 || (cnt_upper
< nickserv_conf
.password_min_upper
)
819 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
821 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
827 static auth_func_t
*auth_func_list
;
828 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
831 reg_auth_func(auth_func_t func
)
833 if (auth_func_used
== auth_func_size
) {
834 if (auth_func_size
) {
835 auth_func_size
<<= 1;
836 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
839 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
842 auth_func_list
[auth_func_used
++] = func
;
845 static handle_rename_func_t
*rf_list
;
846 static unsigned int rf_list_size
, rf_list_used
;
849 reg_handle_rename_func(handle_rename_func_t func
)
851 if (rf_list_used
== rf_list_size
) {
854 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
857 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
860 rf_list
[rf_list_used
++] = func
;
864 generate_fakehost(struct handle_info
*handle
)
866 extern const char *hidden_host_suffix
;
867 static char buffer
[HOSTLEN
+1];
869 if (!handle
->fakehost
) {
870 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
872 } else if (handle
->fakehost
[0] == '.') {
873 /* A leading dot indicates the stored value is actually a title. */
874 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
877 return handle
->fakehost
;
881 apply_fakehost(struct handle_info
*handle
)
883 struct userNode
*target
;
888 fake
= generate_fakehost(handle
);
889 for (target
= handle
->users
; target
; target
= target
->next_authed
)
890 assign_fakehost(target
, fake
, 1);
894 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
897 struct handle_info
*old_info
;
899 /* This can happen if somebody uses COOKIE while authed, or if
900 * they re-auth to their current handle (which is silly, but users
902 if (user
->handle_info
== hi
)
905 if (user
->handle_info
) {
906 struct userNode
*other
;
909 userList_remove(&curr_helpers
, user
);
911 /* remove from next_authed linked list */
912 if (user
->handle_info
->users
== user
) {
913 user
->handle_info
->users
= user
->next_authed
;
915 for (other
= user
->handle_info
->users
;
916 other
->next_authed
!= user
;
917 other
= other
->next_authed
) ;
918 other
->next_authed
= user
->next_authed
;
920 /* if nobody left on old handle, and they're not an oper, remove !god */
921 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
922 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
923 /* record them as being last seen at this time */
924 user
->handle_info
->lastseen
= now
;
925 /* and record their hostmask */
926 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
928 old_info
= user
->handle_info
;
929 user
->handle_info
= hi
;
930 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
931 HANDLE_CLEAR_FLAG(hi
, HELPING
);
932 for (n
=0; n
<auth_func_used
; n
++)
933 auth_func_list
[n
](user
, old_info
);
935 struct nick_info
*ni
;
937 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
938 if (nickserv_conf
.warn_clone_auth
) {
939 struct userNode
*other
;
940 for (other
= hi
->users
; other
; other
= other
->next_authed
)
941 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
943 user
->next_authed
= hi
->users
;
947 userList_append(&curr_helpers
, user
);
949 if (hi
->fakehost
|| old_info
)
953 #ifdef WITH_PROTOCOL_BAHAMUT
954 /* Stamp users with their account ID. */
956 inttobase64(id
, hi
->id
, IDLEN
);
957 #elif WITH_PROTOCOL_P10
958 /* Stamp users with their account name. */
959 char *id
= hi
->handle
;
961 const char *id
= "???";
963 if (!nickserv_conf
.disable_nicks
) {
964 struct nick_info
*ni
;
965 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
966 if (!irccasecmp(user
->nick
, ni
->nick
)) {
967 user
->modes
|= FLAGS_REGNICK
;
972 StampUser(user
, id
, hi
->registered
);
975 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
976 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
978 /* We cannot clear the user's account ID, unfortunately. */
979 user
->next_authed
= NULL
;
983 static struct handle_info
*
984 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
986 struct handle_info
*hi
;
987 struct nick_info
*ni
;
988 char crypted
[MD5_CRYPT_LENGTH
];
990 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
991 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
995 if(strlen(handle
) > 15)
997 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1001 if (!is_secure_password(handle
, passwd
, user
))
1004 cryptpass(passwd
, crypted
);
1005 hi
= register_handle(handle
, crypted
, 0);
1006 hi
->masks
= alloc_string_list(1);
1008 hi
->language
= lang_C
;
1009 hi
->registered
= now
;
1011 hi
->flags
= HI_DEFAULT_FLAGS
;
1012 if (settee
&& !no_auth
)
1013 set_user_handle_info(settee
, hi
, 1);
1016 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1017 else if (nickserv_conf
.disable_nicks
)
1018 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1019 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1020 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1022 register_nick(user
->nick
, hi
);
1023 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1025 if (settee
&& (user
!= settee
))
1026 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1031 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1033 cookie
->hi
->cookie
= cookie
;
1034 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1038 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1040 struct handle_cookie
*cookie
;
1041 char subject
[128], body
[4096], *misc
;
1042 const char *netname
, *fmt
;
1046 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1050 cookie
= calloc(1, sizeof(*cookie
));
1052 cookie
->type
= type
;
1053 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1054 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1055 inttobase64(cookie
->cookie
, rand(), 5);
1056 inttobase64(cookie
->cookie
+5, rand(), 5);
1058 netname
= nickserv_conf
.network_name
;
1061 switch (cookie
->type
) {
1063 hi
->passwd
[0] = 0; /* invalidate password */
1064 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1065 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1066 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1069 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1071 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1073 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1076 case PASSWORD_CHANGE
:
1077 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1078 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1079 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1081 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1083 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1084 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1087 misc
= hi
->email_addr
;
1088 hi
->email_addr
= cookie
->data
;
1089 #ifdef stupid_verify_old_email
1091 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1092 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1093 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1094 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1095 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1096 sendmail(nickserv
, hi
, subject
, body
, 1);
1097 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1098 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1101 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1102 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1103 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1104 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1105 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1106 sendmail(nickserv
, hi
, subject
, body
, 1);
1108 #ifdef stupid_verify_old_email
1111 hi
->email_addr
= misc
;
1114 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1115 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1116 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1117 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1118 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1121 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1125 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1126 nickserv_bake_cookie(cookie
);
1130 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1132 cookie
->hi
->cookie
= NULL
;
1133 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1134 nickserv_free_cookie(cookie
);
1138 nickserv_free_email_addr(void *data
)
1140 handle_info_list_clean(data
);
1145 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1147 struct handle_info_list
*hil
;
1148 /* Remove from old handle_info_list ... */
1149 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1150 handle_info_list_remove(hil
, hi
);
1151 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1152 hi
->email_addr
= NULL
;
1154 /* Add to the new list.. */
1155 if (new_email_addr
) {
1156 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1157 hil
= calloc(1, sizeof(*hil
));
1158 hil
->tag
= strdup(new_email_addr
);
1159 handle_info_list_init(hil
);
1160 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1162 handle_info_list_append(hil
, hi
);
1163 hi
->email_addr
= hil
->tag
;
1167 static NICKSERV_FUNC(cmd_register
)
1169 struct handle_info
*hi
;
1170 const char *email_addr
, *password
;
1171 char syncpass
[MD5_CRYPT_LENGTH
];
1172 int no_auth
, weblink
;
1174 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1175 /* Require the first handle registered to belong to someone +o. */
1176 reply("NSMSG_REQUIRE_OPER");
1180 if (user
->handle_info
) {
1181 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1185 if (IsRegistering(user
)) {
1186 reply("NSMSG_ALREADY_REGISTERING");
1190 if (IsStamped(user
)) {
1191 /* Unauthenticated users might still have been stamped
1192 previously and could therefore have a hidden host;
1193 do not allow them to register a new account. */
1194 reply("NSMSG_STAMPED_REGISTER");
1198 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1200 if (!is_valid_handle(argv
[1])) {
1201 reply("NSMSG_BAD_HANDLE", argv
[1]);
1206 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1207 struct handle_info_list
*hil
;
1210 /* Remember email address. */
1211 email_addr
= argv
[3];
1213 /* Check that the email address looks valid.. */
1214 if (!is_valid_email_addr(email_addr
)) {
1215 reply("NSMSG_BAD_EMAIL_ADDR");
1219 /* .. and that we are allowed to send to it. */
1220 if ((str
= sendmail_prohibited_address(email_addr
))) {
1221 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1225 /* If we do email verify, make sure we don't spam the address. */
1226 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1228 for (nn
=0; nn
<hil
->used
; nn
++) {
1229 if (hil
->list
[nn
]->cookie
) {
1230 reply("NSMSG_EMAIL_UNACTIVATED");
1234 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1235 reply("NSMSG_EMAIL_OVERUSED");
1248 /* Webregister hack - send URL instead of IRC cookie
1251 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1255 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1257 /* Add any masks they should get. */
1258 if (nickserv_conf
.default_hostmask
) {
1259 string_list_append(hi
->masks
, strdup("*@*"));
1261 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1262 if (user
->ip
.s_addr
&& user
->hostname
[strspn(user
->hostname
, "0123456789.")])
1263 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1266 /* If they're the first to register, give them level 1000. */
1267 if (dict_size(nickserv_handle_dict
) == 1) {
1268 hi
->opserv_level
= 1000;
1269 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1272 /* Set their email address. */
1274 nickserv_set_email_addr(hi
, email_addr
);
1276 /* If they need to do email verification, tell them. */
1278 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1280 /* Set registering flag.. */
1281 user
->modes
|= FLAGS_REGISTERING
;
1283 if (nickserv_conf
.sync_log
) {
1284 cryptpass(password
, syncpass
);
1286 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1287 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1290 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1296 static NICKSERV_FUNC(cmd_oregister
)
1299 struct userNode
*settee
;
1300 struct handle_info
*hi
;
1302 NICKSERV_MIN_PARMS(4);
1304 if (!is_valid_handle(argv
[1])) {
1305 reply("NSMSG_BAD_HANDLE", argv
[1]);
1309 if (strchr(argv
[3], '@')) {
1310 mask
= canonicalize_hostmask(strdup(argv
[3]));
1312 settee
= GetUserH(argv
[4]);
1314 reply("MSG_NICK_UNKNOWN", argv
[4]);
1321 } else if ((settee
= GetUserH(argv
[3]))) {
1322 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1324 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1327 if (settee
&& settee
->handle_info
) {
1328 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1332 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1336 string_list_append(hi
->masks
, mask
);
1340 static NICKSERV_FUNC(cmd_handleinfo
)
1343 unsigned int i
, pos
=0, herelen
;
1344 struct userNode
*target
, *next_un
;
1345 struct handle_info
*hi
;
1346 const char *nsmsg_none
;
1349 if (!(hi
= user
->handle_info
)) {
1350 reply("NSMSG_MUST_AUTH");
1353 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1357 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1358 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1359 #ifdef WITH_PROTOCOL_BAHAMUT
1360 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1362 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1365 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1366 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1368 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1371 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1372 if (HANDLE_FLAGGED(hi
, FROZEN
))
1373 reply("NSMSG_HANDLEINFO_VACATION");
1375 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1376 struct do_not_register
*dnr
;
1377 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1378 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1379 if (!oper_outranks(user
, hi
))
1381 } else if (hi
!= user
->handle_info
)
1384 if (nickserv_conf
.email_enabled
)
1385 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1389 switch (hi
->cookie
->type
) {
1390 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1391 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1392 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1393 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1394 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1400 unsigned long flen
= 1;
1401 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1403 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1404 if (hi
->flags
& 1 << i
)
1405 flags
[flen
++] = handle_flags
[i
];
1407 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1409 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1412 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1413 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1414 || (hi
->opserv_level
> 0)) {
1415 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1419 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1421 if (hi
->last_quit_host
[0])
1422 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1424 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1426 if (nickserv_conf
.disable_nicks
) {
1427 /* nicks disabled; don't show anything about registered nicks */
1428 } else if (hi
->nicks
) {
1429 struct nick_info
*ni
, *next_ni
;
1430 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1431 herelen
= strlen(ni
->nick
);
1432 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1434 goto print_nicks_buff
;
1438 memcpy(buff
+pos
, ni
->nick
, herelen
);
1439 pos
+= herelen
; buff
[pos
++] = ' ';
1443 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1448 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1451 if (hi
->masks
->used
) {
1452 for (i
=0; i
< hi
->masks
->used
; i
++) {
1453 herelen
= strlen(hi
->masks
->list
[i
]);
1454 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1456 goto print_mask_buff
;
1458 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1459 pos
+= herelen
; buff
[pos
++] = ' ';
1460 if (i
+1 == hi
->masks
->used
) {
1463 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1468 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1472 struct userData
*channel
, *next
;
1475 for (channel
= hi
->channels
; channel
; channel
= next
) {
1476 next
= channel
->u_next
;
1477 name
= channel
->channel
->channel
->name
;
1478 herelen
= strlen(name
);
1479 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1481 goto print_chans_buff
;
1483 if (IsUserSuspended(channel
))
1485 pos
+= sprintf(buff
+pos
, "%d:%s ", channel
->access
, name
);
1489 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1494 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1497 for (target
= hi
->users
; target
; target
= next_un
) {
1498 herelen
= strlen(target
->nick
);
1499 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1501 goto print_cnick_buff
;
1503 next_un
= target
->next_authed
;
1505 memcpy(buff
+pos
, target
->nick
, herelen
);
1506 pos
+= herelen
; buff
[pos
++] = ' ';
1510 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1518 static NICKSERV_FUNC(cmd_userinfo
)
1520 struct userNode
*target
;
1522 NICKSERV_MIN_PARMS(2);
1523 if (!(target
= GetUserH(argv
[1]))) {
1524 reply("MSG_NICK_UNKNOWN", argv
[1]);
1527 if (target
->handle_info
)
1528 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1530 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1534 static NICKSERV_FUNC(cmd_nickinfo
)
1536 struct nick_info
*ni
;
1538 NICKSERV_MIN_PARMS(2);
1539 if (!(ni
= get_nick_info(argv
[1]))) {
1540 reply("MSG_NICK_UNKNOWN", argv
[1]);
1543 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1547 static NICKSERV_FUNC(cmd_rename_handle
)
1549 struct handle_info
*hi
;
1550 char msgbuf
[MAXLEN
], *old_handle
;
1553 NICKSERV_MIN_PARMS(3);
1554 if (!(hi
= get_victim_oper(user
, argv
[1])))
1556 if (!is_valid_handle(argv
[2])) {
1557 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1560 if (get_handle_info(argv
[2])) {
1561 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1564 if(strlen(argv
[2]) > 15)
1566 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1570 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1571 hi
->handle
= strdup(argv
[2]);
1572 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1573 for (nn
=0; nn
<rf_list_used
; nn
++)
1574 rf_list
[nn
](hi
, old_handle
);
1575 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1576 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1577 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1582 static failpw_func_t
*failpw_func_list
;
1583 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1586 reg_failpw_func(failpw_func_t func
)
1588 if (failpw_func_used
== failpw_func_size
) {
1589 if (failpw_func_size
) {
1590 failpw_func_size
<<= 1;
1591 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1593 failpw_func_size
= 8;
1594 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1597 failpw_func_list
[failpw_func_used
++] = func
;
1601 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1603 * called by nefariouses enhanced AC login-on-connect code
1606 struct handle_info
*loc_auth(char *handle
, char *password
)
1608 int pw_arg
, used
, maxlogins
;
1611 struct handle_info
*hi
;
1612 struct userNode
*other
;
1614 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1620 /* We don't know the users hostname, or anything because they
1621 * havn't registered yet. So we can only allow LOC if your
1622 * account has *@* as a hostmask.
1624 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1626 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1635 /* Responses from here on look up the language used by the handle they asked about. */
1636 if (!checkpass(password
, hi
->passwd
)) {
1639 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1642 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1643 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1644 if (++used
>= maxlogins
) {
1651 static NICKSERV_FUNC(cmd_auth
)
1653 int pw_arg
, used
, maxlogins
;
1654 struct handle_info
*hi
;
1656 struct userNode
*other
;
1658 if (user
->handle_info
) {
1659 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1662 if (IsStamped(user
)) {
1663 /* Unauthenticated users might still have been stamped
1664 previously and could therefore have a hidden host;
1665 do not allow them to authenticate. */
1666 reply("NSMSG_STAMPED_AUTH");
1670 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1672 } else if (argc
== 2) {
1673 if (nickserv_conf
.disable_nicks
) {
1674 if (!(hi
= get_handle_info(user
->nick
))) {
1675 reply("NSMSG_HANDLE_NOT_FOUND");
1679 /* try to look up their handle from their nick */
1680 struct nick_info
*ni
;
1681 ni
= get_nick_info(user
->nick
);
1683 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1690 reply("MSG_MISSING_PARAMS", argv
[0]);
1691 svccmd_send_help(user
, nickserv
, cmd
);
1695 reply("NSMSG_HANDLE_NOT_FOUND");
1698 /* Responses from here on look up the language used by the handle they asked about. */
1699 passwd
= argv
[pw_arg
];
1700 if (!valid_user_for(user
, hi
)) {
1701 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1702 send_message_type(4, user
, cmd
->parent
->bot
,
1703 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1706 send_message_type(4, user
, cmd
->parent
->bot
,
1707 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1709 argv
[pw_arg
] = "BADMASK";
1712 if (!checkpass(passwd
, hi
->passwd
)) {
1714 send_message_type(4, user
, cmd
->parent
->bot
,
1715 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1716 argv
[pw_arg
] = "BADPASS";
1717 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1718 if (nickserv_conf
.autogag_enabled
) {
1719 if (!user
->auth_policer
.params
) {
1720 user
->auth_policer
.last_req
= now
;
1721 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1723 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1725 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1726 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1727 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1729 argv
[pw_arg
] = "GAGGED";
1734 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1735 send_message_type(4, user
, cmd
->parent
->bot
,
1736 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1737 argv
[pw_arg
] = "SUSPENDED";
1740 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1741 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1742 if (++used
>= maxlogins
) {
1743 send_message_type(4, user
, cmd
->parent
->bot
,
1744 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1746 argv
[pw_arg
] = "MAXLOGINS";
1751 set_user_handle_info(user
, hi
, 1);
1752 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1753 reply("NSMSG_PLEASE_SET_EMAIL");
1754 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1755 reply("NSMSG_WEAK_PASSWORD");
1756 if (hi
->passwd
[0] != '$')
1757 cryptpass(passwd
, hi
->passwd
);
1758 reply("NSMSG_AUTH_SUCCESS");
1759 argv
[pw_arg
] = "****";
1763 static allowauth_func_t
*allowauth_func_list
;
1764 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
1767 reg_allowauth_func(allowauth_func_t func
)
1769 if (allowauth_func_used
== allowauth_func_size
) {
1770 if (allowauth_func_size
) {
1771 allowauth_func_size
<<= 1;
1772 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
1774 allowauth_func_size
= 8;
1775 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
1778 allowauth_func_list
[allowauth_func_used
++] = func
;
1781 static NICKSERV_FUNC(cmd_allowauth
)
1783 struct userNode
*target
;
1784 struct handle_info
*hi
;
1787 NICKSERV_MIN_PARMS(2);
1788 if (!(target
= GetUserH(argv
[1]))) {
1789 reply("MSG_NICK_UNKNOWN", argv
[1]);
1792 if (target
->handle_info
) {
1793 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
1796 if (IsStamped(target
)) {
1797 /* Unauthenticated users might still have been stamped
1798 previously and could therefore have a hidden host;
1799 do not allow them to authenticate to an account. */
1800 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
1805 else if (!(hi
= get_handle_info(argv
[2]))) {
1806 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
1810 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
1811 reply("MSG_USER_OUTRANKED", hi
->handle
);
1814 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
1815 || (hi
->opserv_level
> 0))
1816 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
1817 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
1820 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
1821 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
1822 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
1823 if (nickserv_conf
.email_enabled
)
1824 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
1826 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
1827 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
1829 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
1831 for (n
=0; n
<allowauth_func_used
; n
++)
1832 allowauth_func_list
[n
](user
, target
, hi
);
1836 static NICKSERV_FUNC(cmd_authcookie
)
1838 struct handle_info
*hi
;
1840 NICKSERV_MIN_PARMS(2);
1841 if (user
->handle_info
) {
1842 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1845 if (IsStamped(user
)) {
1846 /* Unauthenticated users might still have been stamped
1847 previously and could therefore have a hidden host;
1848 do not allow them to authenticate to an account. */
1849 reply("NSMSG_STAMPED_AUTHCOOKIE");
1852 if (!(hi
= get_handle_info(argv
[1]))) {
1853 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1856 if (!hi
->email_addr
) {
1857 reply("MSG_SET_EMAIL_ADDR");
1860 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
1864 static NICKSERV_FUNC(cmd_delcookie
)
1866 struct handle_info
*hi
;
1868 hi
= user
->handle_info
;
1870 reply("NSMSG_NO_COOKIE");
1873 switch (hi
->cookie
->type
) {
1876 reply("NSMSG_MUST_TIME_OUT");
1879 nickserv_eat_cookie(hi
->cookie
);
1880 reply("NSMSG_ATE_COOKIE");
1886 static NICKSERV_FUNC(cmd_resetpass
)
1888 struct handle_info
*hi
;
1889 char crypted
[MD5_CRYPT_LENGTH
];
1892 NICKSERV_MIN_PARMS(3);
1893 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
1897 if (user
->handle_info
) {
1898 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1901 if (IsStamped(user
)) {
1902 /* Unauthenticated users might still have been stamped
1903 previously and could therefore have a hidden host;
1904 do not allow them to activate an account. */
1905 reply("NSMSG_STAMPED_RESETPASS");
1908 if (!(hi
= get_handle_info(argv
[1]))) {
1909 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1912 if (!hi
->email_addr
) {
1913 reply("MSG_SET_EMAIL_ADDR");
1916 cryptpass(argv
[2], crypted
);
1918 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
1922 static NICKSERV_FUNC(cmd_cookie
)
1924 struct handle_info
*hi
;
1927 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
1930 NICKSERV_MIN_PARMS(3);
1931 if (!(hi
= get_handle_info(argv
[1]))) {
1932 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1938 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1939 reply("NSMSG_HANDLE_SUSPENDED");
1944 reply("NSMSG_NO_COOKIE");
1948 /* Check validity of operation before comparing cookie to
1949 * prohibit guessing by authed users. */
1950 if (user
->handle_info
1951 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
1952 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
1953 reply("NSMSG_CANNOT_COOKIE");
1957 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
1958 reply("NSMSG_BAD_COOKIE");
1962 switch (hi
->cookie
->type
) {
1964 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
1965 set_user_handle_info(user
, hi
, 1);
1966 reply("NSMSG_HANDLE_ACTIVATED");
1967 if (nickserv_conf
.sync_log
)
1968 SyncLog("ACCOUNTACC %s", hi
->handle
);
1970 case PASSWORD_CHANGE
:
1971 set_user_handle_info(user
, hi
, 1);
1972 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
1973 reply("NSMSG_PASSWORD_CHANGED");
1974 if (nickserv_conf
.sync_log
)
1975 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
1978 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
1980 * This should only happen if an OREGISTER was sent. Require
1981 * email must be enabled! - SiRVulcaN
1983 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
1985 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
1986 reply("NSMSG_EMAIL_CHANGED");
1987 if (nickserv_conf
.sync_log
)
1988 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
1991 set_user_handle_info(user
, hi
, 1);
1992 reply("NSMSG_AUTH_SUCCESS");
1995 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
1996 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2000 nickserv_eat_cookie(hi
->cookie
);
2005 static NICKSERV_FUNC(cmd_oregnick
) {
2007 struct handle_info
*target
;
2008 struct nick_info
*ni
;
2010 NICKSERV_MIN_PARMS(3);
2011 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2014 if (!is_registerable_nick(nick
)) {
2015 reply("NSMSG_BAD_NICK", nick
);
2018 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2020 reply("NSMSG_NICK_EXISTS", nick
);
2023 register_nick(nick
, target
);
2024 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2028 static NICKSERV_FUNC(cmd_regnick
) {
2030 struct nick_info
*ni
;
2032 if (!is_registerable_nick(user
->nick
)) {
2033 reply("NSMSG_BAD_NICK", user
->nick
);
2036 /* count their nicks, see if it's too many */
2037 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2038 if (n
>= nickserv_conf
.nicks_per_handle
) {
2039 reply("NSMSG_TOO_MANY_NICKS");
2042 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2044 reply("NSMSG_NICK_EXISTS", user
->nick
);
2047 register_nick(user
->nick
, user
->handle_info
);
2048 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2052 static NICKSERV_FUNC(cmd_pass
)
2054 struct handle_info
*hi
;
2055 const char *old_pass
, *new_pass
;
2057 NICKSERV_MIN_PARMS(3);
2058 hi
= user
->handle_info
;
2062 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2063 if (!checkpass(old_pass
, hi
->passwd
)) {
2064 argv
[1] = "BADPASS";
2065 reply("NSMSG_PASSWORD_INVALID");
2068 cryptpass(new_pass
, hi
->passwd
);
2069 if (nickserv_conf
.sync_log
)
2070 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2072 reply("NSMSG_PASS_SUCCESS");
2077 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2080 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2081 for (i
=0; i
<hi
->masks
->used
; i
++) {
2082 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2083 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2088 string_list_append(hi
->masks
, new_mask
);
2089 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2093 static NICKSERV_FUNC(cmd_addmask
)
2096 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2097 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2101 if (!is_gline(argv
[1])) {
2102 reply("NSMSG_MASK_INVALID", argv
[1]);
2105 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2109 static NICKSERV_FUNC(cmd_oaddmask
)
2111 struct handle_info
*hi
;
2113 NICKSERV_MIN_PARMS(3);
2114 if (!(hi
= get_victim_oper(user
, argv
[1])))
2116 return nickserv_addmask(user
, hi
, argv
[2]);
2120 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2123 for (i
=0; i
<hi
->masks
->used
; i
++) {
2124 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2125 char *old_mask
= hi
->masks
->list
[i
];
2126 if (hi
->masks
->used
== 1) {
2127 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2130 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2131 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2136 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2140 static NICKSERV_FUNC(cmd_delmask
)
2142 NICKSERV_MIN_PARMS(2);
2143 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2146 static NICKSERV_FUNC(cmd_odelmask
)
2148 struct handle_info
*hi
;
2149 NICKSERV_MIN_PARMS(3);
2150 if (!(hi
= get_victim_oper(user
, argv
[1])))
2152 return nickserv_delmask(user
, hi
, argv
[2]);
2156 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2157 unsigned int nn
, add
= 1, pos
;
2158 unsigned long added
, removed
, flag
;
2160 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2162 case '+': add
= 1; break;
2163 case '-': add
= 0; break;
2165 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2166 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2169 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2170 /* cheesy avoidance of looking up the flag name.. */
2171 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2174 flag
= 1 << (pos
- 1);
2176 added
|= flag
, removed
&= ~flag
;
2178 removed
|= flag
, added
&= ~flag
;
2183 *premoved
= removed
;
2188 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2190 unsigned long before
, after
, added
, removed
;
2191 struct userNode
*uNode
;
2193 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2194 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2196 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2197 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2199 /* Strip helping flag if they're only a support helper and not
2200 * currently in #support. */
2201 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2202 struct channelList
*schannels
;
2204 schannels
= chanserv_support_channels();
2205 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2206 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2207 if (GetUserMode(schannels
->list
[ii
], uNode
))
2209 if (ii
< schannels
->used
)
2213 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2216 if (after
&& !before
) {
2217 /* Add user to current helper list. */
2218 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2219 userList_append(&curr_helpers
, uNode
);
2220 } else if (!after
&& before
) {
2221 /* Remove user from current helper list. */
2222 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2223 userList_remove(&curr_helpers
, uNode
);
2230 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2234 char *set_display
[] = {
2235 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2236 "EMAIL", "ANNOUNCEMENTS", "MAXLOGINS", "LANGUAGE"
2239 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2241 /* Do this so options are presented in a consistent order. */
2242 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2243 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2244 opt(user
, hi
, override
, 0, NULL
);
2247 static NICKSERV_FUNC(cmd_set
)
2249 struct handle_info
*hi
;
2252 hi
= user
->handle_info
;
2254 set_list(user
, hi
, 0);
2257 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2258 reply("NSMSG_INVALID_OPTION", argv
[1]);
2261 return opt(user
, hi
, 0, argc
-1, argv
+1);
2264 static NICKSERV_FUNC(cmd_oset
)
2266 struct handle_info
*hi
;
2269 NICKSERV_MIN_PARMS(2);
2271 if (!(hi
= get_victim_oper(user
, argv
[1])))
2275 set_list(user
, hi
, 0);
2279 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2280 reply("NSMSG_INVALID_OPTION", argv
[2]);
2284 return opt(user
, hi
, 1, argc
-2, argv
+2);
2287 static OPTION_FUNC(opt_info
)
2291 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2293 hi
->infoline
= NULL
;
2295 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2299 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2300 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2304 static OPTION_FUNC(opt_width
)
2307 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2309 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2310 hi
->screen_width
= MIN_LINE_SIZE
;
2311 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2312 hi
->screen_width
= MAX_LINE_SIZE
;
2314 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2318 static OPTION_FUNC(opt_tablewidth
)
2321 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2323 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2324 hi
->table_width
= MIN_LINE_SIZE
;
2325 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2326 hi
->table_width
= MAX_LINE_SIZE
;
2328 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2332 static OPTION_FUNC(opt_color
)
2335 if (enabled_string(argv
[1]))
2336 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2337 else if (disabled_string(argv
[1]))
2338 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2340 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2345 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2349 static OPTION_FUNC(opt_privmsg
)
2352 if (enabled_string(argv
[1]))
2353 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2354 else if (disabled_string(argv
[1]))
2355 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2357 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2362 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2366 static OPTION_FUNC(opt_style
)
2371 if (!irccasecmp(argv
[1], "Zoot"))
2372 hi
->userlist_style
= HI_STYLE_ZOOT
;
2373 else if (!irccasecmp(argv
[1], "def"))
2374 hi
->userlist_style
= HI_STYLE_DEF
;
2377 switch (hi
->userlist_style
) {
2386 send_message(user
, nickserv
, "NSMSG_SET_STYLE", style
);
2390 static OPTION_FUNC(opt_announcements
)
2395 if (enabled_string(argv
[1]))
2396 hi
->announcements
= 'y';
2397 else if (disabled_string(argv
[1]))
2398 hi
->announcements
= 'n';
2399 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2400 hi
->announcements
= '?';
2402 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2407 switch (hi
->announcements
) {
2408 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2409 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2410 case '?': choice
= "default"; break;
2411 default: choice
= "unknown"; break;
2413 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2417 static OPTION_FUNC(opt_password
)
2420 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2425 cryptpass(argv
[1], hi
->passwd
);
2427 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2431 static OPTION_FUNC(opt_flags
)
2434 unsigned int ii
, flen
;
2437 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2442 nickserv_apply_flags(user
, hi
, argv
[1]);
2444 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2445 if (hi
->flags
& (1 << ii
))
2446 flags
[flen
++] = handle_flags
[ii
];
2449 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2451 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2455 static OPTION_FUNC(opt_email
)
2459 if (!is_valid_email_addr(argv
[1])) {
2460 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2463 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2464 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2467 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2468 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2470 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2472 nickserv_set_email_addr(hi
, argv
[1]);
2474 nickserv_eat_cookie(hi
->cookie
);
2475 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2478 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2482 static OPTION_FUNC(opt_maxlogins
)
2484 unsigned char maxlogins
;
2486 maxlogins
= strtoul(argv
[1], NULL
, 0);
2487 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2488 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2491 hi
->maxlogins
= maxlogins
;
2493 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2494 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2498 static OPTION_FUNC(opt_language
)
2500 struct language
*lang
;
2502 lang
= language_find(argv
[1]);
2503 if (irccasecmp(lang
->name
, argv
[1]))
2504 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2505 hi
->language
= lang
;
2507 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2512 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2513 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2515 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2516 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2517 && (user
->handle_info
->opserv_level
< 1000))) {
2518 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2521 if ((user
->handle_info
->opserv_level
< new_level
)
2522 || ((user
->handle_info
->opserv_level
== new_level
)
2523 && (user
->handle_info
->opserv_level
< 1000))) {
2524 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2527 if (user
->handle_info
== target
) {
2528 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2531 if (target
->opserv_level
== new_level
)
2533 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2534 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2535 target
->opserv_level
= new_level
;
2539 static OPTION_FUNC(opt_level
)
2544 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2548 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2549 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2553 static OPTION_FUNC(opt_epithet
)
2556 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2560 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2561 char *epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2564 if ((epithet
[0] == '*') && !epithet
[1])
2567 hi
->epithet
= strdup(epithet
);
2571 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2573 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2577 static OPTION_FUNC(opt_title
)
2582 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2586 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2588 if (strchr(title
, '.')) {
2589 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2592 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2593 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2594 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2599 if (!strcmp(title
, "*")) {
2600 hi
->fakehost
= NULL
;
2602 hi
->fakehost
= malloc(strlen(title
)+2);
2603 hi
->fakehost
[0] = '.';
2604 strcpy(hi
->fakehost
+1, title
);
2607 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2608 title
= hi
->fakehost
+ 1;
2612 title
= user_find_message(user
, "MSG_NONE");
2613 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2617 static OPTION_FUNC(opt_fakehost
)
2622 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2626 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2628 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
2629 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
2633 if (!strcmp(fake
, "*"))
2634 hi
->fakehost
= NULL
;
2636 hi
->fakehost
= strdup(fake
);
2637 fake
= hi
->fakehost
;
2640 fake
= generate_fakehost(hi
);
2642 fake
= user_find_message(user
, "MSG_NONE");
2643 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
2647 static NICKSERV_FUNC(cmd_reclaim
)
2649 struct handle_info
*hi
;
2650 struct nick_info
*ni
;
2651 struct userNode
*victim
;
2653 NICKSERV_MIN_PARMS(2);
2654 hi
= user
->handle_info
;
2655 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
2657 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
2660 if (ni
->owner
!= user
->handle_info
) {
2661 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
2664 victim
= GetUserH(ni
->nick
);
2666 reply("MSG_NICK_UNKNOWN", ni
->nick
);
2669 if (victim
== user
) {
2670 reply("NSMSG_NICK_USER_YOU");
2673 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
2674 switch (nickserv_conf
.reclaim_action
) {
2675 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
2676 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
2677 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
2678 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
2683 static NICKSERV_FUNC(cmd_unregnick
)
2686 struct handle_info
*hi
;
2687 struct nick_info
*ni
;
2689 hi
= user
->handle_info
;
2690 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
2691 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2693 reply("NSMSG_UNKNOWN_NICK", nick
);
2696 if (hi
!= ni
->owner
) {
2697 reply("NSMSG_NOT_YOUR_NICK", nick
);
2700 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2705 static NICKSERV_FUNC(cmd_ounregnick
)
2707 struct nick_info
*ni
;
2709 NICKSERV_MIN_PARMS(2);
2710 if (!(ni
= get_nick_info(argv
[1]))) {
2711 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
2714 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
2715 reply("MSG_USER_OUTRANKED", ni
->nick
);
2718 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2723 static NICKSERV_FUNC(cmd_unregister
)
2725 struct handle_info
*hi
;
2728 NICKSERV_MIN_PARMS(2);
2729 hi
= user
->handle_info
;
2732 if (checkpass(passwd
, hi
->passwd
)) {
2733 nickserv_unregister_handle(hi
, user
);
2736 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
2737 reply("NSMSG_PASSWORD_INVALID");
2742 static NICKSERV_FUNC(cmd_ounregister
)
2744 struct handle_info
*hi
;
2746 NICKSERV_MIN_PARMS(2);
2747 if (!(hi
= get_victim_oper(user
, argv
[1])))
2749 nickserv_unregister_handle(hi
, user
);
2753 static NICKSERV_FUNC(cmd_status
)
2755 if (nickserv_conf
.disable_nicks
) {
2756 reply("NSMSG_GLOBAL_STATS_NONICK",
2757 dict_size(nickserv_handle_dict
));
2759 if (user
->handle_info
) {
2761 struct nick_info
*ni
;
2762 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
2763 reply("NSMSG_HANDLE_STATS", cnt
);
2765 reply("NSMSG_HANDLE_NONE");
2767 reply("NSMSG_GLOBAL_STATS",
2768 dict_size(nickserv_handle_dict
),
2769 dict_size(nickserv_nick_dict
));
2774 static NICKSERV_FUNC(cmd_ghost
)
2776 struct userNode
*target
;
2777 char reason
[MAXLEN
];
2779 NICKSERV_MIN_PARMS(2);
2780 if (!(target
= GetUserH(argv
[1]))) {
2781 reply("MSG_NICK_UNKNOWN", argv
[1]);
2784 if (target
== user
) {
2785 reply("NSMSG_CANNOT_GHOST_SELF");
2788 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
2789 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
2792 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
2793 DelUser(target
, nickserv
, 1, reason
);
2794 reply("NSMSG_GHOST_KILLED", argv
[1]);
2798 static NICKSERV_FUNC(cmd_vacation
)
2800 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
2801 reply("NSMSG_ON_VACATION");
2806 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
2808 struct handle_info
*hi
;
2811 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
2813 #ifdef WITH_PROTOCOL_BAHAMUT
2816 saxdb_start_record(ctx
, iter_key(it
), 0);
2817 if (hi
->announcements
!= '?') {
2818 flags
[0] = hi
->announcements
;
2820 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
2823 struct handle_cookie
*cookie
= hi
->cookie
;
2826 switch (cookie
->type
) {
2827 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
2828 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
2829 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
2830 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
2831 default: type
= NULL
; break;
2834 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
2835 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
2836 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
2838 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
2839 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
2840 saxdb_end_record(ctx
);
2844 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
2846 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
2848 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
2852 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
2853 if (hi
->flags
& (1 << ii
))
2854 flags
[flen
++] = handle_flags
[ii
];
2856 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
2858 #ifdef WITH_PROTOCOL_BAHAMUT
2859 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
2862 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
2863 if (hi
->last_quit_host
[0])
2864 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
2865 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
2866 if (hi
->masks
->used
)
2867 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
2869 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
2871 struct string_list
*slist
;
2872 struct nick_info
*ni
;
2874 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
2875 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
2876 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
2880 if (hi
->opserv_level
)
2881 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
2882 if (hi
->language
!= lang_C
)
2883 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
2884 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
2885 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
2886 if (hi
->screen_width
)
2887 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
2888 if (hi
->table_width
)
2889 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
2890 flags
[0] = hi
->userlist_style
;
2892 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
2893 saxdb_end_record(ctx
);
2898 static handle_merge_func_t
*handle_merge_func_list
;
2899 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
2902 reg_handle_merge_func(handle_merge_func_t func
)
2904 if (handle_merge_func_used
== handle_merge_func_size
) {
2905 if (handle_merge_func_size
) {
2906 handle_merge_func_size
<<= 1;
2907 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
2909 handle_merge_func_size
= 8;
2910 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
2913 handle_merge_func_list
[handle_merge_func_used
++] = func
;
2916 static NICKSERV_FUNC(cmd_merge
)
2918 struct handle_info
*hi_from
, *hi_to
;
2919 struct userNode
*last_user
;
2920 struct userData
*cList
, *cListNext
;
2921 unsigned int ii
, jj
, n
;
2922 char buffer
[MAXLEN
];
2924 NICKSERV_MIN_PARMS(3);
2926 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
2928 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
2930 if (hi_to
== hi_from
) {
2931 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
2935 for (n
=0; n
<handle_merge_func_used
; n
++)
2936 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
2938 /* Append "from" handle's nicks to "to" handle's nick list. */
2940 struct nick_info
*last_ni
;
2941 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
2942 last_ni
->next
= hi_from
->nicks
;
2944 while (hi_from
->nicks
) {
2945 hi_from
->nicks
->owner
= hi_to
;
2946 hi_from
->nicks
= hi_from
->nicks
->next
;
2949 /* Merge the hostmasks. */
2950 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
2951 char *mask
= hi_from
->masks
->list
[ii
];
2952 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
2953 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
2955 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
2956 string_list_append(hi_to
->masks
, strdup(mask
));
2959 /* Merge the lists of authed users. */
2961 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
2962 last_user
->next_authed
= hi_from
->users
;
2964 hi_to
->users
= hi_from
->users
;
2966 /* Repoint the old "from" handle's users. */
2967 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
2968 last_user
->handle_info
= hi_to
;
2970 hi_from
->users
= NULL
;
2972 /* Merge channel userlists. */
2973 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
2974 struct userData
*cList2
;
2975 cListNext
= cList
->u_next
;
2976 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
2977 if (cList
->channel
== cList2
->channel
)
2979 if (cList2
&& (cList2
->access
>= cList
->access
)) {
2980 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
);
2981 /* keep cList2 in hi_to; remove cList from hi_from */
2982 del_channel_user(cList
, 1);
2985 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
);
2986 /* remove the lower-ranking cList2 from hi_to */
2987 del_channel_user(cList2
, 1);
2989 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
2991 /* cList needs to be moved from hi_from to hi_to */
2992 cList
->handle
= hi_to
;
2993 /* Remove from linked list for hi_from */
2994 assert(!cList
->u_prev
);
2995 hi_from
->channels
= cList
->u_next
;
2997 cList
->u_next
->u_prev
= cList
->u_prev
;
2998 /* Add to linked list for hi_to */
2999 cList
->u_prev
= NULL
;
3000 cList
->u_next
= hi_to
->channels
;
3001 if (hi_to
->channels
)
3002 hi_to
->channels
->u_prev
= cList
;
3003 hi_to
->channels
= cList
;
3007 /* Do they get an OpServ level promotion? */
3008 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3009 hi_to
->opserv_level
= hi_from
->opserv_level
;
3011 /* What about last seen time? */
3012 if (hi_from
->lastseen
> hi_to
->lastseen
)
3013 hi_to
->lastseen
= hi_from
->lastseen
;
3015 /* Notify of success. */
3016 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3017 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3018 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3020 /* Unregister the "from" handle. */
3021 nickserv_unregister_handle(hi_from
, NULL
);
3026 struct nickserv_discrim
{
3027 unsigned int limit
, min_level
, max_level
;
3028 unsigned long flags_on
, flags_off
;
3029 time_t min_registered
, max_registered
;
3031 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3032 const char *nickmask
;
3033 const char *hostmask
;
3034 const char *handlemask
;
3035 const char *emailmask
;
3038 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3040 struct discrim_apply_info
{
3041 struct nickserv_discrim
*discrim
;
3042 discrim_search_func func
;
3043 struct userNode
*source
;
3044 unsigned int matched
;
3047 static struct nickserv_discrim
*
3048 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3051 struct nickserv_discrim
*discrim
;
3053 discrim
= malloc(sizeof(*discrim
));
3054 memset(discrim
, 0, sizeof(*discrim
));
3055 discrim
->min_level
= 0;
3056 discrim
->max_level
= ~0;
3057 discrim
->limit
= 50;
3058 discrim
->min_registered
= 0;
3059 discrim
->max_registered
= INT_MAX
;
3060 discrim
->lastseen
= now
;
3062 for (i
=0; i
<argc
; i
++) {
3063 if (i
== argc
- 1) {
3064 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3067 if (!irccasecmp(argv
[i
], "limit")) {
3068 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3069 } else if (!irccasecmp(argv
[i
], "flags")) {
3070 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3071 } else if (!irccasecmp(argv
[i
], "registered")) {
3072 const char *cmp
= argv
[++i
];
3073 if (cmp
[0] == '<') {
3074 if (cmp
[1] == '=') {
3075 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3077 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3079 } else if (cmp
[0] == '=') {
3080 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3081 } else if (cmp
[0] == '>') {
3082 if (cmp
[1] == '=') {
3083 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3085 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3088 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3090 } else if (!irccasecmp(argv
[i
], "seen")) {
3091 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3092 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3093 discrim
->nickmask
= argv
[++i
];
3094 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3096 if (!irccasecmp(argv
[i
], "exact")) {
3097 if (i
== argc
- 1) {
3098 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3101 discrim
->hostmask_type
= EXACT
;
3102 } else if (!irccasecmp(argv
[i
], "subset")) {
3103 if (i
== argc
- 1) {
3104 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3107 discrim
->hostmask_type
= SUBSET
;
3108 } else if (!irccasecmp(argv
[i
], "superset")) {
3109 if (i
== argc
- 1) {
3110 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3113 discrim
->hostmask_type
= SUPERSET
;
3114 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3115 if (i
== argc
- 1) {
3116 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3119 discrim
->hostmask_type
= LASTQUIT
;
3122 discrim
->hostmask_type
= SUPERSET
;
3124 discrim
->hostmask
= argv
[++i
];
3125 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3126 if (!irccasecmp(argv
[++i
], "*")) {
3127 discrim
->handlemask
= 0;
3129 discrim
->handlemask
= argv
[i
];
3131 } else if (!irccasecmp(argv
[i
], "email")) {
3132 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3133 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3135 } else if (!irccasecmp(argv
[++i
], "*")) {
3136 discrim
->emailmask
= 0;
3138 discrim
->emailmask
= argv
[i
];
3140 } else if (!irccasecmp(argv
[i
], "access")) {
3141 const char *cmp
= argv
[++i
];
3142 if (cmp
[0] == '<') {
3143 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3144 if (cmp
[1] == '=') {
3145 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3147 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3149 } else if (cmp
[0] == '=') {
3150 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3151 } else if (cmp
[0] == '>') {
3152 if (cmp
[1] == '=') {
3153 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3155 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3158 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3161 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3172 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3174 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3175 || (discrim
->flags_off
& hi
->flags
)
3176 || (discrim
->min_registered
> hi
->registered
)
3177 || (discrim
->max_registered
< hi
->registered
)
3178 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3179 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3180 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3181 || (discrim
->min_level
> hi
->opserv_level
)
3182 || (discrim
->max_level
< hi
->opserv_level
)) {
3185 if (discrim
->hostmask
) {
3187 for (i
=0; i
<hi
->masks
->used
; i
++) {
3188 const char *mask
= hi
->masks
->list
[i
];
3189 if ((discrim
->hostmask_type
== SUBSET
)
3190 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3191 else if ((discrim
->hostmask_type
== EXACT
)
3192 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3193 else if ((discrim
->hostmask_type
== SUPERSET
)
3194 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3195 else if ((discrim
->hostmask_type
== LASTQUIT
)
3196 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3198 if (i
==hi
->masks
->used
) return 0;
3200 if (discrim
->nickmask
) {
3201 struct nick_info
*nick
= hi
->nicks
;
3203 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3206 if (!nick
) return 0;
3212 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3214 dict_iterator_t it
, next
;
3215 unsigned int matched
;
3217 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3218 it
&& (matched
< discrim
->limit
);
3220 next
= iter_next(it
);
3221 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3222 dsf(source
, iter_data(it
));
3230 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3232 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3236 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3241 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3243 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3244 nickserv_unregister_handle(match
, source
);
3248 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3250 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3251 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3252 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3253 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3254 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3258 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3260 struct handle_info_list hil
;
3261 struct helpfile_table tbl
;
3266 memset(&hil
, 0, sizeof(hil
));
3267 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3268 struct handle_info
*hi
= iter_data(it
);
3269 if (hi
->opserv_level
)
3270 handle_info_list_append(&hil
, hi
);
3272 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3273 tbl
.length
= hil
.used
+ 1;
3275 tbl
.flags
= TABLE_NO_FREE
;
3276 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3277 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3280 for (ii
= 0; ii
< hil
.used
; ) {
3281 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3282 ary
[0] = hil
.list
[ii
]->handle
;
3283 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3284 tbl
.contents
[++ii
] = ary
;
3286 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3287 reply("MSG_MATCH_COUNT", hil
.used
);
3288 for (ii
= 0; ii
< hil
.used
; ii
++)
3289 free(tbl
.contents
[ii
]);
3294 static NICKSERV_FUNC(cmd_search
)
3296 struct nickserv_discrim
*discrim
;
3297 discrim_search_func action
;
3298 struct svccmd
*subcmd
;
3299 unsigned int matches
;
3302 NICKSERV_MIN_PARMS(3);
3303 sprintf(buf
, "search %s", argv
[1]);
3304 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3305 if (!irccasecmp(argv
[1], "print"))
3306 action
= search_print_func
;
3307 else if (!irccasecmp(argv
[1], "count"))
3308 action
= search_count_func
;
3309 else if (!irccasecmp(argv
[1], "unregister"))
3310 action
= search_unregister_func
;
3312 reply("NSMSG_INVALID_ACTION", argv
[1]);
3316 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3319 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3323 if (action
== search_print_func
)
3324 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3325 else if (action
== search_count_func
)
3326 discrim
->limit
= INT_MAX
;
3328 matches
= nickserv_discrim_search(discrim
, action
, user
);
3331 reply("MSG_MATCH_COUNT", matches
);
3333 reply("MSG_NO_MATCHES");
3339 static MODCMD_FUNC(cmd_checkpass
)
3341 struct handle_info
*hi
;
3343 NICKSERV_MIN_PARMS(3);
3344 if (!(hi
= get_handle_info(argv
[1]))) {
3345 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3348 if (checkpass(argv
[2], hi
->passwd
))
3349 reply("CHECKPASS_YES");
3351 reply("CHECKPASS_NO");
3357 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3360 struct string_list
*masks
, *slist
;
3361 struct handle_info
*hi
;
3362 struct userNode
*authed_users
;
3363 unsigned long int id
;
3367 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3368 id
= str
? strtoul(str
, NULL
, 0) : 0;
3369 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3371 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3374 if ((hi
= get_handle_info(handle
))) {
3375 authed_users
= hi
->users
;
3377 dict_remove(nickserv_handle_dict
, hi
->handle
);
3379 authed_users
= NULL
;
3381 hi
= register_handle(handle
, str
, id
);
3383 hi
->users
= authed_users
;
3384 while (authed_users
) {
3385 authed_users
->handle_info
= hi
;
3386 authed_users
= authed_users
->next_authed
;
3389 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3390 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3391 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3392 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3393 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3394 hi
->language
= language_find(str
? str
: "C");
3395 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3396 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3397 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3399 hi
->infoline
= strdup(str
);
3400 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3401 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3402 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3403 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3404 /* We want to read the nicks even if disable_nicks is set. This is so
3405 * that we don't lose the nick data entirely. */
3406 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3408 for (ii
=0; ii
<slist
->used
; ii
++)
3409 register_nick(slist
->list
[ii
], hi
);
3411 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3413 for (ii
=0; str
[ii
]; ii
++)
3414 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3416 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3417 hi
->userlist_style
= str
? str
[0] : HI_STYLE_ZOOT
;
3418 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3419 hi
->announcements
= str
? str
[0] : '?';
3420 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3421 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3422 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3423 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3424 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3426 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3428 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3429 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3431 nickserv_set_email_addr(hi
, str
);
3432 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3434 hi
->epithet
= strdup(str
);
3435 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3437 hi
->fakehost
= strdup(str
);
3438 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3440 const char *data
, *type
, *expires
, *cookie_str
;
3441 struct handle_cookie
*cookie
;
3443 cookie
= calloc(1, sizeof(*cookie
));
3444 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3445 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3446 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3447 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3448 if (!type
|| !expires
|| !cookie_str
) {
3449 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3452 if (!irccasecmp(type
, KEY_ACTIVATION
))
3453 cookie
->type
= ACTIVATION
;
3454 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3455 cookie
->type
= PASSWORD_CHANGE
;
3456 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3457 cookie
->type
= EMAIL_CHANGE
;
3458 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3459 cookie
->type
= ALLOWAUTH
;
3461 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3464 cookie
->expires
= strtoul(expires
, NULL
, 0);
3465 if (cookie
->expires
< now
)
3468 cookie
->data
= strdup(data
);
3469 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3473 nickserv_bake_cookie(cookie
);
3475 nickserv_free_cookie(cookie
);
3480 nickserv_saxdb_read(dict_t db
) {
3482 struct record_data
*rd
;
3484 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3486 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3491 static NICKSERV_FUNC(cmd_mergedb
)
3493 struct timeval start
, stop
;
3496 NICKSERV_MIN_PARMS(2);
3497 gettimeofday(&start
, NULL
);
3498 if (!(db
= parse_database(argv
[1]))) {
3499 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3502 nickserv_saxdb_read(db
);
3504 gettimeofday(&stop
, NULL
);
3505 stop
.tv_sec
-= start
.tv_sec
;
3506 stop
.tv_usec
-= start
.tv_usec
;
3507 if (stop
.tv_usec
< 0) {
3509 stop
.tv_usec
+= 1000000;
3511 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3516 expire_handles(UNUSED_ARG(void *data
))
3518 dict_iterator_t it
, next
;
3520 struct handle_info
*hi
;
3522 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3523 next
= iter_next(it
);
3525 if ((hi
->opserv_level
> 0)
3527 || HANDLE_FLAGGED(hi
, FROZEN
)
3528 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3531 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3532 if ((now
- hi
->lastseen
) > expiry
) {
3533 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3534 nickserv_unregister_handle(hi
, NULL
);
3538 if (nickserv_conf
.handle_expire_frequency
)
3539 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3543 nickserv_load_dict(const char *fname
)
3547 if (!(file
= fopen(fname
, "r"))) {
3548 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
3551 while (!feof(file
)) {
3552 fgets(line
, sizeof(line
), file
);
3555 if (line
[strlen(line
)-1] == '\n')
3556 line
[strlen(line
)-1] = 0;
3557 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
3560 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
3563 static enum reclaim_action
3564 reclaim_action_from_string(const char *str
) {
3566 return RECLAIM_NONE
;
3567 else if (!irccasecmp(str
, "warn"))
3568 return RECLAIM_WARN
;
3569 else if (!irccasecmp(str
, "svsnick"))
3570 return RECLAIM_SVSNICK
;
3571 else if (!irccasecmp(str
, "kill"))
3572 return RECLAIM_KILL
;
3574 return RECLAIM_NONE
;
3578 nickserv_conf_read(void)
3580 dict_t conf_node
, child
;
3584 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
3585 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
3588 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
3590 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
3591 if (nickserv_conf
.valid_handle_regex_set
)
3592 regfree(&nickserv_conf
.valid_handle_regex
);
3594 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3595 nickserv_conf
.valid_handle_regex_set
= !err
;
3596 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
3598 nickserv_conf
.valid_handle_regex_set
= 0;
3600 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
3601 if (nickserv_conf
.valid_nick_regex_set
)
3602 regfree(&nickserv_conf
.valid_nick_regex
);
3604 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3605 nickserv_conf
.valid_nick_regex_set
= !err
;
3606 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
3608 nickserv_conf
.valid_nick_regex_set
= 0;
3610 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
3612 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
3613 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
3614 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
3615 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
3616 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
3617 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
3618 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
3619 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
3620 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
3621 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
3622 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
3623 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
3624 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
3625 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
3626 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
3627 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
3628 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
3629 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
3630 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
3631 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
3632 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
3633 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
3634 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
3635 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
3636 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
3638 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
3639 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
3640 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3642 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3643 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
3644 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3646 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3647 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
3648 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
3649 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
3650 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
3651 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
3652 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
3653 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
3654 if (!nickserv_conf
.disable_nicks
) {
3655 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
3656 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3657 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
3658 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
3659 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
3660 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3661 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
3662 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
3664 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
3665 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
3666 const char *key
= iter_key(it
), *value
;
3670 if (!strncasecmp(key
, "uc_", 3))
3671 flag
= toupper(key
[3]);
3672 else if (!strncasecmp(key
, "lc_", 3))
3673 flag
= tolower(key
[3]);
3677 if ((pos
= handle_inverse_flags
[flag
])) {
3678 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
3679 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
3682 if (nickserv_conf
.weak_password_dict
)
3683 dict_delete(nickserv_conf
.weak_password_dict
);
3684 nickserv_conf
.weak_password_dict
= dict_new();
3685 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
3686 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
3687 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
3688 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
3690 nickserv_load_dict(str
);
3691 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
3692 if (nickserv
&& str
)
3693 NickChange(nickserv
, str
, 0);
3694 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
3695 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
3696 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
3697 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
3698 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
3699 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
3700 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
3701 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
3702 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
3703 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
3704 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
3705 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
3706 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
3707 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
3708 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
3709 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
3710 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
3711 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
3712 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
3713 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
3714 str
= conf_get_data("server/network", RECDB_QSTRING
);
3715 nickserv_conf
.network_name
= str
? str
: "some IRC network";
3716 if (!nickserv_conf
.auth_policer_params
) {
3717 nickserv_conf
.auth_policer_params
= policer_params_new();
3718 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
3719 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
3721 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
3722 for (it
=dict_first(child
); it
; it
=iter_next(it
))
3723 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
3727 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
3729 char newnick
[NICKLEN
+1];
3738 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3740 case RECLAIM_SVSNICK
:
3742 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
3743 } while (GetUserH(newnick
));
3744 irc_svsnick(nickserv
, user
, newnick
);
3747 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
3748 irc_kill(nickserv
, user
, msg
);
3754 nickserv_reclaim_p(void *data
) {
3755 struct userNode
*user
= data
;
3756 struct nick_info
*ni
= get_nick_info(user
->nick
);
3758 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3762 check_user_nick(struct userNode
*user
) {
3763 struct nick_info
*ni
;
3764 user
->modes
&= ~FLAGS_REGNICK
;
3765 if (!(ni
= get_nick_info(user
->nick
)))
3767 if (user
->handle_info
== ni
->owner
) {
3768 user
->modes
|= FLAGS_REGNICK
;
3772 if (nickserv_conf
.warn_nick_owned
)
3773 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3774 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
3776 if (nickserv_conf
.auto_reclaim_delay
)
3777 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
3779 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3784 handle_new_user(struct userNode
*user
)
3786 return check_user_nick(user
);
3790 handle_account(struct userNode
*user
, const char *stamp
)
3792 struct handle_info
*hi
;
3795 #ifdef WITH_PROTOCOL_P10
3796 time_t timestamp
= 0;
3798 colon
= strchr(stamp
, ':');
3799 if(colon
&& colon
[1])
3802 timestamp
= atoi(colon
+1);
3804 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
3805 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
3807 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
);
3811 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
3812 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
3816 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
3819 set_user_handle_info(user
, hi
, 0);
3821 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
3826 handle_nick_change(struct userNode
*user
, const char *old_nick
)
3828 struct handle_info
*hi
;
3830 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
3831 dict_remove(nickserv_allow_auth_dict
, old_nick
);
3832 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
3834 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3835 check_user_nick(user
);
3839 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
3841 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
3842 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3843 set_user_handle_info(user
, NULL
, 0);
3846 static struct modcmd
*
3847 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
3849 if (min_level
> 0) {
3851 sprintf(buf
, "%u", min_level
);
3852 if (must_be_qualified
) {
3853 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
3855 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
3857 } else if (min_level
== 0) {
3858 if (must_be_qualified
) {
3859 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3861 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3864 if (must_be_qualified
) {
3865 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
3867 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
3873 nickserv_db_cleanup(void)
3875 unreg_del_user_func(nickserv_remove_user
);
3876 userList_clean(&curr_helpers
);
3877 policer_params_delete(nickserv_conf
.auth_policer_params
);
3878 dict_delete(nickserv_handle_dict
);
3879 dict_delete(nickserv_nick_dict
);
3880 dict_delete(nickserv_opt_dict
);
3881 dict_delete(nickserv_allow_auth_dict
);
3882 dict_delete(nickserv_email_dict
);
3883 dict_delete(nickserv_id_dict
);
3884 dict_delete(nickserv_conf
.weak_password_dict
);
3885 free(auth_func_list
);
3886 free(unreg_func_list
);
3888 free(allowauth_func_list
);
3889 free(handle_merge_func_list
);
3890 free(failpw_func_list
);
3891 if (nickserv_conf
.valid_handle_regex_set
)
3892 regfree(&nickserv_conf
.valid_handle_regex
);
3893 if (nickserv_conf
.valid_nick_regex_set
)
3894 regfree(&nickserv_conf
.valid_nick_regex
);
3898 init_nickserv(const char *nick
)
3901 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
3902 reg_new_user_func(handle_new_user
);
3903 reg_nick_change_func(handle_nick_change
);
3904 reg_del_user_func(nickserv_remove_user
);
3905 reg_account_func(handle_account
);
3907 /* set up handle_inverse_flags */
3908 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
3909 for (i
=0; handle_flags
[i
]; i
++) {
3910 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
3911 flag_access_levels
[i
] = 0;
3914 conf_register_reload(nickserv_conf_read
);
3915 nickserv_opt_dict
= dict_new();
3916 nickserv_email_dict
= dict_new();
3917 dict_set_free_keys(nickserv_email_dict
, free
);
3918 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
3920 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
3921 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
3922 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
3923 * a big pain to disable since its nolonger in the config file. ) -Rubin
3925 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
3926 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
3927 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
3928 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
3929 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
3930 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
3931 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
3932 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
3933 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
3934 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
3935 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
3936 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
3937 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
3938 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
3939 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
3940 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
3941 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
3942 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
3943 if (!nickserv_conf
.disable_nicks
) {
3944 /* nick management commands */
3945 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
3946 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
3947 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
3948 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
3949 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
3950 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
3952 if (nickserv_conf
.email_enabled
) {
3953 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
3954 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
3955 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
3956 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
3957 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
3959 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
3960 /* miscellaneous commands */
3961 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
3962 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
3963 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
3964 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
3965 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
3967 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
3968 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
3969 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
3970 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
3971 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
3972 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
3973 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
3974 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
3975 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
3976 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
3977 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
3978 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
3979 if (nickserv_conf
.titlehost_suffix
) {
3980 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
3981 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
3983 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
3984 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
3985 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
3987 nickserv_handle_dict
= dict_new();
3988 dict_set_free_keys(nickserv_handle_dict
, free
);
3989 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
3991 nickserv_id_dict
= dict_new();
3992 dict_set_free_keys(nickserv_id_dict
, free
);
3994 nickserv_nick_dict
= dict_new();
3995 dict_set_free_data(nickserv_nick_dict
, free
);
3997 nickserv_allow_auth_dict
= dict_new();
3999 userList_init(&curr_helpers
);
4002 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4003 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4004 nickserv_service
= service_register(nickserv
);
4006 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4007 reg_exit_func(nickserv_db_cleanup
);
4008 if(nickserv_conf
.handle_expire_frequency
)
4009 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4010 message_register_table(msgtab
);