1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * x3 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_DENIED_FAKEHOST_WORDS "denied_fakehost_words"
53 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
54 #define KEY_AUTO_OPER "auto_oper"
55 #define KEY_AUTO_ADMIN "auto_admin"
56 #define KEY_FLAG_LEVELS "flag_levels"
57 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
58 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
59 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
60 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
61 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
62 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
63 #define KEY_DICT_FILE "dict_file"
64 #define KEY_NICK "nick"
65 #define KEY_LANGUAGE "language"
66 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
67 #define KEY_AUTOGAG_DURATION "autogag_duration"
68 #define KEY_AUTH_POLICER "auth_policer"
69 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
70 #define KEY_EMAIL_ENABLED "email_enabled"
71 #define KEY_EMAIL_REQUIRED "email_required"
72 #define KEY_SYNC_LOG "sync_log"
73 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
74 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
75 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
76 #define KEY_DEFAULT_STYLE "default_style"
79 #define KEY_PASSWD "passwd"
80 #define KEY_NICKS "nicks"
81 #define KEY_MASKS "masks"
82 #define KEY_IGNORES "ignores"
83 #define KEY_OPSERV_LEVEL "opserv_level"
84 #define KEY_FLAGS "flags"
85 #define KEY_REGISTER_ON "register"
86 #define KEY_LAST_SEEN "lastseen"
87 #define KEY_INFO "info"
88 #define KEY_USERLIST_STYLE "user_style"
89 #define KEY_SCREEN_WIDTH "screen_width"
90 #define KEY_LAST_AUTHED_HOST "last_authed_host"
91 #define KEY_LAST_QUIT_HOST "last_quit_host"
92 #define KEY_EMAIL_ADDR "email_addr"
93 #define KEY_COOKIE "cookie"
94 #define KEY_COOKIE_DATA "data"
95 #define KEY_COOKIE_TYPE "type"
96 #define KEY_COOKIE_EXPIRES "expires"
97 #define KEY_ACTIVATION "activation"
98 #define KEY_PASSWORD_CHANGE "password change"
99 #define KEY_EMAIL_CHANGE "email change"
100 #define KEY_ALLOWAUTH "allowauth"
101 #define KEY_EPITHET "epithet"
102 #define KEY_TABLE_WIDTH "table_width"
103 #define KEY_ANNOUNCEMENTS "announcements"
104 #define KEY_MAXLOGINS "maxlogins"
105 #define KEY_FAKEHOST "fakehost"
106 #define KEY_NOTE_NOTE "note"
107 #define KEY_NOTE_SETTER "setter"
108 #define KEY_NOTE_DATE "date"
111 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
113 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
114 #define OPTION_FUNC(NAME) int NAME(struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
115 typedef OPTION_FUNC(option_func_t
);
117 DEFINE_LIST(handle_info_list
, struct handle_info
*);
119 #define NICKSERV_MIN_PARMS(N) do { \
121 reply("MSG_MISSING_PARAMS", argv[0]); \
122 svccmd_send_help_brief(user, nickserv, cmd); \
126 struct userNode
*nickserv
;
127 struct userList curr_helpers
;
128 const char *handle_flags
= HANDLE_FLAGS
;
130 extern struct string_list
*autojoin_channels
;
131 static struct module *nickserv_module
;
132 static struct service
*nickserv_service
;
133 static struct log_type
*NS_LOG
;
134 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
135 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
136 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
137 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
138 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
139 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
140 static char handle_inverse_flags
[256];
141 static unsigned int flag_access_levels
[32];
142 static const struct message_entry msgtab
[] = {
143 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
144 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu charactors or less."},
145 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
146 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
147 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
148 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
149 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
150 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
151 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
152 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
153 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
154 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
155 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
156 { "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." },
157 { "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." },
158 { "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." },
159 { "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." },
160 { "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." },
161 { "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." },
162 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
163 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
164 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
165 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
166 { "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." },
167 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
168 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
169 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
170 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
171 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
172 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
173 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
174 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
175 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
176 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
177 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
178 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
179 { "NSMSG_REGISTER_BAD_NICKMASK", "Could not recognize $b%s$b as either a current nick or a hostmask." },
180 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
181 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
182 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
183 { "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)" },
184 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
185 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
186 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
187 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
188 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
189 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
190 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
191 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
192 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
193 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
194 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
195 { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
196 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
197 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
198 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
199 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
200 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
201 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
202 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
203 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
204 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
205 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
206 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
207 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
208 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
209 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
210 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
211 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
212 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
213 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
214 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
215 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
216 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
217 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
218 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
219 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
220 { "NSMSG_HANDLEINFO_IGNORES", "Ignore(s): %s" },
221 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
222 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
223 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
224 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
225 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
226 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
227 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
228 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
229 { "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)." },
230 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
231 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
232 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
233 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
234 { "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." },
235 { "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." },
236 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
237 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
238 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
239 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
240 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
241 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
242 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
243 { "NSMSG_PASS_SUCCESS", "Password changed." },
244 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
245 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
246 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
247 { "NSMSG_ADDIGNORE_ALREADY", "$b%s$b is already an ignored hostmask in your account." },
248 { "NSMSG_ADDIGNORE_SUCCESS", "Hostmask %s added." },
249 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
250 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
251 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
252 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
253 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
254 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
255 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
256 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
257 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
258 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
259 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
260 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
261 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
262 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
263 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
264 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
265 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
266 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
267 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
268 { "NSMSG_NO_ACCESS", "Access denied." },
269 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
270 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
271 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
272 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
273 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
274 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
275 { "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." },
276 { "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." },
277 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
278 { "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." },
279 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
280 { "NSMSG_SEARCH_MATCH", "Match: %s" },
281 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
282 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
283 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
284 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
285 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
286 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
287 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
288 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
289 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
290 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
291 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
292 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
293 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
294 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
295 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
296 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
297 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
298 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
299 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
300 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
301 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
302 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
303 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
304 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
305 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
306 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
307 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
308 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
309 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
310 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
311 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
312 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
313 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
315 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
316 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
318 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
319 { "NSEMAIL_ACTIVATION_BODY",
320 "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"
322 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
323 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
324 "This command is only used once to complete your account registration, and never again. Once you have run this command, you will need to authenticate everytime you reconnect to the network. To do this, you will have to type this command every time you reconnect:\n"
325 "/msg %3$s@%4$s AUTH %5$s your-password\n"
326 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
327 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
329 "If you did NOT request this account, you do not need to do anything.\n"
330 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
331 { "NSEMAIL_ACTIVATION_BODY_WEB",
332 "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"
334 "To verify your email address and complete the account registration, visit the following URL:\n"
335 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
337 "If you did NOT request this account, you do not need to do anything.\n"
338 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
339 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
340 { "NSEMAIL_PASSWORD_CHANGE_BODY",
341 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
342 "To complete the password change, log on to %1$s and type the following command:\n"
343 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
344 "If you did NOT request your password to be changed, you do not need to do anything.\n"
345 "Please contact the %1$s staff if you have questions." },
346 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
347 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
348 "To complete the password change, click the following URL:\n"
349 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
350 "If you did NOT request your password to be changed, you do not need to do anything.\n"
351 "Please contact the %1$s staff if you have questions." },
352 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
353 #ifdef stupid_verify_old_email
354 { "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." },
355 { "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." },
357 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
358 { "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." },
359 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
360 { "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." },
361 { "NSMSG_NOT_VALID_FAKEHOST_DOT", "$b%s$b is not a valid vhost. (needs at least one dot)" },
362 { "NSMSG_NOT_VALID_FAKEHOST_AT", "$b%s$b is not a valid vhost. (it can not have a '@')" },
363 { "NSMSG_DENIED_FAKEHOST_WORD", "Access denied because there's a prohibited word in $b%s$b (%s)." },
364 { "NSMSG_NOT_VALID_FAKEHOST_LEN", "$b%s$b is not a valid vhost. (can only be 63 characters)" },
365 { "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", "$b%s$b is not a valid vhost. (TLD can only be 4 characters and less)" },
366 { "CHECKPASS_YES", "Yes." },
367 { "CHECKPASS_NO", "No." },
371 enum reclaim_action
{
377 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
378 static void nickserv_reclaim_p(void *data
);
381 unsigned int disable_nicks
: 1;
382 unsigned int valid_handle_regex_set
: 1;
383 unsigned int valid_nick_regex_set
: 1;
384 unsigned int autogag_enabled
: 1;
385 unsigned int email_enabled
: 1;
386 unsigned int email_required
: 1;
387 unsigned int default_hostmask
: 1;
388 unsigned int warn_nick_owned
: 1;
389 unsigned int warn_clone_auth
: 1;
390 unsigned int sync_log
: 1;
391 unsigned long nicks_per_handle
;
392 unsigned long password_min_length
;
393 unsigned long password_min_digits
;
394 unsigned long password_min_upper
;
395 unsigned long password_min_lower
;
396 unsigned long db_backup_frequency
;
397 unsigned long handle_expire_frequency
;
398 unsigned long autogag_duration
;
399 unsigned long email_visible_level
;
400 unsigned long cookie_timeout
;
401 unsigned long handle_expire_delay
;
402 unsigned long nochan_handle_expire_delay
;
403 unsigned long modoper_level
;
404 unsigned long set_epithet_level
;
405 unsigned long set_title_level
;
406 unsigned long set_fakehost_level
;
407 unsigned long handles_per_email
;
408 unsigned long email_search_level
;
409 const char *network_name
;
410 const char *titlehost_suffix
;
411 regex_t valid_handle_regex
;
412 regex_t valid_nick_regex
;
413 dict_t weak_password_dict
;
414 struct policer_params
*auth_policer_params
;
415 enum reclaim_action reclaim_action
;
416 enum reclaim_action auto_reclaim_action
;
417 unsigned long auto_reclaim_delay
;
418 unsigned char default_maxlogins
;
419 unsigned char hard_maxlogins
;
420 const char *auto_oper
;
421 const char *auto_admin
;
423 struct string_list
*denied_fakehost_words
;
426 /* We have 2^32 unique account IDs to use. */
427 unsigned long int highest_id
= 0;
430 canonicalize_hostmask(char *mask
)
432 char *out
= mask
, *temp
;
433 if ((temp
= strchr(mask
, '!'))) {
435 while (*temp
) *out
++ = *temp
++;
441 static struct handle_note
*
442 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
444 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
446 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
448 memcpy(note
->note
, text
, strlen(text
));
452 static struct handle_info
*
453 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
455 struct handle_info
*hi
;
457 #ifdef WITH_PROTOCOL_BAHAMUT
458 char id_base64
[IDLEN
+ 1];
461 /* Assign a unique account ID to the account; note that 0 is
462 an invalid account ID. 1 is therefore the first account ID. */
464 id
= 1 + highest_id
++;
466 /* Note: highest_id is and must always be the highest ID. */
467 if(id
> highest_id
) {
471 inttobase64(id_base64
, id
, IDLEN
);
473 /* Make sure an account with the same ID doesn't exist. If a
474 duplicate is found, log some details and assign a new one.
475 This should be impossible, but it never hurts to expect it. */
476 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
477 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
483 hi
= calloc(1, sizeof(*hi
));
484 hi
->userlist_style
= HI_DEFAULT_STYLE
;
485 hi
->announcements
= '?';
486 hi
->handle
= strdup(handle
);
487 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
489 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
491 #ifdef WITH_PROTOCOL_BAHAMUT
493 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
500 register_nick(const char *nick
, struct handle_info
*owner
)
502 struct nick_info
*ni
;
503 ni
= malloc(sizeof(struct nick_info
));
504 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
506 ni
->next
= owner
->nicks
;
508 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
512 delete_nick(struct nick_info
*ni
)
514 struct nick_info
*last
, *next
;
515 struct userNode
*user
;
516 /* Check to see if we should mark a user as unregistered. */
517 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
518 user
->modes
&= ~FLAGS_REGNICK
;
521 /* Remove ni from the nick_info linked list. */
522 if (ni
== ni
->owner
->nicks
) {
523 ni
->owner
->nicks
= ni
->next
;
525 last
= ni
->owner
->nicks
;
531 last
->next
= next
->next
;
533 dict_remove(nickserv_nick_dict
, ni
->nick
);
536 static unreg_func_t
*unreg_func_list
;
537 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
540 reg_unreg_func(unreg_func_t func
)
542 if (unreg_func_used
== unreg_func_size
) {
543 if (unreg_func_size
) {
544 unreg_func_size
<<= 1;
545 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
548 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
551 unreg_func_list
[unreg_func_used
++] = func
;
555 nickserv_free_cookie(void *data
)
557 struct handle_cookie
*cookie
= data
;
558 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
559 if (cookie
->data
) free(cookie
->data
);
564 free_handle_info(void *vhi
)
566 struct handle_info
*hi
= vhi
;
568 #ifdef WITH_PROTOCOL_BAHAMUT
571 inttobase64(id
, hi
->id
, IDLEN
);
572 dict_remove(nickserv_id_dict
, id
);
575 free_string_list(hi
->masks
);
576 free_string_list(hi
->ignores
);
580 delete_nick(hi
->nicks
);
586 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
587 nickserv_free_cookie(hi
->cookie
);
589 if (hi
->email_addr
) {
590 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
591 handle_info_list_remove(hil
, hi
);
593 dict_remove(nickserv_email_dict
, hi
->email_addr
);
598 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
601 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
604 struct userNode
*uNode
;
606 for (n
=0; n
<unreg_func_used
; n
++)
607 unreg_func_list
[n
](notify
, hi
);
609 if (nickserv_conf
.sync_log
) {
610 uNode
= GetUserH(hi
->users
->nick
);
614 set_user_handle_info(hi
->users
, NULL
, 0);
617 if (nickserv_conf
.disable_nicks
)
618 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
620 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
623 if (nickserv_conf
.sync_log
)
624 SyncLog("UNREGISTER %s", hi
->handle
);
626 dict_remove(nickserv_handle_dict
, hi
->handle
);
630 get_handle_info(const char *handle
)
632 return dict_find(nickserv_handle_dict
, handle
, 0);
636 get_nick_info(const char *nick
)
638 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
642 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
647 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
648 mn
= channel
->members
.list
[nn
];
649 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
656 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
657 if (!user
->handle_info
) {
659 send_message(user
, bot
, "MSG_AUTHENTICATE");
663 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
665 send_message(user
, bot
, "NSMSG_NO_ACCESS");
669 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
671 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
675 if (user
->handle_info
->opserv_level
< min_level
) {
677 send_message(user
, bot
, "NSMSG_NO_ACCESS");
685 is_valid_handle(const char *handle
)
687 struct userNode
*user
;
688 /* cant register a juped nick/service nick as handle, to prevent confusion */
689 user
= GetUserH(handle
);
690 if (user
&& IsLocal(user
))
692 /* check against maximum length */
693 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
695 /* for consistency, only allow account names that could be nicks */
696 if (!is_valid_nick(handle
))
698 /* disallow account names that look like bad words */
699 if (opserv_bad_channel(handle
))
701 /* test either regex or containing all valid chars */
702 if (nickserv_conf
.valid_handle_regex_set
) {
703 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
706 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
707 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
711 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
716 is_registerable_nick(const char *nick
)
718 /* make sure it could be used as an account name */
719 if (!is_valid_handle(nick
))
722 if (strlen(nick
) > NICKLEN
)
724 /* test either regex or as valid handle */
725 if (nickserv_conf
.valid_nick_regex_set
) {
726 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
729 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
730 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
736 /* this has been replaced with one in tools.c
739 is_valid_email_addr(const char *email)
741 return strchr(email, '@') != NULL;
747 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
749 if (hi
->email_addr
) {
750 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
751 return hi
->email_addr
;
761 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
763 struct handle_info
*hi
;
764 struct userNode
*target
;
768 if (!(hi
= get_handle_info(++name
))) {
769 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
774 if (!(target
= GetUserH(name
))) {
775 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
778 if (IsLocal(target
)) {
779 if (IsService(target
))
780 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
782 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
785 if (!(hi
= target
->handle_info
)) {
786 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
794 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
795 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
797 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
798 if ((user
->handle_info
->opserv_level
== 1000)
799 || (user
->handle_info
== hi
)
800 || ((user
->handle_info
->opserv_level
== 0)
801 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
802 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
806 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
810 static struct handle_info
*
811 get_victim_oper(struct userNode
*user
, const char *target
)
813 struct handle_info
*hi
;
814 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
816 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
817 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
820 return oper_outranks(user
, hi
) ? hi
: NULL
;
824 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
828 /* If no hostmasks on the account, allow it. */
829 if (!hi
->masks
->used
)
831 /* If any hostmask matches, allow it. */
832 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
833 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
835 /* If they are allowauthed to this account, allow it (removing the aa). */
836 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
837 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
840 /* The user is not allowed to use this account. */
845 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
848 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
852 if (len
< nickserv_conf
.password_min_length
) {
854 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
857 if (!irccasecmp(pass
, handle
)) {
859 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
862 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
865 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
868 for (i
=0; i
<len
; i
++) {
869 if (isdigit(pass
[i
]))
871 if (isupper(pass
[i
]))
873 if (islower(pass
[i
]))
876 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
877 || (cnt_upper
< nickserv_conf
.password_min_upper
)
878 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
880 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
886 static auth_func_t
*auth_func_list
;
887 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
890 reg_auth_func(auth_func_t func
)
892 if (auth_func_used
== auth_func_size
) {
893 if (auth_func_size
) {
894 auth_func_size
<<= 1;
895 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
898 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
901 auth_func_list
[auth_func_used
++] = func
;
904 static handle_rename_func_t
*rf_list
;
905 static unsigned int rf_list_size
, rf_list_used
;
908 reg_handle_rename_func(handle_rename_func_t func
)
910 if (rf_list_used
== rf_list_size
) {
913 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
916 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
919 rf_list
[rf_list_used
++] = func
;
923 generate_fakehost(struct handle_info
*handle
)
925 extern const char *hidden_host_suffix
;
926 static char buffer
[HOSTLEN
+1];
928 if (!handle
->fakehost
) {
929 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
931 } else if (handle
->fakehost
[0] == '.') {
932 /* A leading dot indicates the stored value is actually a title. */
933 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
936 return handle
->fakehost
;
940 apply_fakehost(struct handle_info
*handle
)
942 struct userNode
*target
;
947 fake
= generate_fakehost(handle
);
948 for (target
= handle
->users
; target
; target
= target
->next_authed
)
949 assign_fakehost(target
, fake
, 1);
952 void send_func_list(struct userNode
*user
)
955 struct handle_info
*old_info
;
957 old_info
= user
->handle_info
;
959 for (n
=0; n
<auth_func_used
; n
++)
960 auth_func_list
[n
](user
, old_info
);
964 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
967 struct handle_info
*old_info
;
969 /* This can happen if somebody uses COOKIE while authed, or if
970 * they re-auth to their current handle (which is silly, but users
972 if (user
->handle_info
== hi
)
975 if (user
->handle_info
) {
976 struct userNode
*other
;
979 userList_remove(&curr_helpers
, user
);
981 /* remove from next_authed linked list */
982 if (user
->handle_info
->users
== user
) {
983 user
->handle_info
->users
= user
->next_authed
;
985 for (other
= user
->handle_info
->users
;
986 other
->next_authed
!= user
;
987 other
= other
->next_authed
) ;
988 other
->next_authed
= user
->next_authed
;
990 /* if nobody left on old handle, and they're not an oper, remove !god */
991 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
992 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
993 /* record them as being last seen at this time */
994 user
->handle_info
->lastseen
= now
;
995 /* and record their hostmask */
996 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
998 old_info
= user
->handle_info
;
999 user
->handle_info
= hi
;
1000 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
1001 HANDLE_CLEAR_FLAG(hi
, HELPING
);
1003 if (GetUserH(user
->nick
)) {
1004 for (n
=0; n
<auth_func_used
; n
++)
1005 auth_func_list
[n
](user
, old_info
);
1010 struct nick_info
*ni
;
1012 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
1013 if (nickserv_conf
.warn_clone_auth
) {
1014 struct userNode
*other
;
1015 for (other
= hi
->users
; other
; other
= other
->next_authed
)
1016 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1019 user
->next_authed
= hi
->users
;
1023 userList_append(&curr_helpers
, user
);
1025 if (hi
->fakehost
|| old_info
)
1029 #ifdef WITH_PROTOCOL_BAHAMUT
1030 /* Stamp users with their account ID. */
1032 inttobase64(id
, hi
->id
, IDLEN
);
1033 #elif WITH_PROTOCOL_P10
1034 /* Stamp users with their account name. */
1035 char *id
= hi
->handle
;
1037 const char *id
= "???";
1039 if (!nickserv_conf
.disable_nicks
) {
1040 struct nick_info
*ni
;
1041 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
1042 if (!irccasecmp(user
->nick
, ni
->nick
)) {
1043 user
->modes
|= FLAGS_REGNICK
;
1048 StampUser(user
, id
, hi
->registered
);
1051 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1052 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1054 /* We cannot clear the user's account ID, unfortunately. */
1055 user
->next_authed
= NULL
;
1059 static struct handle_info
*
1060 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1062 struct handle_info
*hi
;
1063 struct nick_info
*ni
;
1064 char crypted
[MD5_CRYPT_LENGTH
];
1066 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1067 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1071 if(strlen(handle
) > 15)
1073 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1077 if (!is_secure_password(handle
, passwd
, user
))
1080 cryptpass(passwd
, crypted
);
1081 hi
= register_handle(handle
, crypted
, 0);
1082 hi
->masks
= alloc_string_list(1);
1083 hi
->ignores
= alloc_string_list(1);
1085 hi
->language
= lang_C
;
1086 hi
->registered
= now
;
1088 hi
->flags
= HI_DEFAULT_FLAGS
;
1089 if (settee
&& !no_auth
)
1090 set_user_handle_info(settee
, hi
, 1);
1093 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1094 else if (nickserv_conf
.disable_nicks
)
1095 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1096 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1097 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1099 register_nick(user
->nick
, hi
);
1100 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1102 if (settee
&& (user
!= settee
))
1103 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1108 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1110 cookie
->hi
->cookie
= cookie
;
1111 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1114 /* Contributed by the great sneep of afternet ;) */
1115 /* Since this gets used in a URL, we want to avoid stuff that confuses
1116 * email clients such as ] and ?. a-z, 0-9 only.
1118 void genpass(char *str
, int len
)
1123 for(i
= 0; i
< len
; i
++)
1127 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1128 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1136 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1138 struct handle_cookie
*cookie
;
1139 char subject
[128], body
[4096], *misc
;
1140 const char *netname
, *fmt
;
1144 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1148 cookie
= calloc(1, sizeof(*cookie
));
1150 cookie
->type
= type
;
1151 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1153 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1154 /* Adding dedicated password gen function for more control -Rubin */
1155 genpass(cookie
->cookie
, 10);
1157 *inttobase64(cookie->cookie, rand(), 5);
1158 *inttobase64(cookie->cookie+5, rand(), 5);
1161 netname
= nickserv_conf
.network_name
;
1164 switch (cookie
->type
) {
1166 hi
->passwd
[0] = 0; /* invalidate password */
1167 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1168 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1169 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1172 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1174 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1176 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1179 case PASSWORD_CHANGE
:
1180 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1181 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1182 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1184 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1186 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1187 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1190 misc
= hi
->email_addr
;
1191 hi
->email_addr
= cookie
->data
;
1192 #ifdef stupid_verify_old_email
1194 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1195 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1196 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1197 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1198 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1199 sendmail(nickserv
, hi
, subject
, body
, 1);
1200 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1201 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1204 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1205 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1206 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1207 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1208 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1209 sendmail(nickserv
, hi
, subject
, body
, 1);
1211 #ifdef stupid_verify_old_email
1214 hi
->email_addr
= misc
;
1217 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1218 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1219 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1220 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1221 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1224 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1228 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1229 nickserv_bake_cookie(cookie
);
1233 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1235 cookie
->hi
->cookie
= NULL
;
1236 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1237 nickserv_free_cookie(cookie
);
1241 nickserv_free_email_addr(void *data
)
1243 handle_info_list_clean(data
);
1248 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1250 struct handle_info_list
*hil
;
1251 /* Remove from old handle_info_list ... */
1252 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1253 handle_info_list_remove(hil
, hi
);
1254 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1255 hi
->email_addr
= NULL
;
1257 /* Add to the new list.. */
1258 if (new_email_addr
) {
1259 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1260 hil
= calloc(1, sizeof(*hil
));
1261 hil
->tag
= strdup(new_email_addr
);
1262 handle_info_list_init(hil
);
1263 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1265 handle_info_list_append(hil
, hi
);
1266 hi
->email_addr
= hil
->tag
;
1270 static NICKSERV_FUNC(cmd_register
)
1273 struct handle_info
*hi
;
1274 const char *email_addr
, *password
;
1275 char syncpass
[MD5_CRYPT_LENGTH
];
1276 int no_auth
, weblink
;
1278 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1279 /* Require the first handle registered to belong to someone +o. */
1280 reply("NSMSG_REQUIRE_OPER");
1284 if (user
->handle_info
) {
1285 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1289 if (IsRegistering(user
)) {
1290 reply("NSMSG_ALREADY_REGISTERING");
1294 if (IsStamped(user
)) {
1295 /* Unauthenticated users might still have been stamped
1296 previously and could therefore have a hidden host;
1297 do not allow them to register a new account. */
1298 reply("NSMSG_STAMPED_REGISTER");
1302 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1304 if (!is_valid_handle(argv
[1])) {
1305 reply("NSMSG_BAD_HANDLE", argv
[1]);
1310 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1311 struct handle_info_list
*hil
;
1314 /* Remember email address. */
1315 email_addr
= argv
[3];
1317 /* Check that the email address looks valid.. */
1318 if (!valid_email(email_addr
)) {
1319 reply("NSMSG_BAD_EMAIL_ADDR");
1323 /* .. and that we are allowed to send to it. */
1324 if ((str
= sendmail_prohibited_address(email_addr
))) {
1325 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1329 /* If we do email verify, make sure we don't spam the address. */
1330 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1332 for (nn
=0; nn
<hil
->used
; nn
++) {
1333 if (hil
->list
[nn
]->cookie
) {
1334 reply("NSMSG_EMAIL_UNACTIVATED");
1338 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1339 reply("NSMSG_EMAIL_OVERUSED");
1352 /* Webregister hack - send URL instead of IRC cookie
1355 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1359 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1361 /* Add any masks they should get. */
1362 if (nickserv_conf
.default_hostmask
) {
1363 string_list_append(hi
->masks
, strdup("*@*"));
1365 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1366 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1367 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1370 /* If they're the first to register, give them level 1000. */
1371 if (dict_size(nickserv_handle_dict
) == 1) {
1372 hi
->opserv_level
= 1000;
1373 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1376 /* Set their email address. */
1378 nickserv_set_email_addr(hi
, email_addr
);
1380 /* If they need to do email verification, tell them. */
1382 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1384 /* Set registering flag.. */
1385 user
->modes
|= FLAGS_REGISTERING
;
1387 if (nickserv_conf
.sync_log
) {
1388 cryptpass(password
, syncpass
);
1390 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1391 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1394 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1397 /* this wont work if email is required .. */
1398 process_adduser_pending(user
);
1403 static NICKSERV_FUNC(cmd_oregister
)
1406 struct userNode
*settee
;
1407 struct handle_info
*hi
;
1409 NICKSERV_MIN_PARMS(nickserv_conf
.email_required
? 4 : 3);
1411 if (!is_valid_handle(argv
[1])) {
1412 reply("NSMSG_BAD_HANDLE", argv
[1]);
1416 if (nickserv_conf
.email_required
) {
1417 if (!valid_email(argv
[4])) {
1418 reply("NSMSG_BAD_EMAIL_ADDR");
1423 if (strchr(argv
[3], '@')) {
1424 mask
= canonicalize_hostmask(strdup(argv
[3]));
1426 settee
= GetUserH(nickserv_conf
.email_required
? argv
[5] : argv
[4]);
1428 reply("MSG_NICK_UNKNOWN", nickserv_conf
.email_required
? argv
[5] : argv
[4]);
1435 } else if ((settee
= GetUserH(argv
[3]))) {
1436 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1438 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1441 if (settee
&& settee
->handle_info
) {
1442 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1446 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1447 if (nickserv_conf
.email_required
) {
1448 nickserv_set_email_addr(hi
, argv
[4]);
1449 if (nickserv_conf
.sync_log
)
1450 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, argv
[4], user
->info
);
1455 string_list_append(hi
->masks
, mask
);
1460 nickserv_ignore(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
1463 char *new_mask
= canonicalize_hostmask(strdup(mask
));
1464 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1465 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1466 send_message(user
, nickserv
, "NSMSG_ADDIGNORE_ALREADY", new_mask
);
1471 string_list_append(hi
->ignores
, new_mask
);
1472 send_message(user
, nickserv
, "NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1474 irc_silence(user
, new_mask
, 1);
1478 static NICKSERV_FUNC(cmd_addignore
)
1480 NICKSERV_MIN_PARMS(2);
1482 return nickserv_ignore(user
, user
->handle_info
, argv
[1]);
1485 static NICKSERV_FUNC(cmd_oaddignore
)
1487 struct handle_info
*hi
;
1489 NICKSERV_MIN_PARMS(3);
1490 if (!(hi
= get_victim_oper(user
, argv
[1])))
1492 return nickserv_ignore(user
, hi
, argv
[2]);
1496 nickserv_delignore(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
1499 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1500 if (!strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1501 char *old_mask
= hi
->ignores
->list
[i
];
1502 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1503 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
1504 irc_silence(user
, old_mask
, 0);
1509 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
1513 static NICKSERV_FUNC(cmd_delignore
)
1515 NICKSERV_MIN_PARMS(2);
1516 return nickserv_delignore(user
, user
->handle_info
, argv
[1]);
1519 static NICKSERV_FUNC(cmd_odelignore
)
1521 struct handle_info
*hi
;
1522 NICKSERV_MIN_PARMS(3);
1523 if (!(hi
= get_victim_oper(user
, argv
[1])))
1525 return nickserv_delignore(user
, hi
, argv
[2]);
1528 static NICKSERV_FUNC(cmd_handleinfo
)
1531 unsigned int i
, pos
=0, herelen
;
1532 struct userNode
*target
, *next_un
;
1533 struct handle_info
*hi
;
1534 const char *nsmsg_none
;
1537 if (!(hi
= user
->handle_info
)) {
1538 reply("NSMSG_MUST_AUTH");
1541 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1545 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1546 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1548 #ifdef WITH_PROTOCOL_BAHAMUT
1549 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1551 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1554 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1555 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1557 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1560 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1561 if (HANDLE_FLAGGED(hi
, FROZEN
))
1562 reply("NSMSG_HANDLEINFO_VACATION");
1564 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1565 struct do_not_register
*dnr
;
1566 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1567 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1568 if (!oper_outranks(user
, hi
))
1570 } else if (hi
!= user
->handle_info
) {
1571 reply("NSMSG_HANDLEINFO_END");
1575 if (nickserv_conf
.email_enabled
)
1576 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1580 switch (hi
->cookie
->type
) {
1581 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1582 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1583 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1584 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1585 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1591 unsigned long flen
= 1;
1592 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1594 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1595 if (hi
->flags
& 1 << i
)
1596 flags
[flen
++] = handle_flags
[i
];
1598 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1600 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1603 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1604 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1605 || (hi
->opserv_level
> 0)) {
1606 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1609 if (IsHelping(user
) || IsOper(user
))
1614 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1615 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1620 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1622 if (hi
->last_quit_host
[0])
1623 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1625 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1627 if (nickserv_conf
.disable_nicks
) {
1628 /* nicks disabled; don't show anything about registered nicks */
1629 } else if (hi
->nicks
) {
1630 struct nick_info
*ni
, *next_ni
;
1631 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1632 herelen
= strlen(ni
->nick
);
1633 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1635 goto print_nicks_buff
;
1639 memcpy(buff
+pos
, ni
->nick
, herelen
);
1640 pos
+= herelen
; buff
[pos
++] = ' ';
1644 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1649 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1652 if (hi
->masks
->used
) {
1653 for (i
=0; i
< hi
->masks
->used
; i
++) {
1654 herelen
= strlen(hi
->masks
->list
[i
]);
1655 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1657 goto print_mask_buff
;
1659 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1660 pos
+= herelen
; buff
[pos
++] = ' ';
1661 if (i
+1 == hi
->masks
->used
) {
1664 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1669 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1672 if (hi
->ignores
->used
) {
1673 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1674 herelen
= strlen(hi
->ignores
->list
[i
]);
1675 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1677 goto print_ignore_buff
;
1679 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1680 pos
+= herelen
; buff
[pos
++] = ' ';
1681 if (i
+1 == hi
->ignores
->used
) {
1684 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1689 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1693 struct userData
*channel
, *next
;
1696 for (channel
= hi
->channels
; channel
; channel
= next
) {
1697 next
= channel
->u_next
;
1698 name
= channel
->channel
->channel
->name
;
1699 herelen
= strlen(name
);
1700 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1702 goto print_chans_buff
;
1704 if (IsUserSuspended(channel
))
1706 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1710 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1715 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1718 for (target
= hi
->users
; target
; target
= next_un
) {
1719 herelen
= strlen(target
->nick
);
1720 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1722 goto print_cnick_buff
;
1724 next_un
= target
->next_authed
;
1726 memcpy(buff
+pos
, target
->nick
, herelen
);
1727 pos
+= herelen
; buff
[pos
++] = ' ';
1731 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1736 reply("NSMSG_HANDLEINFO_END");
1740 static NICKSERV_FUNC(cmd_userinfo
)
1742 struct userNode
*target
;
1744 NICKSERV_MIN_PARMS(2);
1745 if (!(target
= GetUserH(argv
[1]))) {
1746 reply("MSG_NICK_UNKNOWN", argv
[1]);
1749 if (target
->handle_info
)
1750 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1752 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1756 static NICKSERV_FUNC(cmd_nickinfo
)
1758 struct nick_info
*ni
;
1760 NICKSERV_MIN_PARMS(2);
1761 if (!(ni
= get_nick_info(argv
[1]))) {
1762 reply("MSG_NICK_UNKNOWN", argv
[1]);
1765 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1769 static NICKSERV_FUNC(cmd_rename_handle
)
1771 struct handle_info
*hi
;
1772 struct userNode
*uNode
;
1773 char msgbuf
[MAXLEN
], *old_handle
;
1776 NICKSERV_MIN_PARMS(3);
1777 if (!(hi
= get_victim_oper(user
, argv
[1])))
1779 if (!is_valid_handle(argv
[2])) {
1780 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1783 if (get_handle_info(argv
[2])) {
1784 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1787 if(strlen(argv
[2]) > 15)
1789 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1793 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1794 hi
->handle
= strdup(argv
[2]);
1795 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1796 for (nn
=0; nn
<rf_list_used
; nn
++)
1797 rf_list
[nn
](hi
, old_handle
);
1798 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1801 if (nickserv_conf
.sync_log
) {
1802 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1803 irc_rename(uNode
, hi
->handle
);
1805 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1808 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1809 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1814 static failpw_func_t
*failpw_func_list
;
1815 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1818 reg_failpw_func(failpw_func_t func
)
1820 if (failpw_func_used
== failpw_func_size
) {
1821 if (failpw_func_size
) {
1822 failpw_func_size
<<= 1;
1823 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1825 failpw_func_size
= 8;
1826 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1829 failpw_func_list
[failpw_func_used
++] = func
;
1833 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1835 * called by nefariouses enhanced AC login-on-connect code
1838 struct handle_info
*loc_auth(char *handle
, char *password
)
1840 int pw_arg
, used
, maxlogins
;
1843 struct handle_info
*hi
;
1844 struct userNode
*other
;
1846 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1852 /* We don't know the users hostname, or anything because they
1853 * havn't registered yet. So we can only allow LOC if your
1854 * account has *@* as a hostmask.
1856 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1858 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1867 /* Responses from here on look up the language used by the handle they asked about. */
1868 if (!checkpass(password
, hi
->passwd
)) {
1871 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1874 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1875 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1876 if (++used
>= maxlogins
) {
1883 static NICKSERV_FUNC(cmd_auth
)
1885 int pw_arg
, used
, maxlogins
;
1886 struct handle_info
*hi
;
1888 struct userNode
*other
;
1890 if (user
->handle_info
) {
1891 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1894 if (IsStamped(user
)) {
1895 /* Unauthenticated users might still have been stamped
1896 previously and could therefore have a hidden host;
1897 do not allow them to authenticate. */
1898 reply("NSMSG_STAMPED_AUTH");
1902 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1904 } else if (argc
== 2) {
1905 if (nickserv_conf
.disable_nicks
) {
1906 if (!(hi
= get_handle_info(user
->nick
))) {
1907 reply("NSMSG_HANDLE_NOT_FOUND");
1911 /* try to look up their handle from their nick */
1912 struct nick_info
*ni
;
1913 ni
= get_nick_info(user
->nick
);
1915 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1922 reply("MSG_MISSING_PARAMS", argv
[0]);
1923 svccmd_send_help_brief(user
, nickserv
, cmd
);
1927 reply("NSMSG_HANDLE_NOT_FOUND");
1930 /* Responses from here on look up the language used by the handle they asked about. */
1931 passwd
= argv
[pw_arg
];
1932 if (!valid_user_for(user
, hi
)) {
1933 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1934 send_message_type(4, user
, cmd
->parent
->bot
,
1935 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1938 send_message_type(4, user
, cmd
->parent
->bot
,
1939 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1941 argv
[pw_arg
] = "BADMASK";
1944 if (!checkpass(passwd
, hi
->passwd
)) {
1946 send_message_type(4, user
, cmd
->parent
->bot
,
1947 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1948 argv
[pw_arg
] = "BADPASS";
1949 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1950 if (nickserv_conf
.autogag_enabled
) {
1951 if (!user
->auth_policer
.params
) {
1952 user
->auth_policer
.last_req
= now
;
1953 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1955 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1957 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1958 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1959 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1961 argv
[pw_arg
] = "GAGGED";
1966 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1967 send_message_type(4, user
, cmd
->parent
->bot
,
1968 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1969 argv
[pw_arg
] = "SUSPENDED";
1972 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1973 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1974 if (++used
>= maxlogins
) {
1975 send_message_type(4, user
, cmd
->parent
->bot
,
1976 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1978 argv
[pw_arg
] = "MAXLOGINS";
1983 set_user_handle_info(user
, hi
, 1);
1984 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1985 reply("NSMSG_PLEASE_SET_EMAIL");
1986 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1987 reply("NSMSG_WEAK_PASSWORD");
1988 if (hi
->passwd
[0] != '$')
1989 cryptpass(passwd
, hi
->passwd
);
1991 /* If a channel was waiting for this user to auth,
1992 * finish adding them */
1993 process_adduser_pending(user
);
1995 reply("NSMSG_AUTH_SUCCESS");
1998 /* Set +x if autohide is on */
1999 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2000 irc_umode(user
, "+x");
2002 if(!IsOper(user
)) /* If they arnt already opered.. */
2004 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2005 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
2007 irc_umode(user
,nickserv_conf
.auto_admin
);
2008 reply("NSMSG_AUTO_OPER_ADMIN");
2010 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
2012 irc_umode(user
,nickserv_conf
.auto_oper
);
2013 reply("NSMSG_AUTO_OPER");
2017 /* Wipe out the pass for the logs */
2018 argv
[pw_arg
] = "****";
2022 static allowauth_func_t
*allowauth_func_list
;
2023 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2026 reg_allowauth_func(allowauth_func_t func
)
2028 if (allowauth_func_used
== allowauth_func_size
) {
2029 if (allowauth_func_size
) {
2030 allowauth_func_size
<<= 1;
2031 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2033 allowauth_func_size
= 8;
2034 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2037 allowauth_func_list
[allowauth_func_used
++] = func
;
2040 static NICKSERV_FUNC(cmd_allowauth
)
2042 struct userNode
*target
;
2043 struct handle_info
*hi
;
2046 NICKSERV_MIN_PARMS(2);
2047 if (!(target
= GetUserH(argv
[1]))) {
2048 reply("MSG_NICK_UNKNOWN", argv
[1]);
2051 if (target
->handle_info
) {
2052 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2055 if (IsStamped(target
)) {
2056 /* Unauthenticated users might still have been stamped
2057 previously and could therefore have a hidden host;
2058 do not allow them to authenticate to an account. */
2059 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2064 else if (!(hi
= get_handle_info(argv
[2]))) {
2065 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2069 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2070 reply("MSG_USER_OUTRANKED", hi
->handle
);
2073 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2074 || (hi
->opserv_level
> 0))
2075 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2076 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2079 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2080 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2081 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2082 if (nickserv_conf
.email_enabled
)
2083 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2085 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2086 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2088 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2090 for (n
=0; n
<allowauth_func_used
; n
++)
2091 allowauth_func_list
[n
](user
, target
, hi
);
2095 static NICKSERV_FUNC(cmd_authcookie
)
2097 struct handle_info
*hi
;
2099 NICKSERV_MIN_PARMS(2);
2100 if (user
->handle_info
) {
2101 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2104 if (IsStamped(user
)) {
2105 /* Unauthenticated users might still have been stamped
2106 previously and could therefore have a hidden host;
2107 do not allow them to authenticate to an account. */
2108 reply("NSMSG_STAMPED_AUTHCOOKIE");
2111 if (!(hi
= get_handle_info(argv
[1]))) {
2112 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2115 if (!hi
->email_addr
) {
2116 reply("MSG_SET_EMAIL_ADDR");
2119 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2123 static NICKSERV_FUNC(cmd_delcookie
)
2125 struct handle_info
*hi
;
2127 hi
= user
->handle_info
;
2129 reply("NSMSG_NO_COOKIE");
2132 switch (hi
->cookie
->type
) {
2135 reply("NSMSG_MUST_TIME_OUT");
2138 nickserv_eat_cookie(hi
->cookie
);
2139 reply("NSMSG_ATE_COOKIE");
2145 static NICKSERV_FUNC(cmd_odelcookie
)
2147 struct handle_info
*hi
;
2149 NICKSERV_MIN_PARMS(2);
2151 if (!(hi
= get_victim_oper(user
, argv
[1])))
2155 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2159 nickserv_eat_cookie(hi
->cookie
);
2160 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2165 static NICKSERV_FUNC(cmd_resetpass
)
2167 struct handle_info
*hi
;
2168 char crypted
[MD5_CRYPT_LENGTH
];
2171 NICKSERV_MIN_PARMS(3);
2172 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2176 if (user
->handle_info
) {
2177 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2180 if (IsStamped(user
)) {
2181 /* Unauthenticated users might still have been stamped
2182 previously and could therefore have a hidden host;
2183 do not allow them to activate an account. */
2184 reply("NSMSG_STAMPED_RESETPASS");
2187 if (!(hi
= get_handle_info(argv
[1]))) {
2188 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2191 if (!hi
->email_addr
) {
2192 reply("MSG_SET_EMAIL_ADDR");
2195 cryptpass(argv
[2], crypted
);
2197 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2201 static NICKSERV_FUNC(cmd_cookie
)
2203 struct handle_info
*hi
;
2206 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2209 NICKSERV_MIN_PARMS(3);
2210 if (!(hi
= get_handle_info(argv
[1]))) {
2211 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2217 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2218 reply("NSMSG_HANDLE_SUSPENDED");
2223 reply("NSMSG_NO_COOKIE");
2227 /* Check validity of operation before comparing cookie to
2228 * prohibit guessing by authed users. */
2229 if (user
->handle_info
2230 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2231 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2232 reply("NSMSG_CANNOT_COOKIE");
2236 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2237 reply("NSMSG_BAD_COOKIE");
2241 switch (hi
->cookie
->type
) {
2243 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2244 set_user_handle_info(user
, hi
, 1);
2245 reply("NSMSG_HANDLE_ACTIVATED");
2246 if (nickserv_conf
.sync_log
)
2247 SyncLog("ACCOUNTACC %s", hi
->handle
);
2249 case PASSWORD_CHANGE
:
2250 set_user_handle_info(user
, hi
, 1);
2251 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2252 reply("NSMSG_PASSWORD_CHANGED");
2253 if (nickserv_conf
.sync_log
)
2254 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2257 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2259 * This should only happen if an OREGISTER was sent. Require
2260 * email must be enabled! - SiRVulcaN
2262 if (nickserv_conf
.sync_log
)
2263 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2265 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2266 reply("NSMSG_EMAIL_CHANGED");
2267 if (nickserv_conf
.sync_log
)
2268 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2271 set_user_handle_info(user
, hi
, 1);
2272 reply("NSMSG_AUTH_SUCCESS");
2275 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2276 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2280 nickserv_eat_cookie(hi
->cookie
);
2282 process_adduser_pending(user
);
2287 static NICKSERV_FUNC(cmd_oregnick
) {
2289 struct handle_info
*target
;
2290 struct nick_info
*ni
;
2292 NICKSERV_MIN_PARMS(3);
2293 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2296 if (!is_registerable_nick(nick
)) {
2297 reply("NSMSG_BAD_NICK", nick
);
2300 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2302 reply("NSMSG_NICK_EXISTS", nick
);
2305 register_nick(nick
, target
);
2306 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2310 static NICKSERV_FUNC(cmd_regnick
) {
2312 struct nick_info
*ni
;
2314 if (!is_registerable_nick(user
->nick
)) {
2315 reply("NSMSG_BAD_NICK", user
->nick
);
2318 /* count their nicks, see if it's too many */
2319 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2320 if (n
>= nickserv_conf
.nicks_per_handle
) {
2321 reply("NSMSG_TOO_MANY_NICKS");
2324 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2326 reply("NSMSG_NICK_EXISTS", user
->nick
);
2329 register_nick(user
->nick
, user
->handle_info
);
2330 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2334 static NICKSERV_FUNC(cmd_pass
)
2336 struct handle_info
*hi
;
2337 const char *old_pass
, *new_pass
;
2339 NICKSERV_MIN_PARMS(3);
2340 hi
= user
->handle_info
;
2344 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2345 if (!checkpass(old_pass
, hi
->passwd
)) {
2346 argv
[1] = "BADPASS";
2347 reply("NSMSG_PASSWORD_INVALID");
2350 cryptpass(new_pass
, hi
->passwd
);
2351 if (nickserv_conf
.sync_log
)
2352 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2354 reply("NSMSG_PASS_SUCCESS");
2359 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2362 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2363 for (i
=0; i
<hi
->masks
->used
; i
++) {
2364 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2365 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2370 string_list_append(hi
->masks
, new_mask
);
2371 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2375 static NICKSERV_FUNC(cmd_addmask
)
2378 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2379 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2383 if (!is_gline(argv
[1])) {
2384 reply("NSMSG_MASK_INVALID", argv
[1]);
2387 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2391 static NICKSERV_FUNC(cmd_oaddmask
)
2393 struct handle_info
*hi
;
2395 NICKSERV_MIN_PARMS(3);
2396 if (!(hi
= get_victim_oper(user
, argv
[1])))
2398 return nickserv_addmask(user
, hi
, argv
[2]);
2402 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2405 for (i
=0; i
<hi
->masks
->used
; i
++) {
2406 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2407 char *old_mask
= hi
->masks
->list
[i
];
2408 if (hi
->masks
->used
== 1) {
2409 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2412 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2413 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2418 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2422 static NICKSERV_FUNC(cmd_delmask
)
2424 NICKSERV_MIN_PARMS(2);
2425 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2428 static NICKSERV_FUNC(cmd_odelmask
)
2430 struct handle_info
*hi
;
2431 NICKSERV_MIN_PARMS(3);
2432 if (!(hi
= get_victim_oper(user
, argv
[1])))
2434 return nickserv_delmask(user
, hi
, argv
[2]);
2438 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2439 unsigned int nn
, add
= 1, pos
;
2440 unsigned long added
, removed
, flag
;
2442 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2444 case '+': add
= 1; break;
2445 case '-': add
= 0; break;
2447 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2448 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2451 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2452 /* cheesy avoidance of looking up the flag name.. */
2453 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2456 flag
= 1 << (pos
- 1);
2458 added
|= flag
, removed
&= ~flag
;
2460 removed
|= flag
, added
&= ~flag
;
2465 *premoved
= removed
;
2470 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2472 unsigned long before
, after
, added
, removed
;
2473 struct userNode
*uNode
;
2475 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2476 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2478 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2479 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2481 /* Strip helping flag if they're only a support helper and not
2482 * currently in #support. */
2483 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2484 struct channelList
*schannels
;
2486 schannels
= chanserv_support_channels();
2487 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2488 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2489 if (GetUserMode(schannels
->list
[ii
], uNode
))
2491 if (ii
< schannels
->used
)
2495 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2498 if (after
&& !before
) {
2499 /* Add user to current helper list. */
2500 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2501 userList_append(&curr_helpers
, uNode
);
2502 } else if (!after
&& before
) {
2503 /* Remove user from current helper list. */
2504 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2505 userList_remove(&curr_helpers
, uNode
);
2512 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2516 char *set_display
[] = {
2517 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2518 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2519 "FAKEHOST", "TITLE", "EPITHET"
2522 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2523 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_HEADER");
2525 /* Do this so options are presented in a consistent order. */
2526 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2527 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2528 opt(user
, hi
, override
, 0, NULL
);
2529 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_END");
2532 static NICKSERV_FUNC(cmd_set
)
2534 struct handle_info
*hi
;
2537 hi
= user
->handle_info
;
2539 set_list(user
, hi
, 0);
2542 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2543 reply("NSMSG_INVALID_OPTION", argv
[1]);
2546 return opt(user
, hi
, 0, argc
-1, argv
+1);
2549 static NICKSERV_FUNC(cmd_oset
)
2551 struct handle_info
*hi
;
2554 NICKSERV_MIN_PARMS(2);
2556 if (!(hi
= get_victim_oper(user
, argv
[1])))
2560 set_list(user
, hi
, 0);
2564 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2565 reply("NSMSG_INVALID_OPTION", argv
[2]);
2569 return opt(user
, hi
, 1, argc
-2, argv
+2);
2572 static OPTION_FUNC(opt_info
)
2576 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2578 hi
->infoline
= NULL
;
2580 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2584 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2585 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2589 static OPTION_FUNC(opt_width
)
2592 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2594 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2595 hi
->screen_width
= MIN_LINE_SIZE
;
2596 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2597 hi
->screen_width
= MAX_LINE_SIZE
;
2599 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2603 static OPTION_FUNC(opt_tablewidth
)
2606 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2608 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2609 hi
->table_width
= MIN_LINE_SIZE
;
2610 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2611 hi
->table_width
= MAX_LINE_SIZE
;
2613 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2617 static OPTION_FUNC(opt_color
)
2620 if (enabled_string(argv
[1]))
2621 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2622 else if (disabled_string(argv
[1]))
2623 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2625 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2630 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2634 static OPTION_FUNC(opt_privmsg
)
2637 if (enabled_string(argv
[1]))
2638 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2639 else if (disabled_string(argv
[1]))
2640 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2642 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2647 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2651 static OPTION_FUNC(opt_autohide
)
2654 if (enabled_string(argv
[1]))
2655 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2656 else if (disabled_string(argv
[1]))
2657 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2659 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2664 send_message(user
, nickserv
, "NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2668 static OPTION_FUNC(opt_style
)
2673 if (!irccasecmp(argv
[1], "Clean"))
2674 hi
->userlist_style
= HI_STYLE_CLEAN
;
2675 else if (!irccasecmp(argv
[1], "Advanced"))
2676 hi
->userlist_style
= HI_STYLE_ADVANCED
;
2677 else if (!irccasecmp(argv
[1], "Classic"))
2678 hi
->userlist_style
= HI_STYLE_CLASSIC
;
2679 else /* Default to normal */
2680 hi
->userlist_style
= HI_STYLE_NORMAL
;
2681 } /* TODO: give error if unknow style is chosen */
2683 switch (hi
->userlist_style
) {
2684 case HI_STYLE_ADVANCED
:
2687 case HI_STYLE_CLASSIC
:
2690 case HI_STYLE_CLEAN
:
2693 case HI_STYLE_NORMAL
:
2698 send_message(user
, nickserv
, "NSMSG_SET_STYLE", style
);
2702 static OPTION_FUNC(opt_announcements
)
2707 if (enabled_string(argv
[1]))
2708 hi
->announcements
= 'y';
2709 else if (disabled_string(argv
[1]))
2710 hi
->announcements
= 'n';
2711 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2712 hi
->announcements
= '?';
2714 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2719 switch (hi
->announcements
) {
2720 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2721 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2722 case '?': choice
= "default"; break;
2723 default: choice
= "unknown"; break;
2725 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2729 static OPTION_FUNC(opt_password
)
2732 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2737 cryptpass(argv
[1], hi
->passwd
);
2739 if (nickserv_conf
.sync_log
)
2740 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2742 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2746 static OPTION_FUNC(opt_flags
)
2749 unsigned int ii
, flen
;
2752 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2757 nickserv_apply_flags(user
, hi
, argv
[1]);
2759 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2760 if (hi
->flags
& (1 << ii
))
2761 flags
[flen
++] = handle_flags
[ii
];
2764 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2766 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2770 static OPTION_FUNC(opt_email
)
2774 if (!valid_email(argv
[1])) {
2775 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2778 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2779 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2782 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2783 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2785 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2787 nickserv_set_email_addr(hi
, argv
[1]);
2789 nickserv_eat_cookie(hi
->cookie
);
2790 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2793 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2797 static OPTION_FUNC(opt_maxlogins
)
2799 unsigned char maxlogins
;
2801 maxlogins
= strtoul(argv
[1], NULL
, 0);
2802 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2803 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2806 hi
->maxlogins
= maxlogins
;
2808 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2809 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2813 static OPTION_FUNC(opt_language
)
2815 struct language
*lang
;
2817 lang
= language_find(argv
[1]);
2818 if (irccasecmp(lang
->name
, argv
[1]))
2819 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2820 hi
->language
= lang
;
2822 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2827 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2828 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2830 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2831 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2832 && (user
->handle_info
->opserv_level
< 1000))) {
2833 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2836 if ((user
->handle_info
->opserv_level
< new_level
)
2837 || ((user
->handle_info
->opserv_level
== new_level
)
2838 && (user
->handle_info
->opserv_level
< 1000))) {
2839 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2842 if (user
->handle_info
== target
) {
2843 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2846 if (target
->opserv_level
== new_level
)
2848 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2849 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2850 target
->opserv_level
= new_level
;
2854 static OPTION_FUNC(opt_level
)
2859 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2863 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2864 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2868 static OPTION_FUNC(opt_epithet
)
2870 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2872 struct userNode
*target
, *next_un
;
2875 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2879 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2883 if ((epithet
[0] == '*') && !epithet
[1])
2886 hi
->epithet
= strdup(epithet
);
2888 for (target
= hi
->users
; target
; target
= next_un
) {
2889 irc_swhois(nickserv
, target
, hi
->epithet
);
2891 next_un
= target
->next_authed
;
2896 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2898 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2902 static OPTION_FUNC(opt_title
)
2906 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2908 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2913 if (strchr(title
, '.')) {
2914 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2917 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2918 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2919 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2924 if (!strcmp(title
, "*")) {
2925 hi
->fakehost
= NULL
;
2927 hi
->fakehost
= malloc(strlen(title
)+2);
2928 hi
->fakehost
[0] = '.';
2929 strcpy(hi
->fakehost
+1, title
);
2932 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2933 title
= hi
->fakehost
+ 1;
2937 title
= user_find_message(user
, "MSG_NONE");
2938 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2943 check_vhost(char *vhost
, struct userNode
*user
)
2945 unsigned int y
, depth
;
2948 // check for a dot in the vhost
2949 if(strchr(vhost
, '.') == NULL
) {
2950 send_message(user
, nickserv
, "NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
2954 // check for a @ in the vhost
2955 if(strchr(vhost
, '@') != NULL
) {
2956 send_message(user
, nickserv
, "NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
2960 // check for denied words, inspired by monk at paki.sex
2961 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
2962 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
2963 send_message(user
, nickserv
, "NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
2968 // check for ircu's HOSTLEN length.
2969 if(strlen(vhost
) >= HOSTLEN
) {
2970 send_message(user
, nickserv
, "NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
2974 if (vhost
[strspn(vhost
, "0123456789.")]) {
2975 hostname
= vhost
+ strlen(vhost
);
2976 for (depth
= 1; depth
&& (hostname
> vhost
); depth
--) {
2978 while ((hostname
> vhost
) && (*hostname
!= '.')) hostname
--;
2981 if (*hostname
== '.') hostname
++; /* advance past last dot we saw */
2982 if(strlen(hostname
) > 4) {
2983 send_message(user
, nickserv
, "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost
);
2991 static OPTION_FUNC(opt_fakehost
)
2995 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2997 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
3002 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3003 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3007 if (!strcmp(fake
, "*")) {
3008 hi
->fakehost
= NULL
;
3010 if (!check_vhost(argv
[1], user
))
3013 hi
->fakehost
= strdup(fake
);
3015 fake
= hi
->fakehost
;
3018 fake
= generate_fakehost(hi
);
3021 fake
= user_find_message(user
, "MSG_NONE");
3022 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
3026 static OPTION_FUNC(opt_note
)
3029 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
3034 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3039 if ((text
[0] == '*') && !text
[1])
3042 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3047 send_message(user
, nickserv
, "NSMSG_SET_NOTE", hi
->note
->note
);
3051 static NICKSERV_FUNC(cmd_reclaim
)
3053 struct handle_info
*hi
;
3054 struct nick_info
*ni
;
3055 struct userNode
*victim
;
3057 NICKSERV_MIN_PARMS(2);
3058 hi
= user
->handle_info
;
3059 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3061 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3064 if (ni
->owner
!= user
->handle_info
) {
3065 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3068 victim
= GetUserH(ni
->nick
);
3070 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3073 if (victim
== user
) {
3074 reply("NSMSG_NICK_USER_YOU");
3077 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3078 switch (nickserv_conf
.reclaim_action
) {
3079 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3080 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3081 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3082 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3087 static NICKSERV_FUNC(cmd_unregnick
)
3090 struct handle_info
*hi
;
3091 struct nick_info
*ni
;
3093 hi
= user
->handle_info
;
3094 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
3095 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
3097 reply("NSMSG_UNKNOWN_NICK", nick
);
3100 if (hi
!= ni
->owner
) {
3101 reply("NSMSG_NOT_YOUR_NICK", nick
);
3104 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3109 static NICKSERV_FUNC(cmd_ounregnick
)
3111 struct nick_info
*ni
;
3113 NICKSERV_MIN_PARMS(2);
3114 if (!(ni
= get_nick_info(argv
[1]))) {
3115 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
3118 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
3119 reply("MSG_USER_OUTRANKED", ni
->nick
);
3122 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3127 static NICKSERV_FUNC(cmd_unregister
)
3129 struct handle_info
*hi
;
3132 NICKSERV_MIN_PARMS(2);
3133 hi
= user
->handle_info
;
3136 if (checkpass(passwd
, hi
->passwd
)) {
3137 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3140 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
3141 reply("NSMSG_PASSWORD_INVALID");
3146 static NICKSERV_FUNC(cmd_ounregister
)
3148 struct handle_info
*hi
;
3150 NICKSERV_MIN_PARMS(2);
3151 if (!(hi
= get_victim_oper(user
, argv
[1])))
3153 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3157 static NICKSERV_FUNC(cmd_status
)
3159 if (nickserv_conf
.disable_nicks
) {
3160 reply("NSMSG_GLOBAL_STATS_NONICK",
3161 dict_size(nickserv_handle_dict
));
3163 if (user
->handle_info
) {
3165 struct nick_info
*ni
;
3166 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
3167 reply("NSMSG_HANDLE_STATS", cnt
);
3169 reply("NSMSG_HANDLE_NONE");
3171 reply("NSMSG_GLOBAL_STATS",
3172 dict_size(nickserv_handle_dict
),
3173 dict_size(nickserv_nick_dict
));
3178 static NICKSERV_FUNC(cmd_ghost
)
3180 struct userNode
*target
;
3181 char reason
[MAXLEN
];
3183 NICKSERV_MIN_PARMS(2);
3184 if (!(target
= GetUserH(argv
[1]))) {
3185 reply("MSG_NICK_UNKNOWN", argv
[1]);
3188 if (target
== user
) {
3189 reply("NSMSG_CANNOT_GHOST_SELF");
3192 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3193 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3196 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3197 DelUser(target
, nickserv
, 1, reason
);
3198 reply("NSMSG_GHOST_KILLED", argv
[1]);
3202 static NICKSERV_FUNC(cmd_vacation
)
3204 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3205 reply("NSMSG_ON_VACATION");
3210 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3212 struct handle_info
*hi
;
3215 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3217 #ifdef WITH_PROTOCOL_BAHAMUT
3220 saxdb_start_record(ctx
, iter_key(it
), 0);
3221 if (hi
->announcements
!= '?') {
3222 flags
[0] = hi
->announcements
;
3224 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3227 struct handle_cookie
*cookie
= hi
->cookie
;
3230 switch (cookie
->type
) {
3231 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3232 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3233 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3234 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3235 default: type
= NULL
; break;
3238 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3239 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3240 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3242 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3243 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3244 saxdb_end_record(ctx
);
3248 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3250 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3252 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3253 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3254 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3255 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3256 saxdb_end_record(ctx
);
3260 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3264 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3265 if (hi
->flags
& (1 << ii
))
3266 flags
[flen
++] = handle_flags
[ii
];
3268 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3270 #ifdef WITH_PROTOCOL_BAHAMUT
3271 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
3274 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3275 if (hi
->last_quit_host
[0])
3276 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3277 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3278 if (hi
->masks
->used
)
3279 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3280 if (hi
->ignores
->used
)
3281 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
3283 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3285 struct string_list
*slist
;
3286 struct nick_info
*ni
;
3288 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3289 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3290 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3294 if (hi
->opserv_level
)
3295 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3296 if (hi
->language
!= lang_C
)
3297 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3298 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3299 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3300 if (hi
->screen_width
)
3301 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3302 if (hi
->table_width
)
3303 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3304 flags
[0] = hi
->userlist_style
;
3306 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3307 saxdb_end_record(ctx
);
3313 static handle_merge_func_t
*handle_merge_func_list
;
3314 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3317 reg_handle_merge_func(handle_merge_func_t func
)
3319 if (handle_merge_func_used
== handle_merge_func_size
) {
3320 if (handle_merge_func_size
) {
3321 handle_merge_func_size
<<= 1;
3322 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3324 handle_merge_func_size
= 8;
3325 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3328 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3331 static NICKSERV_FUNC(cmd_merge
)
3333 struct handle_info
*hi_from
, *hi_to
;
3334 struct userNode
*last_user
;
3335 struct userData
*cList
, *cListNext
;
3336 unsigned int ii
, jj
, n
;
3337 char buffer
[MAXLEN
];
3339 NICKSERV_MIN_PARMS(3);
3341 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
3343 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
3345 if (hi_to
== hi_from
) {
3346 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3350 for (n
=0; n
<handle_merge_func_used
; n
++)
3351 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3353 /* Append "from" handle's nicks to "to" handle's nick list. */
3355 struct nick_info
*last_ni
;
3356 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3357 last_ni
->next
= hi_from
->nicks
;
3359 while (hi_from
->nicks
) {
3360 hi_from
->nicks
->owner
= hi_to
;
3361 hi_from
->nicks
= hi_from
->nicks
->next
;
3364 /* Merge the hostmasks. */
3365 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3366 char *mask
= hi_from
->masks
->list
[ii
];
3367 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3368 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3370 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3371 string_list_append(hi_to
->masks
, strdup(mask
));
3374 /* Merge the ignores. */
3375 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
3376 char *ignore
= hi_from
->ignores
->list
[ii
];
3377 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
3378 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
3380 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3381 string_list_append(hi_to
->ignores
, strdup(ignore
));
3384 /* Merge the lists of authed users. */
3386 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3387 last_user
->next_authed
= hi_from
->users
;
3389 hi_to
->users
= hi_from
->users
;
3391 /* Repoint the old "from" handle's users. */
3392 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3393 last_user
->handle_info
= hi_to
;
3395 hi_from
->users
= NULL
;
3397 /* Merge channel userlists. */
3398 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3399 struct userData
*cList2
;
3400 cListNext
= cList
->u_next
;
3401 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3402 if (cList
->channel
== cList2
->channel
)
3404 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3405 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
);
3406 /* keep cList2 in hi_to; remove cList from hi_from */
3407 del_channel_user(cList
, 1);
3410 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
);
3411 /* remove the lower-ranking cList2 from hi_to */
3412 del_channel_user(cList2
, 1);
3414 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3416 /* cList needs to be moved from hi_from to hi_to */
3417 cList
->handle
= hi_to
;
3418 /* Remove from linked list for hi_from */
3419 assert(!cList
->u_prev
);
3420 hi_from
->channels
= cList
->u_next
;
3422 cList
->u_next
->u_prev
= cList
->u_prev
;
3423 /* Add to linked list for hi_to */
3424 cList
->u_prev
= NULL
;
3425 cList
->u_next
= hi_to
->channels
;
3426 if (hi_to
->channels
)
3427 hi_to
->channels
->u_prev
= cList
;
3428 hi_to
->channels
= cList
;
3432 /* Do they get an OpServ level promotion? */
3433 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3434 hi_to
->opserv_level
= hi_from
->opserv_level
;
3436 /* What about last seen time? */
3437 if (hi_from
->lastseen
> hi_to
->lastseen
)
3438 hi_to
->lastseen
= hi_from
->lastseen
;
3440 /* Does a fakehost carry over? (This intentionally doesn't set it
3441 * for users previously attached to hi_to. They'll just have to
3444 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3445 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3447 /* Notify of success. */
3448 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3449 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3450 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3452 /* Unregister the "from" handle. */
3453 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3458 struct nickserv_discrim
{
3459 unsigned int limit
, min_level
, max_level
;
3460 unsigned long flags_on
, flags_off
;
3461 time_t min_registered
, max_registered
;
3463 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3464 const char *nickmask
;
3465 const char *hostmask
;
3466 const char *handlemask
;
3467 const char *emailmask
;
3470 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3472 struct discrim_apply_info
{
3473 struct nickserv_discrim
*discrim
;
3474 discrim_search_func func
;
3475 struct userNode
*source
;
3476 unsigned int matched
;
3479 static struct nickserv_discrim
*
3480 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3483 struct nickserv_discrim
*discrim
;
3485 discrim
= malloc(sizeof(*discrim
));
3486 memset(discrim
, 0, sizeof(*discrim
));
3487 discrim
->min_level
= 0;
3488 discrim
->max_level
= ~0;
3489 discrim
->limit
= 50;
3490 discrim
->min_registered
= 0;
3491 discrim
->max_registered
= INT_MAX
;
3492 discrim
->lastseen
= now
;
3494 for (i
=0; i
<argc
; i
++) {
3495 if (i
== argc
- 1) {
3496 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3499 if (!irccasecmp(argv
[i
], "limit")) {
3500 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3501 } else if (!irccasecmp(argv
[i
], "flags")) {
3502 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3503 } else if (!irccasecmp(argv
[i
], "registered")) {
3504 const char *cmp
= argv
[++i
];
3505 if (cmp
[0] == '<') {
3506 if (cmp
[1] == '=') {
3507 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3509 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3511 } else if (cmp
[0] == '=') {
3512 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3513 } else if (cmp
[0] == '>') {
3514 if (cmp
[1] == '=') {
3515 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3517 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3520 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3522 } else if (!irccasecmp(argv
[i
], "seen")) {
3523 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3524 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3525 discrim
->nickmask
= argv
[++i
];
3526 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3528 if (!irccasecmp(argv
[i
], "exact")) {
3529 if (i
== argc
- 1) {
3530 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3533 discrim
->hostmask_type
= EXACT
;
3534 } else if (!irccasecmp(argv
[i
], "subset")) {
3535 if (i
== argc
- 1) {
3536 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3539 discrim
->hostmask_type
= SUBSET
;
3540 } else if (!irccasecmp(argv
[i
], "superset")) {
3541 if (i
== argc
- 1) {
3542 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3545 discrim
->hostmask_type
= SUPERSET
;
3546 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3547 if (i
== argc
- 1) {
3548 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3551 discrim
->hostmask_type
= LASTQUIT
;
3554 discrim
->hostmask_type
= SUPERSET
;
3556 discrim
->hostmask
= argv
[++i
];
3557 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3558 if (!irccasecmp(argv
[++i
], "*")) {
3559 discrim
->handlemask
= 0;
3561 discrim
->handlemask
= argv
[i
];
3563 } else if (!irccasecmp(argv
[i
], "email")) {
3564 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3565 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3567 } else if (!irccasecmp(argv
[++i
], "*")) {
3568 discrim
->emailmask
= 0;
3570 discrim
->emailmask
= argv
[i
];
3572 } else if (!irccasecmp(argv
[i
], "access")) {
3573 const char *cmp
= argv
[++i
];
3574 if (cmp
[0] == '<') {
3575 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3576 if (cmp
[1] == '=') {
3577 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3579 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3581 } else if (cmp
[0] == '=') {
3582 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3583 } else if (cmp
[0] == '>') {
3584 if (cmp
[1] == '=') {
3585 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3587 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3590 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3593 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3604 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3606 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3607 || (discrim
->flags_off
& hi
->flags
)
3608 || (discrim
->min_registered
> hi
->registered
)
3609 || (discrim
->max_registered
< hi
->registered
)
3610 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3611 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3612 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3613 || (discrim
->min_level
> hi
->opserv_level
)
3614 || (discrim
->max_level
< hi
->opserv_level
)) {
3617 if (discrim
->hostmask
) {
3619 for (i
=0; i
<hi
->masks
->used
; i
++) {
3620 const char *mask
= hi
->masks
->list
[i
];
3621 if ((discrim
->hostmask_type
== SUBSET
)
3622 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3623 else if ((discrim
->hostmask_type
== EXACT
)
3624 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3625 else if ((discrim
->hostmask_type
== SUPERSET
)
3626 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3627 else if ((discrim
->hostmask_type
== LASTQUIT
)
3628 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3630 if (i
==hi
->masks
->used
) return 0;
3632 if (discrim
->nickmask
) {
3633 struct nick_info
*nick
= hi
->nicks
;
3635 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3638 if (!nick
) return 0;
3644 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3646 dict_iterator_t it
, next
;
3647 unsigned int matched
;
3649 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3650 it
&& (matched
< discrim
->limit
);
3652 next
= iter_next(it
);
3653 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3654 dsf(source
, iter_data(it
));
3662 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3664 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3668 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3673 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3675 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3676 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
3680 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3682 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3683 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3684 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3685 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3686 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3690 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3692 struct handle_info_list hil
;
3693 struct helpfile_table tbl
;
3698 memset(&hil
, 0, sizeof(hil
));
3699 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3700 struct handle_info
*hi
= iter_data(it
);
3701 if (hi
->opserv_level
)
3702 handle_info_list_append(&hil
, hi
);
3704 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3705 tbl
.length
= hil
.used
+ 1;
3707 tbl
.flags
= TABLE_NO_FREE
;
3708 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3709 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3712 for (ii
= 0; ii
< hil
.used
; ) {
3713 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3714 ary
[0] = hil
.list
[ii
]->handle
;
3715 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3716 tbl
.contents
[++ii
] = ary
;
3718 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3719 reply("MSG_MATCH_COUNT", hil
.used
);
3720 for (ii
= 0; ii
< hil
.used
; ii
++)
3721 free(tbl
.contents
[ii
]);
3726 static NICKSERV_FUNC(cmd_search
)
3728 struct nickserv_discrim
*discrim
;
3729 discrim_search_func action
;
3730 struct svccmd
*subcmd
;
3731 unsigned int matches
;
3734 NICKSERV_MIN_PARMS(3);
3735 sprintf(buf
, "search %s", argv
[1]);
3736 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3737 if (!irccasecmp(argv
[1], "print"))
3738 action
= search_print_func
;
3739 else if (!irccasecmp(argv
[1], "count"))
3740 action
= search_count_func
;
3741 else if (!irccasecmp(argv
[1], "unregister"))
3742 action
= search_unregister_func
;
3744 reply("NSMSG_INVALID_ACTION", argv
[1]);
3748 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3751 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3755 if (action
== search_print_func
)
3756 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3757 else if (action
== search_count_func
)
3758 discrim
->limit
= INT_MAX
;
3760 matches
= nickserv_discrim_search(discrim
, action
, user
);
3763 reply("MSG_MATCH_COUNT", matches
);
3765 reply("MSG_NO_MATCHES");
3771 static MODCMD_FUNC(cmd_checkpass
)
3773 struct handle_info
*hi
;
3775 NICKSERV_MIN_PARMS(3);
3776 if (!(hi
= get_handle_info(argv
[1]))) {
3777 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3780 if (checkpass(argv
[2], hi
->passwd
))
3781 reply("CHECKPASS_YES");
3783 reply("CHECKPASS_NO");
3789 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3792 struct string_list
*masks
, *slist
, *ignores
;
3793 struct handle_info
*hi
;
3794 struct userNode
*authed_users
;
3795 struct userData
*channels
;
3796 unsigned long int id
;
3799 char *setter
, *note
;
3802 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3803 id
= str
? strtoul(str
, NULL
, 0) : 0;
3804 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3806 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3809 if ((hi
= get_handle_info(handle
))) {
3810 authed_users
= hi
->users
;
3811 channels
= hi
->channels
;
3813 hi
->channels
= NULL
;
3814 dict_remove(nickserv_handle_dict
, hi
->handle
);
3816 authed_users
= NULL
;
3819 hi
= register_handle(handle
, str
, id
);
3821 hi
->users
= authed_users
;
3822 while (authed_users
) {
3823 authed_users
->handle_info
= hi
;
3824 authed_users
= authed_users
->next_authed
;
3827 hi
->channels
= channels
;
3828 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3829 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3830 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
3831 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
3832 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3833 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3834 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3835 hi
->language
= language_find(str
? str
: "C");
3836 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3837 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3838 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3840 hi
->infoline
= strdup(str
);
3841 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3842 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3843 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3844 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3845 /* We want to read the nicks even if disable_nicks is set. This is so
3846 * that we don't lose the nick data entirely. */
3847 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3849 for (ii
=0; ii
<slist
->used
; ii
++)
3850 register_nick(slist
->list
[ii
], hi
);
3852 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3854 for (ii
=0; str
[ii
]; ii
++)
3855 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3857 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3858 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
3859 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3860 hi
->announcements
= str
? str
[0] : '?';
3861 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3862 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3863 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3864 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3865 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3867 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3869 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3870 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3872 nickserv_set_email_addr(hi
, str
);
3873 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3875 hi
->epithet
= strdup(str
);
3876 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
3878 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
3879 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
3880 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3881 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
3882 if (setter
&& date
&& note
)
3884 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
3889 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3891 hi
->fakehost
= strdup(str
);
3893 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3895 const char *data
, *type
, *expires
, *cookie_str
;
3896 struct handle_cookie
*cookie
;
3898 cookie
= calloc(1, sizeof(*cookie
));
3899 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3900 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3901 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3902 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3903 if (!type
|| !expires
|| !cookie_str
) {
3904 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3907 if (!irccasecmp(type
, KEY_ACTIVATION
))
3908 cookie
->type
= ACTIVATION
;
3909 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3910 cookie
->type
= PASSWORD_CHANGE
;
3911 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3912 cookie
->type
= EMAIL_CHANGE
;
3913 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3914 cookie
->type
= ALLOWAUTH
;
3916 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3919 cookie
->expires
= strtoul(expires
, NULL
, 0);
3920 if (cookie
->expires
< now
)
3923 cookie
->data
= strdup(data
);
3924 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3928 nickserv_bake_cookie(cookie
);
3930 nickserv_free_cookie(cookie
);
3935 nickserv_saxdb_read(dict_t db
) {
3937 struct record_data
*rd
;
3939 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3941 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3946 static NICKSERV_FUNC(cmd_mergedb
)
3948 struct timeval start
, stop
;
3951 NICKSERV_MIN_PARMS(2);
3952 gettimeofday(&start
, NULL
);
3953 if (!(db
= parse_database(argv
[1]))) {
3954 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3957 nickserv_saxdb_read(db
);
3959 gettimeofday(&stop
, NULL
);
3960 stop
.tv_sec
-= start
.tv_sec
;
3961 stop
.tv_usec
-= start
.tv_usec
;
3962 if (stop
.tv_usec
< 0) {
3964 stop
.tv_usec
+= 1000000;
3966 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3971 expire_handles(UNUSED_ARG(void *data
))
3973 dict_iterator_t it
, next
;
3975 struct handle_info
*hi
;
3977 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3978 next
= iter_next(it
);
3980 if ((hi
->opserv_level
> 0)
3982 || HANDLE_FLAGGED(hi
, FROZEN
)
3983 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3986 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3987 if ((now
- hi
->lastseen
) > expiry
) {
3988 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3989 nickserv_unregister_handle(hi
, NULL
, NULL
);
3993 if (nickserv_conf
.handle_expire_frequency
)
3994 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3998 nickserv_load_dict(const char *fname
)
4002 if (!(file
= fopen(fname
, "r"))) {
4003 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
4006 while (!feof(file
)) {
4007 fgets(line
, sizeof(line
), file
);
4010 if (line
[strlen(line
)-1] == '\n')
4011 line
[strlen(line
)-1] = 0;
4012 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
4015 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
4018 static enum reclaim_action
4019 reclaim_action_from_string(const char *str
) {
4021 return RECLAIM_NONE
;
4022 else if (!irccasecmp(str
, "warn"))
4023 return RECLAIM_WARN
;
4024 else if (!irccasecmp(str
, "svsnick"))
4025 return RECLAIM_SVSNICK
;
4026 else if (!irccasecmp(str
, "kill"))
4027 return RECLAIM_KILL
;
4029 return RECLAIM_NONE
;
4033 nickserv_conf_read(void)
4035 dict_t conf_node
, child
;
4038 struct string_list
*strlist
;
4040 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
4041 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
4044 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
4046 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
4047 if (nickserv_conf
.valid_handle_regex_set
)
4048 regfree(&nickserv_conf
.valid_handle_regex
);
4050 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4051 nickserv_conf
.valid_handle_regex_set
= !err
;
4052 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
4054 nickserv_conf
.valid_handle_regex_set
= 0;
4056 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
4057 if (nickserv_conf
.valid_nick_regex_set
)
4058 regfree(&nickserv_conf
.valid_nick_regex
);
4060 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4061 nickserv_conf
.valid_nick_regex_set
= !err
;
4062 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
4064 nickserv_conf
.valid_nick_regex_set
= 0;
4066 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
4068 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
4069 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
4070 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
4071 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
4072 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
4073 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
4074 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
4075 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
4076 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
4077 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
4078 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
4079 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
4080 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
4081 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
4082 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
4083 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
4084 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
4085 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
4086 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
4087 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
4088 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
4089 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
4090 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
4091 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
4092 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
4094 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
4095 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
4096 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4098 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4099 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
4100 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4102 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4103 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
4104 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
4105 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
4106 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
4107 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
4108 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
4109 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
4110 if (!nickserv_conf
.disable_nicks
) {
4111 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
4112 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4113 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
4114 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
4115 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
4116 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4117 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
4118 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
4120 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
4121 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
4122 const char *key
= iter_key(it
), *value
;
4126 if (!strncasecmp(key
, "uc_", 3))
4127 flag
= toupper(key
[3]);
4128 else if (!strncasecmp(key
, "lc_", 3))
4129 flag
= tolower(key
[3]);
4133 if ((pos
= handle_inverse_flags
[flag
])) {
4134 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
4135 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
4138 if (nickserv_conf
.weak_password_dict
)
4139 dict_delete(nickserv_conf
.weak_password_dict
);
4140 nickserv_conf
.weak_password_dict
= dict_new();
4141 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
4142 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
4143 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
4144 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
4146 nickserv_load_dict(str
);
4147 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
4148 if (nickserv
&& str
)
4149 NickChange(nickserv
, str
, 0);
4150 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
4151 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
4152 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
4153 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
4154 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
4155 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
4156 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
4157 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
4158 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
4159 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
4160 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
4161 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
4162 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
4163 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
4164 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
4165 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
4166 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
4167 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
4168 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
4169 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
4171 free_string_list(nickserv_conf
.denied_fakehost_words
);
4172 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
4174 strlist
= string_list_copy(strlist
);
4176 strlist
= alloc_string_list(4);
4177 string_list_append(strlist
, strdup("sex"));
4178 string_list_append(strlist
, strdup("fuck"));
4180 nickserv_conf
.denied_fakehost_words
= strlist
;
4182 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
4183 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4185 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
4186 nickserv_conf
.auto_oper
= str
? str
: "";
4188 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
4189 nickserv_conf
.auto_admin
= str
? str
: "";
4191 str
= conf_get_data("server/network", RECDB_QSTRING
);
4192 nickserv_conf
.network_name
= str
? str
: "some IRC network";
4193 if (!nickserv_conf
.auth_policer_params
) {
4194 nickserv_conf
.auth_policer_params
= policer_params_new();
4195 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
4196 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4198 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4199 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4200 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4204 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
4206 char newnick
[NICKLEN
+1];
4215 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4217 case RECLAIM_SVSNICK
:
4219 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4220 } while (GetUserH(newnick
));
4221 irc_svsnick(nickserv
, user
, newnick
);
4224 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4225 irc_kill(nickserv
, user
, msg
);
4231 nickserv_reclaim_p(void *data
) {
4232 struct userNode
*user
= data
;
4233 struct nick_info
*ni
= get_nick_info(user
->nick
);
4235 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4239 check_user_nick(struct userNode
*user
) {
4240 struct nick_info
*ni
;
4241 user
->modes
&= ~FLAGS_REGNICK
;
4242 if (!(ni
= get_nick_info(user
->nick
)))
4244 if (user
->handle_info
== ni
->owner
) {
4245 user
->modes
|= FLAGS_REGNICK
;
4249 if (nickserv_conf
.warn_nick_owned
)
4250 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4251 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
4253 if (nickserv_conf
.auto_reclaim_delay
)
4254 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
4256 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4261 handle_new_user(struct userNode
*user
)
4263 return check_user_nick(user
);
4267 handle_account(struct userNode
*user
, const char *stamp
)
4269 struct handle_info
*hi
;
4272 #ifdef WITH_PROTOCOL_P10
4273 time_t timestamp
= 0;
4275 colon
= strchr(stamp
, ':');
4276 if(colon
&& colon
[1])
4279 timestamp
= atoi(colon
+1);
4281 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
4282 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
4284 log_module(MAIN_LOG
, LOG_WARNING
, "%s using account %s but timestamp does not match %lu is not %lu.", user
->nick
, stamp
, timestamp
, hi
->registered
);
4288 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4289 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4293 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4296 set_user_handle_info(user
, hi
, 0);
4298 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4303 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4305 struct handle_info
*hi
;
4307 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4308 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4309 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4311 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4312 check_user_nick(user
);
4316 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4318 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4319 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4320 set_user_handle_info(user
, NULL
, 0);
4323 static struct modcmd
*
4324 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4326 if (min_level
> 0) {
4328 sprintf(buf
, "%u", min_level
);
4329 if (must_be_qualified
) {
4330 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4332 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4334 } else if (min_level
== 0) {
4335 if (must_be_qualified
) {
4336 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4338 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4341 if (must_be_qualified
) {
4342 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4344 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4350 nickserv_db_cleanup(void)
4352 unreg_del_user_func(nickserv_remove_user
);
4353 userList_clean(&curr_helpers
);
4354 policer_params_delete(nickserv_conf
.auth_policer_params
);
4355 dict_delete(nickserv_handle_dict
);
4356 dict_delete(nickserv_nick_dict
);
4357 dict_delete(nickserv_opt_dict
);
4358 dict_delete(nickserv_allow_auth_dict
);
4359 dict_delete(nickserv_email_dict
);
4360 dict_delete(nickserv_id_dict
);
4361 dict_delete(nickserv_conf
.weak_password_dict
);
4362 free(auth_func_list
);
4363 free(unreg_func_list
);
4365 free(allowauth_func_list
);
4366 free(handle_merge_func_list
);
4367 free(failpw_func_list
);
4368 if (nickserv_conf
.valid_handle_regex_set
)
4369 regfree(&nickserv_conf
.valid_handle_regex
);
4370 if (nickserv_conf
.valid_nick_regex_set
)
4371 regfree(&nickserv_conf
.valid_nick_regex
);
4375 init_nickserv(const char *nick
)
4377 struct chanNode
*chan
;
4379 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4380 reg_new_user_func(handle_new_user
);
4381 reg_nick_change_func(handle_nick_change
);
4382 reg_del_user_func(nickserv_remove_user
);
4383 reg_account_func(handle_account
);
4385 /* set up handle_inverse_flags */
4386 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4387 for (i
=0; handle_flags
[i
]; i
++) {
4388 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4389 flag_access_levels
[i
] = 0;
4392 conf_register_reload(nickserv_conf_read
);
4393 nickserv_opt_dict
= dict_new();
4394 nickserv_email_dict
= dict_new();
4396 dict_set_free_keys(nickserv_email_dict
, free
);
4397 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4399 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4400 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4401 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4402 * a big pain to disable since its nolonger in the config file. ) -Rubin
4404 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4405 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4406 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4407 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4408 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4409 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4410 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4411 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4412 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4413 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4414 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4415 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4416 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4417 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4418 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4419 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4420 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4421 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4422 if (!nickserv_conf
.disable_nicks
) {
4423 /* nick management commands */
4424 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4425 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4426 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4427 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4428 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4429 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4431 if (nickserv_conf
.email_enabled
) {
4432 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4433 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4434 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4435 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4436 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4437 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4439 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4440 /* ignore commands */
4441 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
4442 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
4443 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
4444 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
4445 /* miscellaneous commands */
4446 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4447 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4448 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4449 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4450 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4452 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4453 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4454 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4455 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4456 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4457 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
4458 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
4459 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4460 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4461 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4462 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4463 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4464 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4465 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
4466 if (nickserv_conf
.titlehost_suffix
) {
4467 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4468 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4470 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4471 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4472 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4474 nickserv_handle_dict
= dict_new();
4475 dict_set_free_keys(nickserv_handle_dict
, free
);
4476 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4478 nickserv_id_dict
= dict_new();
4479 dict_set_free_keys(nickserv_id_dict
, free
);
4481 nickserv_nick_dict
= dict_new();
4482 dict_set_free_data(nickserv_nick_dict
, free
);
4484 nickserv_allow_auth_dict
= dict_new();
4486 userList_init(&curr_helpers
);
4489 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4490 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4491 nickserv_service
= service_register(nickserv
);
4493 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4494 reg_exit_func(nickserv_db_cleanup
);
4495 if(nickserv_conf
.handle_expire_frequency
)
4496 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4498 if(autojoin_channels
&& nickserv
) {
4499 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
4500 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
4501 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
4505 message_register_table(msgtab
);