1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of srvx.
6 * srvx is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 #include "opserv.h" /* for gag_create(), opserv_bad_channel() */
34 #define NICKSERV_CONF_NAME "services/nickserv"
36 #define KEY_DISABLE_NICKS "disable_nicks"
37 #define KEY_DEFAULT_HOSTMASK "default_hostmask"
38 #define KEY_NICKS_PER_HANDLE "nicks_per_handle"
39 #define KEY_NICKS_PER_ACCOUNT "nicks_per_account"
40 #define KEY_PASSWORD_MIN_LENGTH "password_min_length"
41 #define KEY_PASSWORD_MIN_DIGITS "password_min_digits"
42 #define KEY_PASSWORD_MIN_UPPER "password_min_upper"
43 #define KEY_PASSWORD_MIN_LOWER "password_min_lower"
44 #define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
45 #define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
46 #define KEY_VALID_NICK_REGEX "valid_nick_regex"
47 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
48 #define KEY_MODOPER_LEVEL "modoper_level"
49 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
50 #define KEY_SET_TITLE_LEVEL "set_title_level"
51 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
52 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
53 #define KEY_FLAG_LEVELS "flag_levels"
54 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
55 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
56 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
57 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
58 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
59 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
60 #define KEY_DICT_FILE "dict_file"
61 #define KEY_NICK "nick"
62 #define KEY_LANGUAGE "language"
63 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
64 #define KEY_AUTOGAG_DURATION "autogag_duration"
65 #define KEY_AUTH_POLICER "auth_policer"
66 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
67 #define KEY_EMAIL_ENABLED "email_enabled"
68 #define KEY_EMAIL_REQUIRED "email_required"
69 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
70 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
71 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
74 #define KEY_PASSWD "passwd"
75 #define KEY_NICKS "nicks"
76 #define KEY_MASKS "masks"
77 #define KEY_OPSERV_LEVEL "opserv_level"
78 #define KEY_FLAGS "flags"
79 #define KEY_REGISTER_ON "register"
80 #define KEY_LAST_SEEN "lastseen"
81 #define KEY_INFO "info"
82 #define KEY_USERLIST_STYLE "user_style"
83 #define KEY_SCREEN_WIDTH "screen_width"
84 #define KEY_LAST_AUTHED_HOST "last_authed_host"
85 #define KEY_LAST_QUIT_HOST "last_quit_host"
86 #define KEY_EMAIL_ADDR "email_addr"
87 #define KEY_COOKIE "cookie"
88 #define KEY_COOKIE_DATA "data"
89 #define KEY_COOKIE_TYPE "type"
90 #define KEY_COOKIE_EXPIRES "expires"
91 #define KEY_ACTIVATION "activation"
92 #define KEY_PASSWORD_CHANGE "password change"
93 #define KEY_EMAIL_CHANGE "email change"
94 #define KEY_ALLOWAUTH "allowauth"
95 #define KEY_EPITHET "epithet"
96 #define KEY_TABLE_WIDTH "table_width"
97 #define KEY_ANNOUNCEMENTS "announcements"
98 #define KEY_MAXLOGINS "maxlogins"
99 #define KEY_FAKEHOST "fakehost"
101 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
103 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
104 #define OPTION_FUNC(NAME) int NAME(struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
105 typedef OPTION_FUNC(option_func_t
);
107 DEFINE_LIST(handle_info_list
, struct handle_info
*);
109 #define NICKSERV_MIN_PARMS(N) do { \
111 reply("MSG_MISSING_PARAMS", argv[0]); \
112 svccmd_send_help(user, nickserv, cmd); \
116 struct userNode
*nickserv
;
117 struct userList curr_helpers
;
118 const char *handle_flags
= HANDLE_FLAGS
;
120 static struct module *nickserv_module
;
121 static struct service
*nickserv_service
;
122 static struct log_type
*NS_LOG
;
123 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
124 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
125 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
126 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
127 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
128 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
129 static char handle_inverse_flags
[256];
130 static unsigned int flag_access_levels
[32];
131 static const struct message_entry msgtab
[] = {
132 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
133 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu charactors or less."},
134 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
135 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
136 { "NSMSG_PASSWORD_DICTIONARY", "Your password should not be the word \"password\", or any other dictionary word." },
137 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
138 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
139 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
140 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
141 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
142 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
143 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
144 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
145 { "NSMSG_USE_COOKIE_REGISTER", "To activate your account, you must check your email for the \"cookie\" that has been mailed to it. When you have it, use the $bcookie$b command to complete registration." },
146 { "NSMSG_USE_COOKIE_RESETPASS", "A cookie has been mailed to your account's email address. You must check your email and use the $bcookie$b command to confirm the password change." },
147 { "NSMSG_USE_COOKIE_EMAIL_1", "A cookie has been mailed to the new address you requested. To finish setting your email address, please check your email for the cookie and use the $bcookie$b command to verify." },
148 { "NSMSG_USE_COOKIE_EMAIL_2", "A cookie has been generated, and half mailed to each your old and new addresses. To finish changing your email address, please check your email for the cookie and use the $bcookie$b command to verify." },
149 { "NSMSG_USE_COOKIE_AUTH", "A cookie has been generated and sent to your email address. Once you have checked your email and received the cookie, auth using the $bcookie$b command." },
150 { "NSMSG_COOKIE_LIVE", "Account $b%s$b already has a cookie active. Please either finish using that cookie, wait for it to expire, or auth to the account and use the $bdelcookie$b command." },
151 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
152 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
153 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
154 { "NSMSG_BAD_COOKIE", "That cookie is not the right one. Please make sure you are copying it EXACTLY from the email; it is case-sensitive, so $bABC$b is different from $babc$b." },
155 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
156 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
157 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
158 { "NSMSG_EMAIL_OVERUSED", "There are already the maximum number of accounts associated with that email address." },
159 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
160 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
161 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
162 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
163 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
164 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
165 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
166 { "NSMSG_REGISTER_BAD_NICKMASK", "Could not recognize $b%s$b as either a current nick or a hostmask." },
167 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
168 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
169 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
170 { "NSMSG_USE_AUTHCOOKIE", "Your hostmask is not valid for account $b%1$s$b. Please use the $bauthcookie$b command to grant yourself access. (/msg $S authcookie %1$s)" },
171 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
172 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
173 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
174 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
175 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
176 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
177 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
178 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
179 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
180 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
181 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
182 { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
183 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
184 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
185 { "NSMSG_HANDLEINFO_ON", "Account information for $b%s$b:" },
186 { "NSMSG_HANDLEINFO_ID", " Account ID: %lu" },
187 { "NSMSG_HANDLEINFO_REGGED", " Registered on: %s" },
188 { "NSMSG_HANDLEINFO_LASTSEEN", " Last seen: %s" },
189 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", " Last seen: Right now!" },
190 { "NSMSG_HANDLEINFO_VACATION", " On vacation." },
191 { "NSMSG_HANDLEINFO_EMAIL_ADDR", " Email address: %s" },
192 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", " Cookie: There is currently an activation cookie issued for this account" },
193 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", " Cookie: There is currently a password change cookie issued for this account" },
194 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", " Cookie: There is currently an email change cookie issued for this account" },
195 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", " Cookie: There is currently an allowauth cookie issued for this account" },
196 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", " Cookie: There is currently an unknown cookie issued for this account" },
197 { "NSMSG_HANDLEINFO_INFOLINE", " Infoline: %s" },
198 { "NSMSG_HANDLEINFO_FLAGS", " Flags: %s" },
199 { "NSMSG_HANDLEINFO_EPITHET", " Epithet: %s" },
200 { "NSMSG_HANDLEINFO_FAKEHOST", " Fake host: %s" },
201 { "NSMSG_HANDLEINFO_LAST_HOST", " Last quit hostmask: %s" },
202 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", " Last quit hostmask: Unknown" },
203 { "NSMSG_HANDLEINFO_NICKS", " Nickname(s): %s" },
204 { "NSMSG_HANDLEINFO_MASKS", " Hostmask(s): %s" },
205 { "NSMSG_HANDLEINFO_CHANNELS", " Channel(s): %s" },
206 { "NSMSG_HANDLEINFO_CURRENT", " Current nickname(s): %s" },
207 { "NSMSG_HANDLEINFO_DNR", " Do-not-register (by %s): %s" },
208 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
209 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
210 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
211 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
212 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
213 { "NSMSG_WEAK_PASSWORD", "WARNING: You are using a password that is considered weak (easy to guess). It is STRONGLY recommended you change it (now, if not sooner) by typing \"/msg $S@$s PASS oldpass newpass\" (with your current password and a new password)." },
214 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
215 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
216 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
217 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
218 { "NSMSG_AUTH_ALLOWED_MSG", "You may now authenticate to account $b%s$b by typing $b/msg $N@$s auth %s password$b (using your password). If you will be using this computer regularly, please type $b/msg $N addmask$b (AFTER you auth) to permanently add your hostmask." },
219 { "NSMSG_AUTH_ALLOWED_EMAIL", "You may also (after you auth) type $b/msg $N set email user@your.isp$b to set an email address. This will let you use the $bauthcookie$b command to be authenticated in the future." },
220 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
221 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
222 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
223 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
224 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
225 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
226 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
227 { "NSMSG_PASS_SUCCESS", "Password changed." },
228 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
229 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
230 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
231 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
232 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
233 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
234 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
235 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
236 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
237 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
238 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
239 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
240 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
241 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
242 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
243 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
244 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
245 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
246 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
247 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
248 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
249 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
250 { "NSMSG_NO_ACCESS", "Access denied." },
251 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
252 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
253 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
254 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
255 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
256 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
257 { "NSMSG_BAD_HANDLE", "Account $b%s$b not registered because it is in use by a network service, is too long, or contains invalid characters." },
258 { "NSMSG_BAD_NICK", "Nickname $b%s$b not registered because it is in use by a network service, is too long, or contains invalid characters." },
259 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
260 { "NSMSG_FAIL_RENAME", "Account $b%s$b not renamed to $b%s$b because it is in use by a network services, or contains invalid characters." },
261 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
262 { "NSMSG_SEARCH_MATCH", "Match: %s" },
263 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
264 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
265 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
266 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
267 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
268 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
269 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
270 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
271 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
272 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
273 { "NSMSG_SETTING_LIST", "$b$N account settings:$b" },
274 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
275 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
276 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
277 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
278 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
279 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
280 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
281 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
282 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
283 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
284 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
285 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
286 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
287 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
288 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
289 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
290 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
291 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
292 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
293 { "NSEMAIL_ACTIVATION_BODY", "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 %2$s\nTo verify your email address and complete the account registration, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nThis 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 /msg %3$s@%4$s AUTH %5$s your-password\n Please remember to fill in 'your-password' with the actual password you gave to us when you registered.\n\nIf you did NOT request this account, you do not need to do anything. Please contact the %1$s staff if you have questions, and be sure to check our website." },
294 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
295 { "NSEMAIL_PASSWORD_CHANGE_BODY", "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\nTo complete the password change, 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 your password to be changed, you do not need to do anything. Please contact the %1$s staff if you have questions." },
296 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
297 { "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." },
298 { "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." },
299 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
300 { "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." },
301 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
302 { "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." },
303 { "CHECKPASS_YES", "Yes." },
304 { "CHECKPASS_NO", "No." },
308 enum reclaim_action
{
314 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
315 static void nickserv_reclaim_p(void *data
);
318 unsigned int disable_nicks
: 1;
319 unsigned int valid_handle_regex_set
: 1;
320 unsigned int valid_nick_regex_set
: 1;
321 unsigned int autogag_enabled
: 1;
322 unsigned int email_enabled
: 1;
323 unsigned int email_required
: 1;
324 unsigned int default_hostmask
: 1;
325 unsigned int warn_nick_owned
: 1;
326 unsigned int warn_clone_auth
: 1;
327 unsigned long nicks_per_handle
;
328 unsigned long password_min_length
;
329 unsigned long password_min_digits
;
330 unsigned long password_min_upper
;
331 unsigned long password_min_lower
;
332 unsigned long db_backup_frequency
;
333 unsigned long handle_expire_frequency
;
334 unsigned long autogag_duration
;
335 unsigned long email_visible_level
;
336 unsigned long cookie_timeout
;
337 unsigned long handle_expire_delay
;
338 unsigned long nochan_handle_expire_delay
;
339 unsigned long modoper_level
;
340 unsigned long set_epithet_level
;
341 unsigned long set_title_level
;
342 unsigned long set_fakehost_level
;
343 unsigned long handles_per_email
;
344 unsigned long email_search_level
;
345 const char *network_name
;
346 const char *titlehost_suffix
;
347 regex_t valid_handle_regex
;
348 regex_t valid_nick_regex
;
349 dict_t weak_password_dict
;
350 struct policer_params
*auth_policer_params
;
351 enum reclaim_action reclaim_action
;
352 enum reclaim_action auto_reclaim_action
;
353 unsigned long auto_reclaim_delay
;
354 unsigned char default_maxlogins
;
355 unsigned char hard_maxlogins
;
358 /* We have 2^32 unique account IDs to use. */
359 unsigned long int highest_id
= 0;
362 canonicalize_hostmask(char *mask
)
364 char *out
= mask
, *temp
;
365 if ((temp
= strchr(mask
, '!'))) {
367 while (*temp
) *out
++ = *temp
++;
373 static struct handle_info
*
374 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
376 struct handle_info
*hi
;
378 #ifdef WITH_PROTOCOL_BAHAMUT
379 char id_base64
[IDLEN
+ 1];
382 /* Assign a unique account ID to the account; note that 0 is
383 an invalid account ID. 1 is therefore the first account ID. */
385 id
= 1 + highest_id
++;
387 /* Note: highest_id is and must always be the highest ID. */
388 if(id
> highest_id
) {
392 inttobase64(id_base64
, id
, IDLEN
);
394 /* Make sure an account with the same ID doesn't exist. If a
395 duplicate is found, log some details and assign a new one.
396 This should be impossible, but it never hurts to expect it. */
397 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
398 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
404 hi
= calloc(1, sizeof(*hi
));
405 hi
->userlist_style
= HI_DEFAULT_STYLE
;
406 hi
->announcements
= '?';
407 hi
->handle
= strdup(handle
);
408 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
410 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
412 #ifdef WITH_PROTOCOL_BAHAMUT
414 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
421 register_nick(const char *nick
, struct handle_info
*owner
)
423 struct nick_info
*ni
;
424 ni
= malloc(sizeof(struct nick_info
));
425 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
427 ni
->next
= owner
->nicks
;
429 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
433 delete_nick(struct nick_info
*ni
)
435 struct nick_info
*last
, *next
;
436 struct userNode
*user
;
437 /* Check to see if we should mark a user as unregistered. */
438 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
439 user
->modes
&= ~FLAGS_REGNICK
;
442 /* Remove ni from the nick_info linked list. */
443 if (ni
== ni
->owner
->nicks
) {
444 ni
->owner
->nicks
= ni
->next
;
446 last
= ni
->owner
->nicks
;
452 last
->next
= next
->next
;
454 dict_remove(nickserv_nick_dict
, ni
->nick
);
457 static unreg_func_t
*unreg_func_list
;
458 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
461 reg_unreg_func(unreg_func_t func
)
463 if (unreg_func_used
== unreg_func_size
) {
464 if (unreg_func_size
) {
465 unreg_func_size
<<= 1;
466 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
469 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
472 unreg_func_list
[unreg_func_used
++] = func
;
476 nickserv_free_cookie(void *data
)
478 struct handle_cookie
*cookie
= data
;
479 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
480 if (cookie
->data
) free(cookie
->data
);
485 free_handle_info(void *vhi
)
487 struct handle_info
*hi
= vhi
;
489 #ifdef WITH_PROTOCOL_BAHAMUT
492 inttobase64(id
, hi
->id
, IDLEN
);
493 dict_remove(nickserv_id_dict
, id
);
496 free_string_list(hi
->masks
);
500 delete_nick(hi
->nicks
);
505 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
506 nickserv_free_cookie(hi
->cookie
);
508 if (hi
->email_addr
) {
509 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
510 handle_info_list_remove(hil
, hi
);
512 dict_remove(nickserv_email_dict
, hi
->email_addr
);
517 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
520 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
)
524 for (n
=0; n
<unreg_func_used
; n
++)
525 unreg_func_list
[n
](notify
, hi
);
527 set_user_handle_info(hi
->users
, NULL
, 0);
529 if (nickserv_conf
.disable_nicks
)
530 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
532 send_message(notify
, nickserv
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
534 dict_remove(nickserv_handle_dict
, hi
->handle
);
538 get_handle_info(const char *handle
)
540 return dict_find(nickserv_handle_dict
, handle
, 0);
544 get_nick_info(const char *nick
)
546 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
550 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
555 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
556 mn
= channel
->members
.list
[nn
];
557 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
564 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
565 if (!user
->handle_info
) {
567 send_message(user
, bot
, "MSG_AUTHENTICATE");
571 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
573 send_message(user
, bot
, "NSMSG_NO_ACCESS");
577 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
579 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
583 if (user
->handle_info
->opserv_level
< min_level
) {
585 send_message(user
, bot
, "NSMSG_NO_ACCESS");
593 is_valid_handle(const char *handle
)
595 struct userNode
*user
;
596 /* cant register a juped nick/service nick as handle, to prevent confusion */
597 user
= GetUserH(handle
);
598 if (user
&& IsLocal(user
))
600 /* check against maximum length */
601 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
603 /* for consistency, only allow account names that could be nicks */
604 if (!is_valid_nick(handle
))
606 /* disallow account names that look like bad words */
607 if (opserv_bad_channel(handle
))
609 /* test either regex or containing all valid chars */
610 if (nickserv_conf
.valid_handle_regex_set
) {
611 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
614 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
615 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
619 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
624 is_registerable_nick(const char *nick
)
626 /* make sure it could be used as an account name */
627 if (!is_valid_handle(nick
))
630 if (strlen(nick
) > NICKLEN
)
632 /* test either regex or as valid handle */
633 if (nickserv_conf
.valid_nick_regex_set
) {
634 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
637 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
638 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
646 is_valid_email_addr(const char *email
)
648 return strchr(email
, '@') != NULL
;
652 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
654 if (hi
->email_addr
) {
655 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
656 return hi
->email_addr
;
666 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
668 struct handle_info
*hi
;
669 struct userNode
*target
;
673 if (!(hi
= get_handle_info(++name
))) {
674 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
679 if (!(target
= GetUserH(name
))) {
680 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
683 if (IsLocal(target
)) {
684 if (IsService(target
))
685 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
687 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
690 if (!(hi
= target
->handle_info
)) {
691 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
699 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
700 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
702 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
703 if ((user
->handle_info
->opserv_level
== 1000)
704 || (user
->handle_info
== hi
)
705 || ((user
->handle_info
->opserv_level
== 0)
706 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
707 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
711 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
715 static struct handle_info
*
716 get_victim_oper(struct userNode
*user
, const char *target
)
718 struct handle_info
*hi
;
719 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
721 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
722 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
725 return oper_outranks(user
, hi
) ? hi
: NULL
;
729 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
733 /* If no hostmasks on the account, allow it. */
734 if (!hi
->masks
->used
)
736 /* If any hostmask matches, allow it. */
737 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
738 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
740 /* If they are allowauthed to this account, allow it (removing the aa). */
741 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
742 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
745 /* The user is not allowed to use this account. */
750 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
753 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
755 if (len
< nickserv_conf
.password_min_length
) {
757 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
760 if (!irccasecmp(pass
, handle
)) {
762 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
765 dict_find(nickserv_conf
.weak_password_dict
, pass
, &i
);
768 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
771 for (i
=0; i
<len
; i
++) {
772 if (isdigit(pass
[i
]))
774 if (isupper(pass
[i
]))
776 if (islower(pass
[i
]))
779 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
780 || (cnt_upper
< nickserv_conf
.password_min_upper
)
781 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
783 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
789 static auth_func_t
*auth_func_list
;
790 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
793 reg_auth_func(auth_func_t func
)
795 if (auth_func_used
== auth_func_size
) {
796 if (auth_func_size
) {
797 auth_func_size
<<= 1;
798 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
801 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
804 auth_func_list
[auth_func_used
++] = func
;
807 static handle_rename_func_t
*rf_list
;
808 static unsigned int rf_list_size
, rf_list_used
;
811 reg_handle_rename_func(handle_rename_func_t func
)
813 if (rf_list_used
== rf_list_size
) {
816 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
819 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
822 rf_list
[rf_list_used
++] = func
;
826 generate_fakehost(struct handle_info
*handle
)
828 extern const char *hidden_host_suffix
;
829 static char buffer
[HOSTLEN
+1];
831 if (!handle
->fakehost
) {
832 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
834 } else if (handle
->fakehost
[0] == '.') {
835 /* A leading dot indicates the stored value is actually a title. */
836 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
839 return handle
->fakehost
;
843 apply_fakehost(struct handle_info
*handle
)
845 struct userNode
*target
;
850 fake
= generate_fakehost(handle
);
851 for (target
= handle
->users
; target
; target
= target
->next_authed
)
852 assign_fakehost(target
, fake
, 1);
856 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
859 struct handle_info
*old_info
;
861 /* This can happen if somebody uses COOKIE while authed, or if
862 * they re-auth to their current handle (which is silly, but users
864 if (user
->handle_info
== hi
)
867 if (user
->handle_info
) {
868 struct userNode
*other
;
871 userList_remove(&curr_helpers
, user
);
873 /* remove from next_authed linked list */
874 if (user
->handle_info
->users
== user
) {
875 user
->handle_info
->users
= user
->next_authed
;
877 for (other
= user
->handle_info
->users
;
878 other
->next_authed
!= user
;
879 other
= other
->next_authed
) ;
880 other
->next_authed
= user
->next_authed
;
882 /* if nobody left on old handle, and they're not an oper, remove !god */
883 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
884 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
885 /* record them as being last seen at this time */
886 user
->handle_info
->lastseen
= now
;
887 /* and record their hostmask */
888 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
890 old_info
= user
->handle_info
;
891 user
->handle_info
= hi
;
892 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
893 HANDLE_CLEAR_FLAG(hi
, HELPING
);
894 for (n
=0; n
<auth_func_used
; n
++)
895 auth_func_list
[n
](user
, old_info
);
897 struct nick_info
*ni
;
899 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
900 if (nickserv_conf
.warn_clone_auth
) {
901 struct userNode
*other
;
902 for (other
= hi
->users
; other
; other
= other
->next_authed
)
903 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
905 user
->next_authed
= hi
->users
;
909 userList_append(&curr_helpers
, user
);
911 if (hi
->fakehost
|| old_info
)
915 #ifdef WITH_PROTOCOL_BAHAMUT
916 /* Stamp users with their account ID. */
918 inttobase64(id
, hi
->id
, IDLEN
);
919 #elif WITH_PROTOCOL_P10
920 /* Stamp users with their account name. */
921 char *id
= hi
->handle
;
923 const char *id
= "???";
925 if (!nickserv_conf
.disable_nicks
) {
926 struct nick_info
*ni
;
927 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
928 if (!irccasecmp(user
->nick
, ni
->nick
)) {
929 user
->modes
|= FLAGS_REGNICK
;
937 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
938 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
940 /* We cannot clear the user's account ID, unfortunately. */
941 user
->next_authed
= NULL
;
945 static struct handle_info
*
946 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
948 struct handle_info
*hi
;
949 struct nick_info
*ni
;
950 char crypted
[MD5_CRYPT_LENGTH
];
952 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
953 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
957 if(strlen(handle
) > 15)
959 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
963 if (!is_secure_password(handle
, passwd
, user
))
966 cryptpass(passwd
, crypted
);
967 hi
= register_handle(handle
, crypted
, 0);
968 hi
->masks
= alloc_string_list(1);
970 hi
->language
= lang_C
;
971 hi
->registered
= now
;
973 hi
->flags
= HI_DEFAULT_FLAGS
;
974 if (settee
&& !no_auth
)
975 set_user_handle_info(settee
, hi
, 1);
978 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
979 else if (nickserv_conf
.disable_nicks
)
980 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
981 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
982 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
984 register_nick(user
->nick
, hi
);
985 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
987 if (settee
&& (user
!= settee
))
988 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
993 nickserv_bake_cookie(struct handle_cookie
*cookie
)
995 cookie
->hi
->cookie
= cookie
;
996 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1000 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
)
1002 struct handle_cookie
*cookie
;
1003 char subject
[128], body
[4096], *misc
;
1004 const char *netname
, *fmt
;
1008 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1012 cookie
= calloc(1, sizeof(*cookie
));
1014 cookie
->type
= type
;
1015 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1016 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1017 inttobase64(cookie
->cookie
, rand(), 5);
1018 inttobase64(cookie
->cookie
+5, rand(), 5);
1020 netname
= nickserv_conf
.network_name
;
1023 switch (cookie
->type
) {
1025 hi
->passwd
[0] = 0; /* invalidate password */
1026 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1027 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1028 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1029 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1030 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1033 case PASSWORD_CHANGE
:
1034 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1035 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1036 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1037 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1038 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1041 misc
= hi
->email_addr
;
1042 hi
->email_addr
= cookie
->data
;
1044 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1045 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1046 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1047 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1048 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1049 sendmail(nickserv
, hi
, subject
, body
, 1);
1050 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1051 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1053 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1054 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1055 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1056 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1057 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1058 sendmail(nickserv
, hi
, subject
, body
, 1);
1061 hi
->email_addr
= misc
;
1064 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1065 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1066 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1067 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1068 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1071 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1075 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1076 nickserv_bake_cookie(cookie
);
1080 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1082 cookie
->hi
->cookie
= NULL
;
1083 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1084 nickserv_free_cookie(cookie
);
1088 nickserv_free_email_addr(void *data
)
1090 handle_info_list_clean(data
);
1095 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1097 struct handle_info_list
*hil
;
1098 /* Remove from old handle_info_list ... */
1099 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1100 handle_info_list_remove(hil
, hi
);
1101 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1102 hi
->email_addr
= NULL
;
1104 /* Add to the new list.. */
1105 if (new_email_addr
) {
1106 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1107 hil
= calloc(1, sizeof(*hil
));
1108 hil
->tag
= strdup(new_email_addr
);
1109 handle_info_list_init(hil
);
1110 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1112 handle_info_list_append(hil
, hi
);
1113 hi
->email_addr
= hil
->tag
;
1117 static NICKSERV_FUNC(cmd_register
)
1119 struct handle_info
*hi
;
1120 const char *email_addr
, *password
;
1123 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1124 /* Require the first handle registered to belong to someone +o. */
1125 reply("NSMSG_REQUIRE_OPER");
1129 if (user
->handle_info
) {
1130 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1134 if (IsRegistering(user
)) {
1135 reply("NSMSG_ALREADY_REGISTERING");
1139 if (IsStamped(user
)) {
1140 /* Unauthenticated users might still have been stamped
1141 previously and could therefore have a hidden host;
1142 do not allow them to register a new account. */
1143 reply("NSMSG_STAMPED_REGISTER");
1147 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1149 if (!is_valid_handle(argv
[1])) {
1150 reply("NSMSG_BAD_HANDLE", argv
[1]);
1154 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1155 struct handle_info_list
*hil
;
1158 /* Remember email address. */
1159 email_addr
= argv
[3];
1161 /* Check that the email address looks valid.. */
1162 if (!is_valid_email_addr(email_addr
)) {
1163 reply("NSMSG_BAD_EMAIL_ADDR");
1167 /* .. and that we are allowed to send to it. */
1168 if ((str
= sendmail_prohibited_address(email_addr
))) {
1169 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1173 /* If we do email verify, make sure we don't spam the address. */
1174 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1176 for (nn
=0; nn
<hil
->used
; nn
++) {
1177 if (hil
->list
[nn
]->cookie
) {
1178 reply("NSMSG_EMAIL_UNACTIVATED");
1182 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1183 reply("NSMSG_EMAIL_OVERUSED");
1196 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1198 /* Add any masks they should get. */
1199 if (nickserv_conf
.default_hostmask
) {
1200 string_list_append(hi
->masks
, strdup("*@*"));
1202 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1203 if (user
->ip
.s_addr
&& user
->hostname
[strspn(user
->hostname
, "0123456789.")])
1204 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1207 /* If they're the first to register, give them level 1000. */
1208 if (dict_size(nickserv_handle_dict
) == 1) {
1209 hi
->opserv_level
= 1000;
1210 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1213 /* Set their email address. */
1215 nickserv_set_email_addr(hi
, email_addr
);
1217 /* If they need to do email verification, tell them. */
1219 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
);
1221 /* Set registering flag.. */
1222 user
->modes
|= FLAGS_REGISTERING
;
1227 static NICKSERV_FUNC(cmd_oregister
)
1230 struct userNode
*settee
;
1231 struct handle_info
*hi
;
1233 NICKSERV_MIN_PARMS(4);
1235 if (!is_valid_handle(argv
[1])) {
1236 reply("NSMSG_BAD_HANDLE", argv
[1]);
1240 if (strchr(argv
[3], '@')) {
1241 mask
= canonicalize_hostmask(strdup(argv
[3]));
1243 settee
= GetUserH(argv
[4]);
1245 reply("MSG_NICK_UNKNOWN", argv
[4]);
1252 } else if ((settee
= GetUserH(argv
[3]))) {
1253 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1255 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1258 if (settee
&& settee
->handle_info
) {
1259 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1263 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1267 string_list_append(hi
->masks
, mask
);
1271 static NICKSERV_FUNC(cmd_handleinfo
)
1274 unsigned int i
, pos
=0, herelen
;
1275 struct userNode
*target
, *next_un
;
1276 struct handle_info
*hi
;
1277 const char *nsmsg_none
;
1280 if (!(hi
= user
->handle_info
)) {
1281 reply("NSMSG_MUST_AUTH");
1284 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1288 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1289 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1290 #ifdef WITH_PROTOCOL_BAHAMUT
1291 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1293 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1296 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1297 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1299 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1302 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1303 if (HANDLE_FLAGGED(hi
, FROZEN
))
1304 reply("NSMSG_HANDLEINFO_VACATION");
1306 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1307 struct do_not_register
*dnr
;
1308 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1309 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1310 if (!oper_outranks(user
, hi
))
1312 } else if (hi
!= user
->handle_info
)
1315 if (nickserv_conf
.email_enabled
)
1316 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1320 switch (hi
->cookie
->type
) {
1321 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1322 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1323 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1324 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1325 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1331 unsigned long flen
= 1;
1332 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1334 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1335 if (hi
->flags
& 1 << i
)
1336 flags
[flen
++] = handle_flags
[i
];
1338 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1340 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1343 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1344 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1345 || (hi
->opserv_level
> 0)) {
1346 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1350 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1352 if (hi
->last_quit_host
[0])
1353 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1355 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1357 if (nickserv_conf
.disable_nicks
) {
1358 /* nicks disabled; don't show anything about registered nicks */
1359 } else if (hi
->nicks
) {
1360 struct nick_info
*ni
, *next_ni
;
1361 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1362 herelen
= strlen(ni
->nick
);
1363 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1365 goto print_nicks_buff
;
1369 memcpy(buff
+pos
, ni
->nick
, herelen
);
1370 pos
+= herelen
; buff
[pos
++] = ' ';
1374 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1379 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1382 if (hi
->masks
->used
) {
1383 for (i
=0; i
< hi
->masks
->used
; i
++) {
1384 herelen
= strlen(hi
->masks
->list
[i
]);
1385 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1387 goto print_mask_buff
;
1389 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1390 pos
+= herelen
; buff
[pos
++] = ' ';
1391 if (i
+1 == hi
->masks
->used
) {
1394 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1399 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1403 struct userData
*channel
, *next
;
1406 for (channel
= hi
->channels
; channel
; channel
= next
) {
1407 next
= channel
->u_next
;
1408 name
= channel
->channel
->channel
->name
;
1409 herelen
= strlen(name
);
1410 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1412 goto print_chans_buff
;
1414 if (IsUserSuspended(channel
))
1416 pos
+= sprintf(buff
+pos
, "%d:%s ", channel
->access
, name
);
1420 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1425 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1428 for (target
= hi
->users
; target
; target
= next_un
) {
1429 herelen
= strlen(target
->nick
);
1430 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1432 goto print_cnick_buff
;
1434 next_un
= target
->next_authed
;
1436 memcpy(buff
+pos
, target
->nick
, herelen
);
1437 pos
+= herelen
; buff
[pos
++] = ' ';
1441 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1449 static NICKSERV_FUNC(cmd_userinfo
)
1451 struct userNode
*target
;
1453 NICKSERV_MIN_PARMS(2);
1454 if (!(target
= GetUserH(argv
[1]))) {
1455 reply("MSG_NICK_UNKNOWN", argv
[1]);
1458 if (target
->handle_info
)
1459 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1461 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1465 static NICKSERV_FUNC(cmd_nickinfo
)
1467 struct nick_info
*ni
;
1469 NICKSERV_MIN_PARMS(2);
1470 if (!(ni
= get_nick_info(argv
[1]))) {
1471 reply("MSG_NICK_UNKNOWN", argv
[1]);
1474 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1478 static NICKSERV_FUNC(cmd_rename_handle
)
1480 struct handle_info
*hi
;
1481 char msgbuf
[MAXLEN
], *old_handle
;
1484 NICKSERV_MIN_PARMS(3);
1485 if (!(hi
= get_victim_oper(user
, argv
[1])))
1487 if (!is_valid_handle(argv
[2])) {
1488 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1491 if (get_handle_info(argv
[2])) {
1492 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1495 if(strlen(argv
[2]) > 15)
1497 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1501 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1502 hi
->handle
= strdup(argv
[2]);
1503 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1504 for (nn
=0; nn
<rf_list_used
; nn
++)
1505 rf_list
[nn
](hi
, old_handle
);
1506 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1507 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1508 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1513 static failpw_func_t
*failpw_func_list
;
1514 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1517 reg_failpw_func(failpw_func_t func
)
1519 if (failpw_func_used
== failpw_func_size
) {
1520 if (failpw_func_size
) {
1521 failpw_func_size
<<= 1;
1522 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1524 failpw_func_size
= 8;
1525 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1528 failpw_func_list
[failpw_func_used
++] = func
;
1532 * Return 1 if the handle/pass pair matches, 0 if it doesnt.
1534 * called by nefariouses enhanced AC login-on-connect code
1537 int loc_auth(struct userNode
*user
, char *handle
, char *password
)
1539 int pw_arg
, used
, maxlogins
;
1540 struct handle_info
*hi
;
1542 struct userNode *other;
1545 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1550 /* Responses from here on look up the language used by the handle they asked about. */
1551 if (!checkpass(password
, hi
->passwd
)) {
1554 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1557 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1558 /* Do we want to deny if they already have more logins? I dont see why but
1559 * someone else might? -Rubin
1560 for (used = 0, other = hi->users; other; other = other->next_authed) {
1561 if (++used >= maxlogins) {
1562 send_message_type(4, user, cmd->parent->bot,
1563 handle_find_message(hi, "NSMSG_MAX_LOGINS"),
1565 argv[pw_arg] = "MAXLOGINS";
1573 static NICKSERV_FUNC(cmd_auth
)
1575 int pw_arg
, used
, maxlogins
;
1576 struct handle_info
*hi
;
1578 struct userNode
*other
;
1580 if (user
->handle_info
) {
1581 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1584 if (IsStamped(user
)) {
1585 /* Unauthenticated users might still have been stamped
1586 previously and could therefore have a hidden host;
1587 do not allow them to authenticate. */
1588 reply("NSMSG_STAMPED_AUTH");
1592 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1594 } else if (argc
== 2) {
1595 if (nickserv_conf
.disable_nicks
) {
1596 if (!(hi
= get_handle_info(user
->nick
))) {
1597 reply("NSMSG_HANDLE_NOT_FOUND");
1601 /* try to look up their handle from their nick */
1602 struct nick_info
*ni
;
1603 ni
= get_nick_info(user
->nick
);
1605 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1612 reply("MSG_MISSING_PARAMS", argv
[0]);
1613 svccmd_send_help(user
, nickserv
, cmd
);
1617 reply("NSMSG_HANDLE_NOT_FOUND");
1620 /* Responses from here on look up the language used by the handle they asked about. */
1621 passwd
= argv
[pw_arg
];
1622 if (!valid_user_for(user
, hi
)) {
1623 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1624 send_message_type(4, user
, cmd
->parent
->bot
,
1625 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1628 send_message_type(4, user
, cmd
->parent
->bot
,
1629 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1631 argv
[pw_arg
] = "BADMASK";
1634 if (!checkpass(passwd
, hi
->passwd
)) {
1636 send_message_type(4, user
, cmd
->parent
->bot
,
1637 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1638 argv
[pw_arg
] = "BADPASS";
1639 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1640 if (nickserv_conf
.autogag_enabled
) {
1641 if (!user
->auth_policer
.params
) {
1642 user
->auth_policer
.last_req
= now
;
1643 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1645 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1647 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1648 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1649 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1651 argv
[pw_arg
] = "GAGGED";
1656 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1657 send_message_type(4, user
, cmd
->parent
->bot
,
1658 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1659 argv
[pw_arg
] = "SUSPENDED";
1662 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1663 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1664 if (++used
>= maxlogins
) {
1665 send_message_type(4, user
, cmd
->parent
->bot
,
1666 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1668 argv
[pw_arg
] = "MAXLOGINS";
1673 set_user_handle_info(user
, hi
, 1);
1674 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1675 reply("NSMSG_PLEASE_SET_EMAIL");
1676 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1677 reply("NSMSG_WEAK_PASSWORD");
1678 if (hi
->passwd
[0] != '$')
1679 cryptpass(passwd
, hi
->passwd
);
1680 reply("NSMSG_AUTH_SUCCESS");
1681 argv
[pw_arg
] = "****";
1685 static allowauth_func_t
*allowauth_func_list
;
1686 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
1689 reg_allowauth_func(allowauth_func_t func
)
1691 if (allowauth_func_used
== allowauth_func_size
) {
1692 if (allowauth_func_size
) {
1693 allowauth_func_size
<<= 1;
1694 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
1696 allowauth_func_size
= 8;
1697 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
1700 allowauth_func_list
[allowauth_func_used
++] = func
;
1703 static NICKSERV_FUNC(cmd_allowauth
)
1705 struct userNode
*target
;
1706 struct handle_info
*hi
;
1709 NICKSERV_MIN_PARMS(2);
1710 if (!(target
= GetUserH(argv
[1]))) {
1711 reply("MSG_NICK_UNKNOWN", argv
[1]);
1714 if (target
->handle_info
) {
1715 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
1718 if (IsStamped(target
)) {
1719 /* Unauthenticated users might still have been stamped
1720 previously and could therefore have a hidden host;
1721 do not allow them to authenticate to an account. */
1722 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
1727 else if (!(hi
= get_handle_info(argv
[2]))) {
1728 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
1732 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
1733 reply("MSG_USER_OUTRANKED", hi
->handle
);
1736 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
1737 || (hi
->opserv_level
> 0))
1738 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
1739 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
1742 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
1743 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
1744 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
1745 if (nickserv_conf
.email_enabled
)
1746 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
1748 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
1749 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
1751 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
1753 for (n
=0; n
<allowauth_func_used
; n
++)
1754 allowauth_func_list
[n
](user
, target
, hi
);
1758 static NICKSERV_FUNC(cmd_authcookie
)
1760 struct handle_info
*hi
;
1762 NICKSERV_MIN_PARMS(2);
1763 if (user
->handle_info
) {
1764 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1767 if (IsStamped(user
)) {
1768 /* Unauthenticated users might still have been stamped
1769 previously and could therefore have a hidden host;
1770 do not allow them to authenticate to an account. */
1771 reply("NSMSG_STAMPED_AUTHCOOKIE");
1774 if (!(hi
= get_handle_info(argv
[1]))) {
1775 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1778 if (!hi
->email_addr
) {
1779 reply("MSG_SET_EMAIL_ADDR");
1782 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
);
1786 static NICKSERV_FUNC(cmd_delcookie
)
1788 struct handle_info
*hi
;
1790 hi
= user
->handle_info
;
1792 reply("NSMSG_NO_COOKIE");
1795 switch (hi
->cookie
->type
) {
1798 reply("NSMSG_MUST_TIME_OUT");
1801 nickserv_eat_cookie(hi
->cookie
);
1802 reply("NSMSG_ATE_COOKIE");
1808 static NICKSERV_FUNC(cmd_resetpass
)
1810 struct handle_info
*hi
;
1811 char crypted
[MD5_CRYPT_LENGTH
];
1813 NICKSERV_MIN_PARMS(3);
1814 if (user
->handle_info
) {
1815 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1818 if (IsStamped(user
)) {
1819 /* Unauthenticated users might still have been stamped
1820 previously and could therefore have a hidden host;
1821 do not allow them to activate an account. */
1822 reply("NSMSG_STAMPED_RESETPASS");
1825 if (!(hi
= get_handle_info(argv
[1]))) {
1826 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1829 if (!hi
->email_addr
) {
1830 reply("MSG_SET_EMAIL_ADDR");
1833 cryptpass(argv
[2], crypted
);
1835 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
);
1839 static NICKSERV_FUNC(cmd_cookie
)
1841 struct handle_info
*hi
;
1844 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
1847 NICKSERV_MIN_PARMS(3);
1848 if (!(hi
= get_handle_info(argv
[1]))) {
1849 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
1855 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1856 reply("NSMSG_HANDLE_SUSPENDED");
1861 reply("NSMSG_NO_COOKIE");
1865 /* Check validity of operation before comparing cookie to
1866 * prohibit guessing by authed users. */
1867 if (user
->handle_info
1868 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
1869 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
1870 reply("NSMSG_CANNOT_COOKIE");
1874 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
1875 reply("NSMSG_BAD_COOKIE");
1879 switch (hi
->cookie
->type
) {
1881 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
1882 set_user_handle_info(user
, hi
, 1);
1883 reply("NSMSG_HANDLE_ACTIVATED");
1885 case PASSWORD_CHANGE
:
1886 set_user_handle_info(user
, hi
, 1);
1887 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
1888 reply("NSMSG_PASSWORD_CHANGED");
1891 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
1892 reply("NSMSG_EMAIL_CHANGED");
1895 set_user_handle_info(user
, hi
, 1);
1896 reply("NSMSG_AUTH_SUCCESS");
1899 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
1900 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
1904 nickserv_eat_cookie(hi
->cookie
);
1909 static NICKSERV_FUNC(cmd_oregnick
) {
1911 struct handle_info
*target
;
1912 struct nick_info
*ni
;
1914 NICKSERV_MIN_PARMS(3);
1915 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
1918 if (!is_registerable_nick(nick
)) {
1919 reply("NSMSG_BAD_NICK", nick
);
1922 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
1924 reply("NSMSG_NICK_EXISTS", nick
);
1927 register_nick(nick
, target
);
1928 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
1932 static NICKSERV_FUNC(cmd_regnick
) {
1934 struct nick_info
*ni
;
1936 if (!is_registerable_nick(user
->nick
)) {
1937 reply("NSMSG_BAD_NICK", user
->nick
);
1940 /* count their nicks, see if it's too many */
1941 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
1942 if (n
>= nickserv_conf
.nicks_per_handle
) {
1943 reply("NSMSG_TOO_MANY_NICKS");
1946 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
1948 reply("NSMSG_NICK_EXISTS", user
->nick
);
1951 register_nick(user
->nick
, user
->handle_info
);
1952 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
1956 static NICKSERV_FUNC(cmd_pass
)
1958 struct handle_info
*hi
;
1959 const char *old_pass
, *new_pass
;
1961 NICKSERV_MIN_PARMS(3);
1962 hi
= user
->handle_info
;
1966 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
1967 if (!checkpass(old_pass
, hi
->passwd
)) {
1968 argv
[1] = "BADPASS";
1969 reply("NSMSG_PASSWORD_INVALID");
1972 cryptpass(new_pass
, hi
->passwd
);
1974 reply("NSMSG_PASS_SUCCESS");
1979 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
1982 char *new_mask
= canonicalize_hostmask(strdup(mask
));
1983 for (i
=0; i
<hi
->masks
->used
; i
++) {
1984 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
1985 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
1990 string_list_append(hi
->masks
, new_mask
);
1991 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
1995 static NICKSERV_FUNC(cmd_addmask
)
1998 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1999 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2003 if (!is_gline(argv
[1])) {
2004 reply("NSMSG_MASK_INVALID", argv
[1]);
2007 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2011 static NICKSERV_FUNC(cmd_oaddmask
)
2013 struct handle_info
*hi
;
2015 NICKSERV_MIN_PARMS(3);
2016 if (!(hi
= get_victim_oper(user
, argv
[1])))
2018 return nickserv_addmask(user
, hi
, argv
[2]);
2022 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2025 for (i
=0; i
<hi
->masks
->used
; i
++) {
2026 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2027 char *old_mask
= hi
->masks
->list
[i
];
2028 if (hi
->masks
->used
== 1) {
2029 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2032 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2033 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2038 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2042 static NICKSERV_FUNC(cmd_delmask
)
2044 NICKSERV_MIN_PARMS(2);
2045 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2048 static NICKSERV_FUNC(cmd_odelmask
)
2050 struct handle_info
*hi
;
2051 NICKSERV_MIN_PARMS(3);
2052 if (!(hi
= get_victim_oper(user
, argv
[1])))
2054 return nickserv_delmask(user
, hi
, argv
[2]);
2058 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2059 unsigned int nn
, add
= 1, pos
;
2060 unsigned long added
, removed
, flag
;
2062 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2064 case '+': add
= 1; break;
2065 case '-': add
= 0; break;
2067 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2068 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2071 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2072 /* cheesy avoidance of looking up the flag name.. */
2073 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2076 flag
= 1 << (pos
- 1);
2078 added
|= flag
, removed
&= ~flag
;
2080 removed
|= flag
, added
&= ~flag
;
2085 *premoved
= removed
;
2090 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2092 unsigned long before
, after
, added
, removed
;
2093 struct userNode
*uNode
;
2095 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2096 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2098 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2099 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2101 /* Strip helping flag if they're only a support helper and not
2102 * currently in #support. */
2103 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2104 struct channelList
*schannels
;
2106 schannels
= chanserv_support_channels();
2107 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2108 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2109 if (GetUserMode(schannels
->list
[ii
], uNode
))
2111 if (ii
< schannels
->used
)
2115 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2118 if (after
&& !before
) {
2119 /* Add user to current helper list. */
2120 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2121 userList_append(&curr_helpers
, uNode
);
2122 } else if (!after
&& before
) {
2123 /* Remove user from current helper list. */
2124 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2125 userList_remove(&curr_helpers
, uNode
);
2132 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2136 char *set_display
[] = {
2137 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2138 "EMAIL", "ANNOUNCEMENTS", "MAXLOGINS", "LANGUAGE"
2141 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2143 /* Do this so options are presented in a consistent order. */
2144 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2145 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2146 opt(user
, hi
, override
, 0, NULL
);
2149 static NICKSERV_FUNC(cmd_set
)
2151 struct handle_info
*hi
;
2154 hi
= user
->handle_info
;
2156 set_list(user
, hi
, 0);
2159 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2160 reply("NSMSG_INVALID_OPTION", argv
[1]);
2163 return opt(user
, hi
, 0, argc
-1, argv
+1);
2166 static NICKSERV_FUNC(cmd_oset
)
2168 struct handle_info
*hi
;
2171 NICKSERV_MIN_PARMS(2);
2173 if (!(hi
= get_victim_oper(user
, argv
[1])))
2177 set_list(user
, hi
, 0);
2181 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2182 reply("NSMSG_INVALID_OPTION", argv
[2]);
2186 return opt(user
, hi
, 1, argc
-2, argv
+2);
2189 static OPTION_FUNC(opt_info
)
2193 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2195 hi
->infoline
= NULL
;
2197 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2201 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2202 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2206 static OPTION_FUNC(opt_width
)
2209 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2211 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2212 hi
->screen_width
= MIN_LINE_SIZE
;
2213 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2214 hi
->screen_width
= MAX_LINE_SIZE
;
2216 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2220 static OPTION_FUNC(opt_tablewidth
)
2223 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2225 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2226 hi
->table_width
= MIN_LINE_SIZE
;
2227 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2228 hi
->table_width
= MAX_LINE_SIZE
;
2230 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2234 static OPTION_FUNC(opt_color
)
2237 if (enabled_string(argv
[1]))
2238 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2239 else if (disabled_string(argv
[1]))
2240 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2242 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2247 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2251 static OPTION_FUNC(opt_privmsg
)
2254 if (enabled_string(argv
[1]))
2255 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2256 else if (disabled_string(argv
[1]))
2257 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2259 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2264 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2268 static OPTION_FUNC(opt_style
)
2273 if (!irccasecmp(argv
[1], "Zoot"))
2274 hi
->userlist_style
= HI_STYLE_ZOOT
;
2275 else if (!irccasecmp(argv
[1], "def"))
2276 hi
->userlist_style
= HI_STYLE_DEF
;
2279 switch (hi
->userlist_style
) {
2288 send_message(user
, nickserv
, "NSMSG_SET_STYLE", style
);
2292 static OPTION_FUNC(opt_announcements
)
2297 if (enabled_string(argv
[1]))
2298 hi
->announcements
= 'y';
2299 else if (disabled_string(argv
[1]))
2300 hi
->announcements
= 'n';
2301 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2302 hi
->announcements
= '?';
2304 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2309 switch (hi
->announcements
) {
2310 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2311 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2312 case '?': choice
= "default"; break;
2313 default: choice
= "unknown"; break;
2315 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2319 static OPTION_FUNC(opt_password
)
2322 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2327 cryptpass(argv
[1], hi
->passwd
);
2329 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2333 static OPTION_FUNC(opt_flags
)
2336 unsigned int ii
, flen
;
2339 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2344 nickserv_apply_flags(user
, hi
, argv
[1]);
2346 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2347 if (hi
->flags
& (1 << ii
))
2348 flags
[flen
++] = handle_flags
[ii
];
2351 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2353 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2357 static OPTION_FUNC(opt_email
)
2361 if (!is_valid_email_addr(argv
[1])) {
2362 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2365 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2366 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2369 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2370 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2372 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1]);
2374 nickserv_set_email_addr(hi
, argv
[1]);
2376 nickserv_eat_cookie(hi
->cookie
);
2377 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2380 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2384 static OPTION_FUNC(opt_maxlogins
)
2386 unsigned char maxlogins
;
2388 maxlogins
= strtoul(argv
[1], NULL
, 0);
2389 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2390 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2393 hi
->maxlogins
= maxlogins
;
2395 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2396 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2400 static OPTION_FUNC(opt_language
)
2402 struct language
*lang
;
2404 lang
= language_find(argv
[1]);
2405 if (irccasecmp(lang
->name
, argv
[1]))
2406 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2407 hi
->language
= lang
;
2409 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2414 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2415 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2417 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2418 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2419 && (user
->handle_info
->opserv_level
< 1000))) {
2420 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2423 if ((user
->handle_info
->opserv_level
< new_level
)
2424 || ((user
->handle_info
->opserv_level
== new_level
)
2425 && (user
->handle_info
->opserv_level
< 1000))) {
2426 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2429 if (user
->handle_info
== target
) {
2430 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2433 if (target
->opserv_level
== new_level
)
2435 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2436 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2437 target
->opserv_level
= new_level
;
2441 static OPTION_FUNC(opt_level
)
2446 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2450 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2451 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2455 static OPTION_FUNC(opt_epithet
)
2458 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2462 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2463 char *epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2466 if ((epithet
[0] == '*') && !epithet
[1])
2469 hi
->epithet
= strdup(epithet
);
2473 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2475 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2479 static OPTION_FUNC(opt_title
)
2484 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2488 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2490 if (strchr(title
, '.')) {
2491 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2494 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2495 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2496 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2501 if (!strcmp(title
, "*")) {
2502 hi
->fakehost
= NULL
;
2504 hi
->fakehost
= malloc(strlen(title
)+2);
2505 hi
->fakehost
[0] = '.';
2506 strcpy(hi
->fakehost
+1, title
);
2509 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2510 title
= hi
->fakehost
+ 1;
2514 title
= user_find_message(user
, "MSG_NONE");
2515 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2519 static OPTION_FUNC(opt_fakehost
)
2524 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2528 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2530 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
2531 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
2535 if (!strcmp(fake
, "*"))
2536 hi
->fakehost
= NULL
;
2538 hi
->fakehost
= strdup(fake
);
2539 fake
= hi
->fakehost
;
2542 fake
= generate_fakehost(hi
);
2544 fake
= user_find_message(user
, "MSG_NONE");
2545 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
2549 static NICKSERV_FUNC(cmd_reclaim
)
2551 struct handle_info
*hi
;
2552 struct nick_info
*ni
;
2553 struct userNode
*victim
;
2555 NICKSERV_MIN_PARMS(2);
2556 hi
= user
->handle_info
;
2557 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
2559 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
2562 if (ni
->owner
!= user
->handle_info
) {
2563 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
2566 victim
= GetUserH(ni
->nick
);
2568 reply("MSG_NICK_UNKNOWN", ni
->nick
);
2571 if (victim
== user
) {
2572 reply("NSMSG_NICK_USER_YOU");
2575 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
2576 switch (nickserv_conf
.reclaim_action
) {
2577 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
2578 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
2579 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
2580 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
2585 static NICKSERV_FUNC(cmd_unregnick
)
2588 struct handle_info
*hi
;
2589 struct nick_info
*ni
;
2591 hi
= user
->handle_info
;
2592 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
2593 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2595 reply("NSMSG_UNKNOWN_NICK", nick
);
2598 if (hi
!= ni
->owner
) {
2599 reply("NSMSG_NOT_YOUR_NICK", nick
);
2602 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2607 static NICKSERV_FUNC(cmd_ounregnick
)
2609 struct nick_info
*ni
;
2611 NICKSERV_MIN_PARMS(2);
2612 if (!(ni
= get_nick_info(argv
[1]))) {
2613 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
2616 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
2617 reply("MSG_USER_OUTRANKED", ni
->nick
);
2620 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2625 static NICKSERV_FUNC(cmd_unregister
)
2627 struct handle_info
*hi
;
2630 NICKSERV_MIN_PARMS(2);
2631 hi
= user
->handle_info
;
2634 if (checkpass(passwd
, hi
->passwd
)) {
2635 nickserv_unregister_handle(hi
, user
);
2638 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
2639 reply("NSMSG_PASSWORD_INVALID");
2644 static NICKSERV_FUNC(cmd_ounregister
)
2646 struct handle_info
*hi
;
2648 NICKSERV_MIN_PARMS(2);
2649 if (!(hi
= get_victim_oper(user
, argv
[1])))
2651 nickserv_unregister_handle(hi
, user
);
2655 static NICKSERV_FUNC(cmd_status
)
2657 if (nickserv_conf
.disable_nicks
) {
2658 reply("NSMSG_GLOBAL_STATS_NONICK",
2659 dict_size(nickserv_handle_dict
));
2661 if (user
->handle_info
) {
2663 struct nick_info
*ni
;
2664 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
2665 reply("NSMSG_HANDLE_STATS", cnt
);
2667 reply("NSMSG_HANDLE_NONE");
2669 reply("NSMSG_GLOBAL_STATS",
2670 dict_size(nickserv_handle_dict
),
2671 dict_size(nickserv_nick_dict
));
2676 static NICKSERV_FUNC(cmd_ghost
)
2678 struct userNode
*target
;
2679 char reason
[MAXLEN
];
2681 NICKSERV_MIN_PARMS(2);
2682 if (!(target
= GetUserH(argv
[1]))) {
2683 reply("MSG_NICK_UNKNOWN", argv
[1]);
2686 if (target
== user
) {
2687 reply("NSMSG_CANNOT_GHOST_SELF");
2690 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
2691 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
2694 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
2695 DelUser(target
, nickserv
, 1, reason
);
2696 reply("NSMSG_GHOST_KILLED", argv
[1]);
2700 static NICKSERV_FUNC(cmd_vacation
)
2702 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
2703 reply("NSMSG_ON_VACATION");
2708 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
2710 struct handle_info
*hi
;
2713 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
2715 #ifdef WITH_PROTOCOL_BAHAMUT
2718 saxdb_start_record(ctx
, iter_key(it
), 0);
2719 if (hi
->announcements
!= '?') {
2720 flags
[0] = hi
->announcements
;
2722 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
2725 struct handle_cookie
*cookie
= hi
->cookie
;
2728 switch (cookie
->type
) {
2729 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
2730 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
2731 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
2732 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
2733 default: type
= NULL
; break;
2736 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
2737 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
2738 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
2740 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
2741 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
2742 saxdb_end_record(ctx
);
2746 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
2748 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
2750 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
2754 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
2755 if (hi
->flags
& (1 << ii
))
2756 flags
[flen
++] = handle_flags
[ii
];
2758 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
2760 #ifdef WITH_PROTOCOL_BAHAMUT
2761 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
2764 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
2765 if (hi
->last_quit_host
[0])
2766 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
2767 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
2768 if (hi
->masks
->used
)
2769 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
2771 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
2773 struct string_list
*slist
;
2774 struct nick_info
*ni
;
2776 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
2777 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
2778 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
2782 if (hi
->opserv_level
)
2783 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
2784 if (hi
->language
!= lang_C
)
2785 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
2786 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
2787 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
2788 if (hi
->screen_width
)
2789 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
2790 if (hi
->table_width
)
2791 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
2792 flags
[0] = hi
->userlist_style
;
2794 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
2795 saxdb_end_record(ctx
);
2800 static handle_merge_func_t
*handle_merge_func_list
;
2801 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
2804 reg_handle_merge_func(handle_merge_func_t func
)
2806 if (handle_merge_func_used
== handle_merge_func_size
) {
2807 if (handle_merge_func_size
) {
2808 handle_merge_func_size
<<= 1;
2809 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
2811 handle_merge_func_size
= 8;
2812 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
2815 handle_merge_func_list
[handle_merge_func_used
++] = func
;
2818 static NICKSERV_FUNC(cmd_merge
)
2820 struct handle_info
*hi_from
, *hi_to
;
2821 struct userNode
*last_user
;
2822 struct userData
*cList
, *cListNext
;
2823 unsigned int ii
, jj
, n
;
2824 char buffer
[MAXLEN
];
2826 NICKSERV_MIN_PARMS(3);
2828 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
2830 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
2832 if (hi_to
== hi_from
) {
2833 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
2837 for (n
=0; n
<handle_merge_func_used
; n
++)
2838 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
2840 /* Append "from" handle's nicks to "to" handle's nick list. */
2842 struct nick_info
*last_ni
;
2843 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
2844 last_ni
->next
= hi_from
->nicks
;
2846 while (hi_from
->nicks
) {
2847 hi_from
->nicks
->owner
= hi_to
;
2848 hi_from
->nicks
= hi_from
->nicks
->next
;
2851 /* Merge the hostmasks. */
2852 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
2853 char *mask
= hi_from
->masks
->list
[ii
];
2854 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
2855 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
2857 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
2858 string_list_append(hi_to
->masks
, strdup(mask
));
2861 /* Merge the lists of authed users. */
2863 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
2864 last_user
->next_authed
= hi_from
->users
;
2866 hi_to
->users
= hi_from
->users
;
2868 /* Repoint the old "from" handle's users. */
2869 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
2870 last_user
->handle_info
= hi_to
;
2872 hi_from
->users
= NULL
;
2874 /* Merge channel userlists. */
2875 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
2876 struct userData
*cList2
;
2877 cListNext
= cList
->u_next
;
2878 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
2879 if (cList
->channel
== cList2
->channel
)
2881 if (cList2
&& (cList2
->access
>= cList
->access
)) {
2882 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
);
2883 /* keep cList2 in hi_to; remove cList from hi_from */
2884 del_channel_user(cList
, 1);
2887 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
);
2888 /* remove the lower-ranking cList2 from hi_to */
2889 del_channel_user(cList2
, 1);
2891 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
2893 /* cList needs to be moved from hi_from to hi_to */
2894 cList
->handle
= hi_to
;
2895 /* Remove from linked list for hi_from */
2896 assert(!cList
->u_prev
);
2897 hi_from
->channels
= cList
->u_next
;
2899 cList
->u_next
->u_prev
= cList
->u_prev
;
2900 /* Add to linked list for hi_to */
2901 cList
->u_prev
= NULL
;
2902 cList
->u_next
= hi_to
->channels
;
2903 if (hi_to
->channels
)
2904 hi_to
->channels
->u_prev
= cList
;
2905 hi_to
->channels
= cList
;
2909 /* Do they get an OpServ level promotion? */
2910 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
2911 hi_to
->opserv_level
= hi_from
->opserv_level
;
2913 /* What about last seen time? */
2914 if (hi_from
->lastseen
> hi_to
->lastseen
)
2915 hi_to
->lastseen
= hi_from
->lastseen
;
2917 /* Notify of success. */
2918 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
2919 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
2920 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
2922 /* Unregister the "from" handle. */
2923 nickserv_unregister_handle(hi_from
, NULL
);
2928 struct nickserv_discrim
{
2929 unsigned int limit
, min_level
, max_level
;
2930 unsigned long flags_on
, flags_off
;
2931 time_t min_registered
, max_registered
;
2933 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
2934 const char *nickmask
;
2935 const char *hostmask
;
2936 const char *handlemask
;
2937 const char *emailmask
;
2940 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
2942 struct discrim_apply_info
{
2943 struct nickserv_discrim
*discrim
;
2944 discrim_search_func func
;
2945 struct userNode
*source
;
2946 unsigned int matched
;
2949 static struct nickserv_discrim
*
2950 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
2953 struct nickserv_discrim
*discrim
;
2955 discrim
= malloc(sizeof(*discrim
));
2956 memset(discrim
, 0, sizeof(*discrim
));
2957 discrim
->min_level
= 0;
2958 discrim
->max_level
= ~0;
2959 discrim
->limit
= 50;
2960 discrim
->min_registered
= 0;
2961 discrim
->max_registered
= INT_MAX
;
2962 discrim
->lastseen
= now
;
2964 for (i
=0; i
<argc
; i
++) {
2965 if (i
== argc
- 1) {
2966 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
2969 if (!irccasecmp(argv
[i
], "limit")) {
2970 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
2971 } else if (!irccasecmp(argv
[i
], "flags")) {
2972 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
2973 } else if (!irccasecmp(argv
[i
], "registered")) {
2974 const char *cmp
= argv
[++i
];
2975 if (cmp
[0] == '<') {
2976 if (cmp
[1] == '=') {
2977 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
2979 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
2981 } else if (cmp
[0] == '=') {
2982 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
2983 } else if (cmp
[0] == '>') {
2984 if (cmp
[1] == '=') {
2985 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
2987 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
2990 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
2992 } else if (!irccasecmp(argv
[i
], "seen")) {
2993 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
2994 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
2995 discrim
->nickmask
= argv
[++i
];
2996 } else if (!irccasecmp(argv
[i
], "hostmask")) {
2998 if (!irccasecmp(argv
[i
], "exact")) {
2999 if (i
== argc
- 1) {
3000 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3003 discrim
->hostmask_type
= EXACT
;
3004 } else if (!irccasecmp(argv
[i
], "subset")) {
3005 if (i
== argc
- 1) {
3006 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3009 discrim
->hostmask_type
= SUBSET
;
3010 } else if (!irccasecmp(argv
[i
], "superset")) {
3011 if (i
== argc
- 1) {
3012 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3015 discrim
->hostmask_type
= SUPERSET
;
3016 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3017 if (i
== argc
- 1) {
3018 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3021 discrim
->hostmask_type
= LASTQUIT
;
3024 discrim
->hostmask_type
= SUPERSET
;
3026 discrim
->hostmask
= argv
[++i
];
3027 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3028 if (!irccasecmp(argv
[++i
], "*")) {
3029 discrim
->handlemask
= 0;
3031 discrim
->handlemask
= argv
[i
];
3033 } else if (!irccasecmp(argv
[i
], "email")) {
3034 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3035 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3037 } else if (!irccasecmp(argv
[++i
], "*")) {
3038 discrim
->emailmask
= 0;
3040 discrim
->emailmask
= argv
[i
];
3042 } else if (!irccasecmp(argv
[i
], "access")) {
3043 const char *cmp
= argv
[++i
];
3044 if (cmp
[0] == '<') {
3045 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3046 if (cmp
[1] == '=') {
3047 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3049 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3051 } else if (cmp
[0] == '=') {
3052 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3053 } else if (cmp
[0] == '>') {
3054 if (cmp
[1] == '=') {
3055 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3057 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3060 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3063 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3074 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3076 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3077 || (discrim
->flags_off
& hi
->flags
)
3078 || (discrim
->min_registered
> hi
->registered
)
3079 || (discrim
->max_registered
< hi
->registered
)
3080 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3081 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3082 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3083 || (discrim
->min_level
> hi
->opserv_level
)
3084 || (discrim
->max_level
< hi
->opserv_level
)) {
3087 if (discrim
->hostmask
) {
3089 for (i
=0; i
<hi
->masks
->used
; i
++) {
3090 const char *mask
= hi
->masks
->list
[i
];
3091 if ((discrim
->hostmask_type
== SUBSET
)
3092 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3093 else if ((discrim
->hostmask_type
== EXACT
)
3094 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3095 else if ((discrim
->hostmask_type
== SUPERSET
)
3096 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3097 else if ((discrim
->hostmask_type
== LASTQUIT
)
3098 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3100 if (i
==hi
->masks
->used
) return 0;
3102 if (discrim
->nickmask
) {
3103 struct nick_info
*nick
= hi
->nicks
;
3105 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3108 if (!nick
) return 0;
3114 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3116 dict_iterator_t it
, next
;
3117 unsigned int matched
;
3119 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3120 it
&& (matched
< discrim
->limit
);
3122 next
= iter_next(it
);
3123 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3124 dsf(source
, iter_data(it
));
3132 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3134 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3138 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3143 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3145 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3146 nickserv_unregister_handle(match
, source
);
3150 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3152 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3153 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3154 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3155 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3156 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3160 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3162 struct handle_info_list hil
;
3163 struct helpfile_table tbl
;
3168 memset(&hil
, 0, sizeof(hil
));
3169 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3170 struct handle_info
*hi
= iter_data(it
);
3171 if (hi
->opserv_level
)
3172 handle_info_list_append(&hil
, hi
);
3174 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3175 tbl
.length
= hil
.used
+ 1;
3177 tbl
.flags
= TABLE_NO_FREE
;
3178 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3179 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3182 for (ii
= 0; ii
< hil
.used
; ) {
3183 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3184 ary
[0] = hil
.list
[ii
]->handle
;
3185 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3186 tbl
.contents
[++ii
] = ary
;
3188 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3189 reply("MSG_MATCH_COUNT", hil
.used
);
3190 for (ii
= 0; ii
< hil
.used
; ii
++)
3191 free(tbl
.contents
[ii
]);
3196 static NICKSERV_FUNC(cmd_search
)
3198 struct nickserv_discrim
*discrim
;
3199 discrim_search_func action
;
3200 struct svccmd
*subcmd
;
3201 unsigned int matches
;
3204 NICKSERV_MIN_PARMS(3);
3205 sprintf(buf
, "search %s", argv
[1]);
3206 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3207 if (!irccasecmp(argv
[1], "print"))
3208 action
= search_print_func
;
3209 else if (!irccasecmp(argv
[1], "count"))
3210 action
= search_count_func
;
3211 else if (!irccasecmp(argv
[1], "unregister"))
3212 action
= search_unregister_func
;
3214 reply("NSMSG_INVALID_ACTION", argv
[1]);
3218 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3221 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3225 if (action
== search_print_func
)
3226 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3227 else if (action
== search_count_func
)
3228 discrim
->limit
= INT_MAX
;
3230 matches
= nickserv_discrim_search(discrim
, action
, user
);
3233 reply("MSG_MATCH_COUNT", matches
);
3235 reply("MSG_NO_MATCHES");
3241 static MODCMD_FUNC(cmd_checkpass
)
3243 struct handle_info
*hi
;
3245 NICKSERV_MIN_PARMS(3);
3246 if (!(hi
= get_handle_info(argv
[1]))) {
3247 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3250 if (checkpass(argv
[2], hi
->passwd
))
3251 reply("CHECKPASS_YES");
3253 reply("CHECKPASS_NO");
3259 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3262 struct string_list
*masks
, *slist
;
3263 struct handle_info
*hi
;
3264 struct userNode
*authed_users
;
3265 unsigned long int id
;
3269 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3270 id
= str
? strtoul(str
, NULL
, 0) : 0;
3271 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3273 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3276 if ((hi
= get_handle_info(handle
))) {
3277 authed_users
= hi
->users
;
3279 dict_remove(nickserv_handle_dict
, hi
->handle
);
3281 authed_users
= NULL
;
3283 hi
= register_handle(handle
, str
, id
);
3285 hi
->users
= authed_users
;
3286 while (authed_users
) {
3287 authed_users
->handle_info
= hi
;
3288 authed_users
= authed_users
->next_authed
;
3291 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3292 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3293 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3294 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3295 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3296 hi
->language
= language_find(str
? str
: "C");
3297 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3298 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3299 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3301 hi
->infoline
= strdup(str
);
3302 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3303 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3304 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3305 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3306 /* We want to read the nicks even if disable_nicks is set. This is so
3307 * that we don't lose the nick data entirely. */
3308 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3310 for (ii
=0; ii
<slist
->used
; ii
++)
3311 register_nick(slist
->list
[ii
], hi
);
3313 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3315 for (ii
=0; str
[ii
]; ii
++)
3316 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3318 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3319 hi
->userlist_style
= str
? str
[0] : HI_STYLE_ZOOT
;
3320 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3321 hi
->announcements
= str
? str
[0] : '?';
3322 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3323 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3324 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3325 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3326 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3328 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3330 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3331 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3333 nickserv_set_email_addr(hi
, str
);
3334 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3336 hi
->epithet
= strdup(str
);
3337 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3339 hi
->fakehost
= strdup(str
);
3340 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3342 const char *data
, *type
, *expires
, *cookie_str
;
3343 struct handle_cookie
*cookie
;
3345 cookie
= calloc(1, sizeof(*cookie
));
3346 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3347 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3348 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3349 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3350 if (!type
|| !expires
|| !cookie_str
) {
3351 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3354 if (!irccasecmp(type
, KEY_ACTIVATION
))
3355 cookie
->type
= ACTIVATION
;
3356 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3357 cookie
->type
= PASSWORD_CHANGE
;
3358 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3359 cookie
->type
= EMAIL_CHANGE
;
3360 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3361 cookie
->type
= ALLOWAUTH
;
3363 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3366 cookie
->expires
= strtoul(expires
, NULL
, 0);
3367 if (cookie
->expires
< now
)
3370 cookie
->data
= strdup(data
);
3371 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3375 nickserv_bake_cookie(cookie
);
3377 nickserv_free_cookie(cookie
);
3382 nickserv_saxdb_read(dict_t db
) {
3384 struct record_data
*rd
;
3386 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3388 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3393 static NICKSERV_FUNC(cmd_mergedb
)
3395 struct timeval start
, stop
;
3398 NICKSERV_MIN_PARMS(2);
3399 gettimeofday(&start
, NULL
);
3400 if (!(db
= parse_database(argv
[1]))) {
3401 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3404 nickserv_saxdb_read(db
);
3406 gettimeofday(&stop
, NULL
);
3407 stop
.tv_sec
-= start
.tv_sec
;
3408 stop
.tv_usec
-= start
.tv_usec
;
3409 if (stop
.tv_usec
< 0) {
3411 stop
.tv_usec
+= 1000000;
3413 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3418 expire_handles(UNUSED_ARG(void *data
))
3420 dict_iterator_t it
, next
;
3422 struct handle_info
*hi
;
3424 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3425 next
= iter_next(it
);
3427 if ((hi
->opserv_level
> 0)
3429 || HANDLE_FLAGGED(hi
, FROZEN
)
3430 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3433 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3434 if ((now
- hi
->lastseen
) > expiry
) {
3435 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3436 nickserv_unregister_handle(hi
, NULL
);
3440 if (nickserv_conf
.handle_expire_frequency
)
3441 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3445 nickserv_load_dict(const char *fname
)
3449 if (!(file
= fopen(fname
, "r"))) {
3450 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
3453 while (!feof(file
)) {
3454 fgets(line
, sizeof(line
), file
);
3457 if (line
[strlen(line
)-1] == '\n')
3458 line
[strlen(line
)-1] = 0;
3459 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
3462 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
3465 static enum reclaim_action
3466 reclaim_action_from_string(const char *str
) {
3468 return RECLAIM_NONE
;
3469 else if (!irccasecmp(str
, "warn"))
3470 return RECLAIM_WARN
;
3471 else if (!irccasecmp(str
, "svsnick"))
3472 return RECLAIM_SVSNICK
;
3473 else if (!irccasecmp(str
, "kill"))
3474 return RECLAIM_KILL
;
3476 return RECLAIM_NONE
;
3480 nickserv_conf_read(void)
3482 dict_t conf_node
, child
;
3486 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
3487 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
3490 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
3492 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
3493 if (nickserv_conf
.valid_handle_regex_set
)
3494 regfree(&nickserv_conf
.valid_handle_regex
);
3496 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3497 nickserv_conf
.valid_handle_regex_set
= !err
;
3498 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
3500 nickserv_conf
.valid_handle_regex_set
= 0;
3502 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
3503 if (nickserv_conf
.valid_nick_regex_set
)
3504 regfree(&nickserv_conf
.valid_nick_regex
);
3506 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3507 nickserv_conf
.valid_nick_regex_set
= !err
;
3508 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
3510 nickserv_conf
.valid_nick_regex_set
= 0;
3512 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
3514 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
3515 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
3516 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
3517 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
3518 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
3519 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
3520 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
3521 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
3522 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
3523 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
3524 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
3525 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
3526 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
3527 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
3528 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
3529 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
3530 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
3531 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
3532 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
3533 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
3534 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
3535 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
3536 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
3537 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
3538 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
3540 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
3541 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
3542 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3544 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3545 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
3546 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3548 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3549 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
3550 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
3551 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
3552 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
3553 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
3554 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
3555 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
3556 if (!nickserv_conf
.disable_nicks
) {
3557 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
3558 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3559 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
3560 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
3561 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
3562 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3563 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
3564 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
3566 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
3567 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
3568 const char *key
= iter_key(it
), *value
;
3572 if (!strncasecmp(key
, "uc_", 3))
3573 flag
= toupper(key
[3]);
3574 else if (!strncasecmp(key
, "lc_", 3))
3575 flag
= tolower(key
[3]);
3579 if ((pos
= handle_inverse_flags
[flag
])) {
3580 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
3581 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
3584 if (nickserv_conf
.weak_password_dict
)
3585 dict_delete(nickserv_conf
.weak_password_dict
);
3586 nickserv_conf
.weak_password_dict
= dict_new();
3587 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
3588 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
3589 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
3590 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
3592 nickserv_load_dict(str
);
3593 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
3594 if (nickserv
&& str
)
3595 NickChange(nickserv
, str
, 0);
3596 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
3597 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
3598 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
3599 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
3600 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
3601 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
3602 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
3603 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
3604 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
3605 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
3606 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
3607 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
3608 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
3609 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
3610 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
3611 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
3612 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
3613 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
3614 str
= conf_get_data("server/network", RECDB_QSTRING
);
3615 nickserv_conf
.network_name
= str
? str
: "some IRC network";
3616 if (!nickserv_conf
.auth_policer_params
) {
3617 nickserv_conf
.auth_policer_params
= policer_params_new();
3618 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
3619 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
3621 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
3622 for (it
=dict_first(child
); it
; it
=iter_next(it
))
3623 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
3627 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
3629 char newnick
[NICKLEN
+1];
3638 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3640 case RECLAIM_SVSNICK
:
3642 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
3643 } while (GetUserH(newnick
));
3644 irc_svsnick(nickserv
, user
, newnick
);
3647 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
3648 irc_kill(nickserv
, user
, msg
);
3654 nickserv_reclaim_p(void *data
) {
3655 struct userNode
*user
= data
;
3656 struct nick_info
*ni
= get_nick_info(user
->nick
);
3658 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3662 check_user_nick(struct userNode
*user
) {
3663 struct nick_info
*ni
;
3664 user
->modes
&= ~FLAGS_REGNICK
;
3665 if (!(ni
= get_nick_info(user
->nick
)))
3667 if (user
->handle_info
== ni
->owner
) {
3668 user
->modes
|= FLAGS_REGNICK
;
3672 if (nickserv_conf
.warn_nick_owned
)
3673 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
3674 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
3676 if (nickserv_conf
.auto_reclaim_delay
)
3677 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
3679 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
3684 handle_new_user(struct userNode
*user
)
3686 return check_user_nick(user
);
3690 handle_account(struct userNode
*user
, const char *stamp
)
3692 struct handle_info
*hi
;
3694 #ifdef WITH_PROTOCOL_P10
3695 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
3697 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
3701 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
3704 set_user_handle_info(user
, hi
, 0);
3706 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
3711 handle_nick_change(struct userNode
*user
, const char *old_nick
)
3713 struct handle_info
*hi
;
3715 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
3716 dict_remove(nickserv_allow_auth_dict
, old_nick
);
3717 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
3719 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3720 check_user_nick(user
);
3724 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
3726 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
3727 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
3728 set_user_handle_info(user
, NULL
, 0);
3731 static struct modcmd
*
3732 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
3734 if (min_level
> 0) {
3736 sprintf(buf
, "%u", min_level
);
3737 if (must_be_qualified
) {
3738 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
3740 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
3742 } else if (min_level
== 0) {
3743 if (must_be_qualified
) {
3744 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3746 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
3749 if (must_be_qualified
) {
3750 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
3752 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
3758 nickserv_db_cleanup(void)
3760 unreg_del_user_func(nickserv_remove_user
);
3761 userList_clean(&curr_helpers
);
3762 policer_params_delete(nickserv_conf
.auth_policer_params
);
3763 dict_delete(nickserv_handle_dict
);
3764 dict_delete(nickserv_nick_dict
);
3765 dict_delete(nickserv_opt_dict
);
3766 dict_delete(nickserv_allow_auth_dict
);
3767 dict_delete(nickserv_email_dict
);
3768 dict_delete(nickserv_id_dict
);
3769 dict_delete(nickserv_conf
.weak_password_dict
);
3770 free(auth_func_list
);
3771 free(unreg_func_list
);
3773 free(allowauth_func_list
);
3774 free(handle_merge_func_list
);
3775 free(failpw_func_list
);
3776 if (nickserv_conf
.valid_handle_regex_set
)
3777 regfree(&nickserv_conf
.valid_handle_regex
);
3778 if (nickserv_conf
.valid_nick_regex_set
)
3779 regfree(&nickserv_conf
.valid_nick_regex
);
3783 init_nickserv(const char *nick
)
3786 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
3787 reg_new_user_func(handle_new_user
);
3788 reg_nick_change_func(handle_nick_change
);
3789 reg_del_user_func(nickserv_remove_user
);
3790 reg_account_func(handle_account
);
3792 /* set up handle_inverse_flags */
3793 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
3794 for (i
=0; handle_flags
[i
]; i
++) {
3795 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
3796 flag_access_levels
[i
] = 0;
3799 conf_register_reload(nickserv_conf_read
);
3800 nickserv_opt_dict
= dict_new();
3801 nickserv_email_dict
= dict_new();
3802 dict_set_free_keys(nickserv_email_dict
, free
);
3803 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
3805 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
3806 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
3807 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
3808 * a big pain to disable since its nolonger in the config file. ) -Rubin
3810 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
3811 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
3812 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
3813 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
3814 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
3815 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
3816 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
3817 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
3818 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
3819 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
3820 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
3821 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
3822 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
3823 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
3824 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
3825 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
3826 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
3827 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
3828 if (!nickserv_conf
.disable_nicks
) {
3829 /* nick management commands */
3830 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
3831 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
3832 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
3833 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
3834 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
3835 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
3837 if (nickserv_conf
.email_enabled
) {
3838 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
3839 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
3840 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
3841 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
3842 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
3844 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
3845 /* miscellaneous commands */
3846 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
3847 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
3848 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
3849 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
3850 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
3852 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
3853 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
3854 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
3855 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
3856 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
3857 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
3858 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
3859 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
3860 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
3861 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
3862 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
3863 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
3864 if (nickserv_conf
.titlehost_suffix
) {
3865 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
3866 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
3868 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
3869 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
3870 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
3872 nickserv_handle_dict
= dict_new();
3873 dict_set_free_keys(nickserv_handle_dict
, free
);
3874 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
3876 nickserv_id_dict
= dict_new();
3877 dict_set_free_keys(nickserv_id_dict
, free
);
3879 nickserv_nick_dict
= dict_new();
3880 dict_set_free_data(nickserv_nick_dict
, free
);
3882 nickserv_allow_auth_dict
= dict_new();
3884 userList_init(&curr_helpers
);
3887 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
3888 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
3889 nickserv_service
= service_register(nickserv
);
3891 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
3892 reg_exit_func(nickserv_db_cleanup
);
3893 if(nickserv_conf
.handle_expire_frequency
)
3894 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3895 message_register_table(msgtab
);