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_BAD_ADVANCED", "Advanced must be either 1 to enable it or 0 to disable it." },
190 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
191 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
192 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
193 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
194 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
195 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
196 { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
197 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
198 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
199 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
200 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
201 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
202 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
203 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
204 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
205 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
206 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
207 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
208 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
209 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
210 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
211 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
212 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
213 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
214 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
215 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
216 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
217 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
218 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
219 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
220 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
221 { "NSMSG_HANDLEINFO_IGNORES", "Ignore(s): %s" },
222 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
223 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
224 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
225 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
226 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
227 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
228 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
229 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
230 { "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)." },
231 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
232 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
233 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
234 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
235 { "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." },
236 { "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." },
237 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
238 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
239 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
240 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
241 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
242 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
243 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
244 { "NSMSG_PASS_SUCCESS", "Password changed." },
245 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
246 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
247 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
248 { "NSMSG_ADDIGNORE_ALREADY", "$b%s$b is already an ignored hostmask in your account." },
249 { "NSMSG_ADDIGNORE_SUCCESS", "Hostmask %s added." },
250 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
251 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
252 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
253 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
254 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
255 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
256 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
257 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
258 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
259 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
260 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
261 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
262 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
263 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
264 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
265 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
266 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
267 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
268 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
269 { "NSMSG_NO_ACCESS", "Access denied." },
270 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
271 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
272 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
273 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
274 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
275 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
276 { "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." },
277 { "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." },
278 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
279 { "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." },
280 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
281 { "NSMSG_SEARCH_MATCH", "Match: %s" },
282 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
283 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
284 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
285 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
286 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
287 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
288 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
289 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
290 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
291 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
292 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
293 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
294 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
295 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
296 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
297 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
298 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
299 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
300 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
301 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
302 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
303 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
304 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
305 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
306 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
307 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
308 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
309 { "NSMSG_SET_ADVANCED", "$bADVANCED: $b%s" },
310 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
311 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
312 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
313 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
314 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
315 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
317 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
318 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
320 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
321 { "NSEMAIL_ACTIVATION_BODY",
322 "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"
324 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
325 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
326 "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"
327 "/msg %3$s@%4$s AUTH %5$s your-password\n"
328 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
329 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
331 "If you did NOT request this account, you do not need to do anything.\n"
332 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
333 { "NSEMAIL_ACTIVATION_BODY_WEB",
334 "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"
336 "To verify your email address and complete the account registration, visit the following URL:\n"
337 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
339 "If you did NOT request this account, you do not need to do anything.\n"
340 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
341 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
342 { "NSEMAIL_PASSWORD_CHANGE_BODY",
343 "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"
344 "To complete the password change, log on to %1$s and type the following command:\n"
345 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
346 "If you did NOT request your password to be changed, you do not need to do anything.\n"
347 "Please contact the %1$s staff if you have questions." },
348 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
349 "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"
350 "To complete the password change, click the following URL:\n"
351 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
352 "If you did NOT request your password to be changed, you do not need to do anything.\n"
353 "Please contact the %1$s staff if you have questions." },
354 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
355 #ifdef stupid_verify_old_email
356 { "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." },
357 { "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." },
359 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
360 { "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." },
361 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
362 { "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." },
363 { "NSMSG_NOT_VALID_FAKEHOST_DOT", "$b%s$b is not a valid vhost. (needs at least one dot)" },
364 { "NSMSG_NOT_VALID_FAKEHOST_AT", "$b%s$b is not a valid vhost. (it can not have a '@')" },
365 { "NSMSG_DENIED_FAKEHOST_WORD", "Access denied because there's a prohibited word in $b%s$b (%s)." },
366 { "NSMSG_NOT_VALID_FAKEHOST_LEN", "$b%s$b is not a valid vhost. (can only be 63 characters)" },
367 { "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", "$b%s$b is not a valid vhost. (TLD can only be 4 characters and less)" },
368 { "CHECKPASS_YES", "Yes." },
369 { "CHECKPASS_NO", "No." },
373 enum reclaim_action
{
379 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
380 static void nickserv_reclaim_p(void *data
);
383 unsigned int disable_nicks
: 1;
384 unsigned int valid_handle_regex_set
: 1;
385 unsigned int valid_nick_regex_set
: 1;
386 unsigned int autogag_enabled
: 1;
387 unsigned int email_enabled
: 1;
388 unsigned int email_required
: 1;
389 unsigned int default_hostmask
: 1;
390 unsigned int warn_nick_owned
: 1;
391 unsigned int warn_clone_auth
: 1;
392 unsigned int sync_log
: 1;
393 unsigned long nicks_per_handle
;
394 unsigned long password_min_length
;
395 unsigned long password_min_digits
;
396 unsigned long password_min_upper
;
397 unsigned long password_min_lower
;
398 unsigned long db_backup_frequency
;
399 unsigned long handle_expire_frequency
;
400 unsigned long autogag_duration
;
401 unsigned long email_visible_level
;
402 unsigned long cookie_timeout
;
403 unsigned long handle_expire_delay
;
404 unsigned long nochan_handle_expire_delay
;
405 unsigned long modoper_level
;
406 unsigned long set_epithet_level
;
407 unsigned long set_title_level
;
408 unsigned long set_fakehost_level
;
409 unsigned long handles_per_email
;
410 unsigned long email_search_level
;
411 const char *network_name
;
412 const char *titlehost_suffix
;
413 regex_t valid_handle_regex
;
414 regex_t valid_nick_regex
;
415 dict_t weak_password_dict
;
416 struct policer_params
*auth_policer_params
;
417 enum reclaim_action reclaim_action
;
418 enum reclaim_action auto_reclaim_action
;
419 unsigned long auto_reclaim_delay
;
420 unsigned char default_maxlogins
;
421 unsigned char hard_maxlogins
;
422 const char *auto_oper
;
423 const char *auto_admin
;
425 struct string_list
*denied_fakehost_words
;
428 /* We have 2^32 unique account IDs to use. */
429 unsigned long int highest_id
= 0;
432 canonicalize_hostmask(char *mask
)
434 char *out
= mask
, *temp
;
435 if ((temp
= strchr(mask
, '!'))) {
437 while (*temp
) *out
++ = *temp
++;
443 static struct handle_note
*
444 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
446 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
448 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
450 memcpy(note
->note
, text
, strlen(text
));
454 static struct handle_info
*
455 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
457 struct handle_info
*hi
;
459 #ifdef WITH_PROTOCOL_BAHAMUT
460 char id_base64
[IDLEN
+ 1];
463 /* Assign a unique account ID to the account; note that 0 is
464 an invalid account ID. 1 is therefore the first account ID. */
466 id
= 1 + highest_id
++;
468 /* Note: highest_id is and must always be the highest ID. */
469 if(id
> highest_id
) {
473 inttobase64(id_base64
, id
, IDLEN
);
475 /* Make sure an account with the same ID doesn't exist. If a
476 duplicate is found, log some details and assign a new one.
477 This should be impossible, but it never hurts to expect it. */
478 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
479 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
485 hi
= calloc(1, sizeof(*hi
));
486 hi
->userlist_style
= HI_DEFAULT_STYLE
;
487 hi
->announcements
= '?';
488 hi
->handle
= strdup(handle
);
489 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
491 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
493 #ifdef WITH_PROTOCOL_BAHAMUT
495 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
502 register_nick(const char *nick
, struct handle_info
*owner
)
504 struct nick_info
*ni
;
505 ni
= malloc(sizeof(struct nick_info
));
506 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
508 ni
->next
= owner
->nicks
;
510 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
514 delete_nick(struct nick_info
*ni
)
516 struct nick_info
*last
, *next
;
517 struct userNode
*user
;
518 /* Check to see if we should mark a user as unregistered. */
519 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
520 user
->modes
&= ~FLAGS_REGNICK
;
523 /* Remove ni from the nick_info linked list. */
524 if (ni
== ni
->owner
->nicks
) {
525 ni
->owner
->nicks
= ni
->next
;
527 last
= ni
->owner
->nicks
;
533 last
->next
= next
->next
;
535 dict_remove(nickserv_nick_dict
, ni
->nick
);
538 static unreg_func_t
*unreg_func_list
;
539 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
542 reg_unreg_func(unreg_func_t func
)
544 if (unreg_func_used
== unreg_func_size
) {
545 if (unreg_func_size
) {
546 unreg_func_size
<<= 1;
547 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
550 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
553 unreg_func_list
[unreg_func_used
++] = func
;
557 nickserv_free_cookie(void *data
)
559 struct handle_cookie
*cookie
= data
;
560 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
561 if (cookie
->data
) free(cookie
->data
);
566 free_handle_info(void *vhi
)
568 struct handle_info
*hi
= vhi
;
570 #ifdef WITH_PROTOCOL_BAHAMUT
573 inttobase64(id
, hi
->id
, IDLEN
);
574 dict_remove(nickserv_id_dict
, id
);
577 free_string_list(hi
->masks
);
578 free_string_list(hi
->ignores
);
582 delete_nick(hi
->nicks
);
588 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
589 nickserv_free_cookie(hi
->cookie
);
591 if (hi
->email_addr
) {
592 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
593 handle_info_list_remove(hil
, hi
);
595 dict_remove(nickserv_email_dict
, hi
->email_addr
);
600 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
603 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
606 struct userNode
*uNode
;
608 for (n
=0; n
<unreg_func_used
; n
++)
609 unreg_func_list
[n
](notify
, hi
);
611 if (nickserv_conf
.sync_log
) {
612 uNode
= GetUserH(hi
->users
->nick
);
616 set_user_handle_info(hi
->users
, NULL
, 0);
619 if (nickserv_conf
.disable_nicks
)
620 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
622 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
625 if (nickserv_conf
.sync_log
)
626 SyncLog("UNREGISTER %s", hi
->handle
);
628 dict_remove(nickserv_handle_dict
, hi
->handle
);
632 get_handle_info(const char *handle
)
634 return dict_find(nickserv_handle_dict
, handle
, 0);
638 get_nick_info(const char *nick
)
640 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
644 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
649 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
650 mn
= channel
->members
.list
[nn
];
651 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
658 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
659 if (!user
->handle_info
) {
661 send_message(user
, bot
, "MSG_AUTHENTICATE");
665 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
667 send_message(user
, bot
, "NSMSG_NO_ACCESS");
671 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
673 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
677 if (user
->handle_info
->opserv_level
< min_level
) {
679 send_message(user
, bot
, "NSMSG_NO_ACCESS");
687 is_valid_handle(const char *handle
)
689 struct userNode
*user
;
690 /* cant register a juped nick/service nick as handle, to prevent confusion */
691 user
= GetUserH(handle
);
692 if (user
&& IsLocal(user
))
694 /* check against maximum length */
695 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
697 /* for consistency, only allow account names that could be nicks */
698 if (!is_valid_nick(handle
))
700 /* disallow account names that look like bad words */
701 if (opserv_bad_channel(handle
))
703 /* test either regex or containing all valid chars */
704 if (nickserv_conf
.valid_handle_regex_set
) {
705 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
708 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
709 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
713 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
718 is_registerable_nick(const char *nick
)
720 /* make sure it could be used as an account name */
721 if (!is_valid_handle(nick
))
724 if (strlen(nick
) > NICKLEN
)
726 /* test either regex or as valid handle */
727 if (nickserv_conf
.valid_nick_regex_set
) {
728 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
731 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
732 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
738 /* this has been replaced with one in tools.c
741 is_valid_email_addr(const char *email)
743 return strchr(email, '@') != NULL;
749 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
751 if (hi
->email_addr
) {
752 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
753 return hi
->email_addr
;
763 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
765 struct handle_info
*hi
;
766 struct userNode
*target
;
770 if (!(hi
= get_handle_info(++name
))) {
771 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
776 if (!(target
= GetUserH(name
))) {
777 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
780 if (IsLocal(target
)) {
781 if (IsService(target
))
782 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
784 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
787 if (!(hi
= target
->handle_info
)) {
788 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
796 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
797 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
799 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
800 if ((user
->handle_info
->opserv_level
== 1000)
801 || (user
->handle_info
== hi
)
802 || ((user
->handle_info
->opserv_level
== 0)
803 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
804 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
808 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
812 static struct handle_info
*
813 get_victim_oper(struct userNode
*user
, const char *target
)
815 struct handle_info
*hi
;
816 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
818 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
819 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
822 return oper_outranks(user
, hi
) ? hi
: NULL
;
826 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
830 /* If no hostmasks on the account, allow it. */
831 if (!hi
->masks
->used
)
833 /* If any hostmask matches, allow it. */
834 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
835 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
837 /* If they are allowauthed to this account, allow it (removing the aa). */
838 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
839 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
842 /* The user is not allowed to use this account. */
847 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
850 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
854 if (len
< nickserv_conf
.password_min_length
) {
856 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
859 if (!irccasecmp(pass
, handle
)) {
861 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
864 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
867 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
870 for (i
=0; i
<len
; i
++) {
871 if (isdigit(pass
[i
]))
873 if (isupper(pass
[i
]))
875 if (islower(pass
[i
]))
878 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
879 || (cnt_upper
< nickserv_conf
.password_min_upper
)
880 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
882 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
888 static auth_func_t
*auth_func_list
;
889 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
892 reg_auth_func(auth_func_t func
)
894 if (auth_func_used
== auth_func_size
) {
895 if (auth_func_size
) {
896 auth_func_size
<<= 1;
897 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
900 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
903 auth_func_list
[auth_func_used
++] = func
;
906 static handle_rename_func_t
*rf_list
;
907 static unsigned int rf_list_size
, rf_list_used
;
910 reg_handle_rename_func(handle_rename_func_t func
)
912 if (rf_list_used
== rf_list_size
) {
915 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
918 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
921 rf_list
[rf_list_used
++] = func
;
925 generate_fakehost(struct handle_info
*handle
)
927 extern const char *hidden_host_suffix
;
928 static char buffer
[HOSTLEN
+1];
930 if (!handle
->fakehost
) {
931 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
933 } else if (handle
->fakehost
[0] == '.') {
934 /* A leading dot indicates the stored value is actually a title. */
935 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
938 return handle
->fakehost
;
942 apply_fakehost(struct handle_info
*handle
)
944 struct userNode
*target
;
949 fake
= generate_fakehost(handle
);
950 for (target
= handle
->users
; target
; target
= target
->next_authed
)
951 assign_fakehost(target
, fake
, 1);
954 void send_func_list(struct userNode
*user
)
957 struct handle_info
*old_info
;
959 old_info
= user
->handle_info
;
961 for (n
=0; n
<auth_func_used
; n
++)
962 auth_func_list
[n
](user
, old_info
);
966 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
969 struct handle_info
*old_info
;
971 /* This can happen if somebody uses COOKIE while authed, or if
972 * they re-auth to their current handle (which is silly, but users
974 if (user
->handle_info
== hi
)
977 if (user
->handle_info
) {
978 struct userNode
*other
;
981 userList_remove(&curr_helpers
, user
);
983 /* remove from next_authed linked list */
984 if (user
->handle_info
->users
== user
) {
985 user
->handle_info
->users
= user
->next_authed
;
987 for (other
= user
->handle_info
->users
;
988 other
->next_authed
!= user
;
989 other
= other
->next_authed
) ;
990 other
->next_authed
= user
->next_authed
;
992 /* if nobody left on old handle, and they're not an oper, remove !god */
993 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
994 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
995 /* record them as being last seen at this time */
996 user
->handle_info
->lastseen
= now
;
997 /* and record their hostmask */
998 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
1000 old_info
= user
->handle_info
;
1001 user
->handle_info
= hi
;
1002 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
1003 HANDLE_CLEAR_FLAG(hi
, HELPING
);
1005 if (GetUserH(user
->nick
)) {
1006 for (n
=0; n
<auth_func_used
; n
++)
1007 auth_func_list
[n
](user
, old_info
);
1012 struct nick_info
*ni
;
1014 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
1015 if (nickserv_conf
.warn_clone_auth
) {
1016 struct userNode
*other
;
1017 for (other
= hi
->users
; other
; other
= other
->next_authed
)
1018 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1021 user
->next_authed
= hi
->users
;
1025 userList_append(&curr_helpers
, user
);
1027 if (hi
->fakehost
|| old_info
)
1031 #ifdef WITH_PROTOCOL_BAHAMUT
1032 /* Stamp users with their account ID. */
1034 inttobase64(id
, hi
->id
, IDLEN
);
1035 #elif WITH_PROTOCOL_P10
1036 /* Stamp users with their account name. */
1037 char *id
= hi
->handle
;
1039 const char *id
= "???";
1041 if (!nickserv_conf
.disable_nicks
) {
1042 struct nick_info
*ni
;
1043 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
1044 if (!irccasecmp(user
->nick
, ni
->nick
)) {
1045 user
->modes
|= FLAGS_REGNICK
;
1050 StampUser(user
, id
, hi
->registered
);
1053 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1054 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1056 /* We cannot clear the user's account ID, unfortunately. */
1057 user
->next_authed
= NULL
;
1061 static struct handle_info
*
1062 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1064 struct handle_info
*hi
;
1065 struct nick_info
*ni
;
1066 char crypted
[MD5_CRYPT_LENGTH
];
1068 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1069 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1073 if(strlen(handle
) > 15)
1075 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1079 if (!is_secure_password(handle
, passwd
, user
))
1082 cryptpass(passwd
, crypted
);
1083 hi
= register_handle(handle
, crypted
, 0);
1084 hi
->masks
= alloc_string_list(1);
1085 hi
->ignores
= alloc_string_list(1);
1087 hi
->language
= lang_C
;
1088 hi
->registered
= now
;
1090 hi
->flags
= HI_DEFAULT_FLAGS
;
1091 if (settee
&& !no_auth
)
1092 set_user_handle_info(settee
, hi
, 1);
1095 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1096 else if (nickserv_conf
.disable_nicks
)
1097 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1098 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1099 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1101 register_nick(user
->nick
, hi
);
1102 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1104 if (settee
&& (user
!= settee
))
1105 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1110 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1112 cookie
->hi
->cookie
= cookie
;
1113 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1116 /* Contributed by the great sneep of afternet ;) */
1117 /* Since this gets used in a URL, we want to avoid stuff that confuses
1118 * email clients such as ] and ?. a-z, 0-9 only.
1120 void genpass(char *str
, int len
)
1125 for(i
= 0; i
< len
; i
++)
1129 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1130 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1138 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1140 struct handle_cookie
*cookie
;
1141 char subject
[128], body
[4096], *misc
;
1142 const char *netname
, *fmt
;
1146 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1150 cookie
= calloc(1, sizeof(*cookie
));
1152 cookie
->type
= type
;
1153 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1155 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1156 /* Adding dedicated password gen function for more control -Rubin */
1157 genpass(cookie
->cookie
, 10);
1159 *inttobase64(cookie->cookie, rand(), 5);
1160 *inttobase64(cookie->cookie+5, rand(), 5);
1163 netname
= nickserv_conf
.network_name
;
1166 switch (cookie
->type
) {
1168 hi
->passwd
[0] = 0; /* invalidate password */
1169 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1170 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1171 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1174 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1176 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1178 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1181 case PASSWORD_CHANGE
:
1182 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1183 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1184 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1186 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1188 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1189 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1192 misc
= hi
->email_addr
;
1193 hi
->email_addr
= cookie
->data
;
1194 #ifdef stupid_verify_old_email
1196 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1197 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1198 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1199 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1200 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1201 sendmail(nickserv
, hi
, subject
, body
, 1);
1202 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1203 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1206 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1207 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1208 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1209 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1210 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1211 sendmail(nickserv
, hi
, subject
, body
, 1);
1213 #ifdef stupid_verify_old_email
1216 hi
->email_addr
= misc
;
1219 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1220 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1221 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1222 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1223 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1226 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1230 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1231 nickserv_bake_cookie(cookie
);
1235 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1237 cookie
->hi
->cookie
= NULL
;
1238 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1239 nickserv_free_cookie(cookie
);
1243 nickserv_free_email_addr(void *data
)
1245 handle_info_list_clean(data
);
1250 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1252 struct handle_info_list
*hil
;
1253 /* Remove from old handle_info_list ... */
1254 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1255 handle_info_list_remove(hil
, hi
);
1256 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1257 hi
->email_addr
= NULL
;
1259 /* Add to the new list.. */
1260 if (new_email_addr
) {
1261 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1262 hil
= calloc(1, sizeof(*hil
));
1263 hil
->tag
= strdup(new_email_addr
);
1264 handle_info_list_init(hil
);
1265 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1267 handle_info_list_append(hil
, hi
);
1268 hi
->email_addr
= hil
->tag
;
1272 static NICKSERV_FUNC(cmd_register
)
1275 struct handle_info
*hi
;
1276 const char *email_addr
, *password
;
1277 char syncpass
[MD5_CRYPT_LENGTH
];
1278 int no_auth
, weblink
;
1280 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1281 /* Require the first handle registered to belong to someone +o. */
1282 reply("NSMSG_REQUIRE_OPER");
1286 if (user
->handle_info
) {
1287 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1291 if (IsRegistering(user
)) {
1292 reply("NSMSG_ALREADY_REGISTERING");
1296 if (IsStamped(user
)) {
1297 /* Unauthenticated users might still have been stamped
1298 previously and could therefore have a hidden host;
1299 do not allow them to register a new account. */
1300 reply("NSMSG_STAMPED_REGISTER");
1304 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1306 if (!is_valid_handle(argv
[1])) {
1307 reply("NSMSG_BAD_HANDLE", argv
[1]);
1312 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1313 struct handle_info_list
*hil
;
1316 /* Remember email address. */
1317 email_addr
= argv
[3];
1319 /* Check that the email address looks valid.. */
1320 if (!valid_email(email_addr
)) {
1321 reply("NSMSG_BAD_EMAIL_ADDR");
1325 /* .. and that we are allowed to send to it. */
1326 if ((str
= sendmail_prohibited_address(email_addr
))) {
1327 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1331 /* If we do email verify, make sure we don't spam the address. */
1332 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1334 for (nn
=0; nn
<hil
->used
; nn
++) {
1335 if (hil
->list
[nn
]->cookie
) {
1336 reply("NSMSG_EMAIL_UNACTIVATED");
1340 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1341 reply("NSMSG_EMAIL_OVERUSED");
1354 /* Webregister hack - send URL instead of IRC cookie
1357 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1361 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1363 /* Add any masks they should get. */
1364 if (nickserv_conf
.default_hostmask
) {
1365 string_list_append(hi
->masks
, strdup("*@*"));
1367 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1368 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1369 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1372 /* If they're the first to register, give them level 1000. */
1373 if (dict_size(nickserv_handle_dict
) == 1) {
1374 hi
->opserv_level
= 1000;
1375 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1378 /* Set their email address. */
1380 nickserv_set_email_addr(hi
, email_addr
);
1382 /* If they need to do email verification, tell them. */
1384 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1386 /* Set registering flag.. */
1387 user
->modes
|= FLAGS_REGISTERING
;
1389 if (nickserv_conf
.sync_log
) {
1390 cryptpass(password
, syncpass
);
1392 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1393 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1396 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1399 /* this wont work if email is required .. */
1400 process_adduser_pending(user
);
1405 static NICKSERV_FUNC(cmd_oregister
)
1408 struct userNode
*settee
;
1409 struct handle_info
*hi
;
1411 NICKSERV_MIN_PARMS(nickserv_conf
.email_required
? 4 : 3);
1413 if (!is_valid_handle(argv
[1])) {
1414 reply("NSMSG_BAD_HANDLE", argv
[1]);
1418 if (nickserv_conf
.email_required
) {
1419 if (!valid_email(argv
[4])) {
1420 reply("NSMSG_BAD_EMAIL_ADDR");
1425 if (strchr(argv
[3], '@')) {
1426 mask
= canonicalize_hostmask(strdup(argv
[3]));
1428 settee
= GetUserH(nickserv_conf
.email_required
? argv
[5] : argv
[4]);
1430 reply("MSG_NICK_UNKNOWN", nickserv_conf
.email_required
? argv
[5] : argv
[4]);
1437 } else if ((settee
= GetUserH(argv
[3]))) {
1438 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1440 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1443 if (settee
&& settee
->handle_info
) {
1444 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1448 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1449 if (nickserv_conf
.email_required
) {
1450 nickserv_set_email_addr(hi
, argv
[4]);
1451 if (nickserv_conf
.sync_log
)
1452 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, argv
[4], user
->info
);
1457 string_list_append(hi
->masks
, mask
);
1462 nickserv_ignore(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
1465 struct userNode
*target
;
1466 char *new_mask
= canonicalize_hostmask(strdup(mask
));
1467 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1468 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1469 send_message(user
, nickserv
, "NSMSG_ADDIGNORE_ALREADY", new_mask
);
1474 string_list_append(hi
->ignores
, new_mask
);
1475 send_message(user
, nickserv
, "NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1477 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1478 irc_silence(target
, new_mask
, 1);
1483 static NICKSERV_FUNC(cmd_addignore
)
1485 NICKSERV_MIN_PARMS(2);
1487 return nickserv_ignore(user
, user
->handle_info
, argv
[1]);
1490 static NICKSERV_FUNC(cmd_oaddignore
)
1492 struct handle_info
*hi
;
1494 NICKSERV_MIN_PARMS(3);
1495 if (!(hi
= get_victim_oper(user
, argv
[1])))
1497 return nickserv_ignore(user
, hi
, argv
[2]);
1501 nickserv_delignore(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
1504 struct userNode
*target
;
1505 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1506 if (!strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1507 char *old_mask
= hi
->ignores
->list
[i
];
1508 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1509 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
1510 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1511 irc_silence(user
, old_mask
, 0);
1517 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
1521 static NICKSERV_FUNC(cmd_delignore
)
1523 NICKSERV_MIN_PARMS(2);
1524 return nickserv_delignore(user
, user
->handle_info
, argv
[1]);
1527 static NICKSERV_FUNC(cmd_odelignore
)
1529 struct handle_info
*hi
;
1530 NICKSERV_MIN_PARMS(3);
1531 if (!(hi
= get_victim_oper(user
, argv
[1])))
1533 return nickserv_delignore(user
, hi
, argv
[2]);
1536 static NICKSERV_FUNC(cmd_handleinfo
)
1539 unsigned int i
, pos
=0, herelen
;
1540 struct userNode
*target
, *next_un
;
1541 struct handle_info
*hi
;
1542 const char *nsmsg_none
;
1545 if (!(hi
= user
->handle_info
)) {
1546 reply("NSMSG_MUST_AUTH");
1549 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1553 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1554 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1556 #ifdef WITH_PROTOCOL_BAHAMUT
1557 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1559 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1562 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1563 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1565 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1568 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1569 if (HANDLE_FLAGGED(hi
, FROZEN
))
1570 reply("NSMSG_HANDLEINFO_VACATION");
1572 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1573 struct do_not_register
*dnr
;
1574 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1575 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1576 if (!oper_outranks(user
, hi
))
1578 } else if (hi
!= user
->handle_info
) {
1579 reply("NSMSG_HANDLEINFO_END");
1583 if (nickserv_conf
.email_enabled
)
1584 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1588 switch (hi
->cookie
->type
) {
1589 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1590 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1591 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1592 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1593 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1599 unsigned long flen
= 1;
1600 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1602 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1603 if (hi
->flags
& 1 << i
)
1604 flags
[flen
++] = handle_flags
[i
];
1606 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1608 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1611 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1612 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1613 || (hi
->opserv_level
> 0)) {
1614 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1617 if (IsHelping(user
) || IsOper(user
))
1622 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1623 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1628 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1630 if (hi
->last_quit_host
[0])
1631 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1633 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1635 if (nickserv_conf
.disable_nicks
) {
1636 /* nicks disabled; don't show anything about registered nicks */
1637 } else if (hi
->nicks
) {
1638 struct nick_info
*ni
, *next_ni
;
1639 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1640 herelen
= strlen(ni
->nick
);
1641 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1643 goto print_nicks_buff
;
1647 memcpy(buff
+pos
, ni
->nick
, herelen
);
1648 pos
+= herelen
; buff
[pos
++] = ' ';
1652 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1657 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1660 if (hi
->masks
->used
) {
1661 for (i
=0; i
< hi
->masks
->used
; i
++) {
1662 herelen
= strlen(hi
->masks
->list
[i
]);
1663 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1665 goto print_mask_buff
;
1667 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1668 pos
+= herelen
; buff
[pos
++] = ' ';
1669 if (i
+1 == hi
->masks
->used
) {
1672 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1677 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1680 if (hi
->ignores
->used
) {
1681 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1682 herelen
= strlen(hi
->ignores
->list
[i
]);
1683 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1685 goto print_ignore_buff
;
1687 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1688 pos
+= herelen
; buff
[pos
++] = ' ';
1689 if (i
+1 == hi
->ignores
->used
) {
1692 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1697 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1701 struct userData
*channel
, *next
;
1704 for (channel
= hi
->channels
; channel
; channel
= next
) {
1705 next
= channel
->u_next
;
1706 name
= channel
->channel
->channel
->name
;
1707 herelen
= strlen(name
);
1708 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1710 goto print_chans_buff
;
1712 if (IsUserSuspended(channel
))
1714 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1718 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1723 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1726 for (target
= hi
->users
; target
; target
= next_un
) {
1727 herelen
= strlen(target
->nick
);
1728 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1730 goto print_cnick_buff
;
1732 next_un
= target
->next_authed
;
1734 memcpy(buff
+pos
, target
->nick
, herelen
);
1735 pos
+= herelen
; buff
[pos
++] = ' ';
1739 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1744 reply("NSMSG_HANDLEINFO_END");
1748 static NICKSERV_FUNC(cmd_userinfo
)
1750 struct userNode
*target
;
1752 NICKSERV_MIN_PARMS(2);
1753 if (!(target
= GetUserH(argv
[1]))) {
1754 reply("MSG_NICK_UNKNOWN", argv
[1]);
1757 if (target
->handle_info
)
1758 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1760 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1764 static NICKSERV_FUNC(cmd_nickinfo
)
1766 struct nick_info
*ni
;
1768 NICKSERV_MIN_PARMS(2);
1769 if (!(ni
= get_nick_info(argv
[1]))) {
1770 reply("MSG_NICK_UNKNOWN", argv
[1]);
1773 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1777 static NICKSERV_FUNC(cmd_rename_handle
)
1779 struct handle_info
*hi
;
1780 struct userNode
*uNode
;
1781 char msgbuf
[MAXLEN
], *old_handle
;
1784 NICKSERV_MIN_PARMS(3);
1785 if (!(hi
= get_victim_oper(user
, argv
[1])))
1787 if (!is_valid_handle(argv
[2])) {
1788 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1791 if (get_handle_info(argv
[2])) {
1792 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1795 if(strlen(argv
[2]) > 15)
1797 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1801 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1802 hi
->handle
= strdup(argv
[2]);
1803 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1804 for (nn
=0; nn
<rf_list_used
; nn
++)
1805 rf_list
[nn
](hi
, old_handle
);
1806 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1809 if (nickserv_conf
.sync_log
) {
1810 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1811 irc_rename(uNode
, hi
->handle
);
1813 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1816 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1817 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1822 static failpw_func_t
*failpw_func_list
;
1823 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1826 reg_failpw_func(failpw_func_t func
)
1828 if (failpw_func_used
== failpw_func_size
) {
1829 if (failpw_func_size
) {
1830 failpw_func_size
<<= 1;
1831 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1833 failpw_func_size
= 8;
1834 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1837 failpw_func_list
[failpw_func_used
++] = func
;
1841 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1843 * called by nefariouses enhanced AC login-on-connect code
1846 struct handle_info
*loc_auth(char *handle
, char *password
)
1848 int pw_arg
, used
, maxlogins
;
1851 struct handle_info
*hi
;
1852 struct userNode
*other
;
1854 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1860 /* We don't know the users hostname, or anything because they
1861 * havn't registered yet. So we can only allow LOC if your
1862 * account has *@* as a hostmask.
1864 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1866 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1875 /* Responses from here on look up the language used by the handle they asked about. */
1876 if (!checkpass(password
, hi
->passwd
)) {
1879 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1882 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1883 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1884 if (++used
>= maxlogins
) {
1891 static NICKSERV_FUNC(cmd_auth
)
1893 int pw_arg
, used
, maxlogins
;
1894 struct handle_info
*hi
;
1896 struct userNode
*other
;
1898 if (user
->handle_info
) {
1899 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1902 if (IsStamped(user
)) {
1903 /* Unauthenticated users might still have been stamped
1904 previously and could therefore have a hidden host;
1905 do not allow them to authenticate. */
1906 reply("NSMSG_STAMPED_AUTH");
1910 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1912 } else if (argc
== 2) {
1913 if (nickserv_conf
.disable_nicks
) {
1914 if (!(hi
= get_handle_info(user
->nick
))) {
1915 reply("NSMSG_HANDLE_NOT_FOUND");
1919 /* try to look up their handle from their nick */
1920 struct nick_info
*ni
;
1921 ni
= get_nick_info(user
->nick
);
1923 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1930 reply("MSG_MISSING_PARAMS", argv
[0]);
1931 svccmd_send_help_brief(user
, nickserv
, cmd
);
1935 reply("NSMSG_HANDLE_NOT_FOUND");
1938 /* Responses from here on look up the language used by the handle they asked about. */
1939 passwd
= argv
[pw_arg
];
1940 if (!valid_user_for(user
, hi
)) {
1941 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1942 send_message_type(4, user
, cmd
->parent
->bot
,
1943 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1946 send_message_type(4, user
, cmd
->parent
->bot
,
1947 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1949 argv
[pw_arg
] = "BADMASK";
1952 if (!checkpass(passwd
, hi
->passwd
)) {
1954 send_message_type(4, user
, cmd
->parent
->bot
,
1955 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1956 argv
[pw_arg
] = "BADPASS";
1957 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1958 if (nickserv_conf
.autogag_enabled
) {
1959 if (!user
->auth_policer
.params
) {
1960 user
->auth_policer
.last_req
= now
;
1961 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1963 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1965 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1966 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1967 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1969 argv
[pw_arg
] = "GAGGED";
1974 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1975 send_message_type(4, user
, cmd
->parent
->bot
,
1976 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1977 argv
[pw_arg
] = "SUSPENDED";
1980 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1981 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1982 if (++used
>= maxlogins
) {
1983 send_message_type(4, user
, cmd
->parent
->bot
,
1984 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1986 argv
[pw_arg
] = "MAXLOGINS";
1991 set_user_handle_info(user
, hi
, 1);
1992 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1993 reply("NSMSG_PLEASE_SET_EMAIL");
1994 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1995 reply("NSMSG_WEAK_PASSWORD");
1996 if (hi
->passwd
[0] != '$')
1997 cryptpass(passwd
, hi
->passwd
);
1999 /* If a channel was waiting for this user to auth,
2000 * finish adding them */
2001 process_adduser_pending(user
);
2003 reply("NSMSG_AUTH_SUCCESS");
2006 /* Set +x if autohide is on */
2007 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2008 irc_umode(user
, "+x");
2010 if(!IsOper(user
)) /* If they arnt already opered.. */
2012 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2013 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
2015 irc_umode(user
,nickserv_conf
.auto_admin
);
2016 reply("NSMSG_AUTO_OPER_ADMIN");
2018 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
2020 irc_umode(user
,nickserv_conf
.auto_oper
);
2021 reply("NSMSG_AUTO_OPER");
2025 /* Wipe out the pass for the logs */
2026 argv
[pw_arg
] = "****";
2030 static allowauth_func_t
*allowauth_func_list
;
2031 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2034 reg_allowauth_func(allowauth_func_t func
)
2036 if (allowauth_func_used
== allowauth_func_size
) {
2037 if (allowauth_func_size
) {
2038 allowauth_func_size
<<= 1;
2039 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2041 allowauth_func_size
= 8;
2042 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2045 allowauth_func_list
[allowauth_func_used
++] = func
;
2048 static NICKSERV_FUNC(cmd_allowauth
)
2050 struct userNode
*target
;
2051 struct handle_info
*hi
;
2054 NICKSERV_MIN_PARMS(2);
2055 if (!(target
= GetUserH(argv
[1]))) {
2056 reply("MSG_NICK_UNKNOWN", argv
[1]);
2059 if (target
->handle_info
) {
2060 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2063 if (IsStamped(target
)) {
2064 /* Unauthenticated users might still have been stamped
2065 previously and could therefore have a hidden host;
2066 do not allow them to authenticate to an account. */
2067 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2072 else if (!(hi
= get_handle_info(argv
[2]))) {
2073 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2077 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2078 reply("MSG_USER_OUTRANKED", hi
->handle
);
2081 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2082 || (hi
->opserv_level
> 0))
2083 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2084 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2087 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2088 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2089 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2090 if (nickserv_conf
.email_enabled
)
2091 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2093 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2094 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2096 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2098 for (n
=0; n
<allowauth_func_used
; n
++)
2099 allowauth_func_list
[n
](user
, target
, hi
);
2103 static NICKSERV_FUNC(cmd_authcookie
)
2105 struct handle_info
*hi
;
2107 NICKSERV_MIN_PARMS(2);
2108 if (user
->handle_info
) {
2109 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2112 if (IsStamped(user
)) {
2113 /* Unauthenticated users might still have been stamped
2114 previously and could therefore have a hidden host;
2115 do not allow them to authenticate to an account. */
2116 reply("NSMSG_STAMPED_AUTHCOOKIE");
2119 if (!(hi
= get_handle_info(argv
[1]))) {
2120 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2123 if (!hi
->email_addr
) {
2124 reply("MSG_SET_EMAIL_ADDR");
2127 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2131 static NICKSERV_FUNC(cmd_delcookie
)
2133 struct handle_info
*hi
;
2135 hi
= user
->handle_info
;
2137 reply("NSMSG_NO_COOKIE");
2140 switch (hi
->cookie
->type
) {
2143 reply("NSMSG_MUST_TIME_OUT");
2146 nickserv_eat_cookie(hi
->cookie
);
2147 reply("NSMSG_ATE_COOKIE");
2153 static NICKSERV_FUNC(cmd_odelcookie
)
2155 struct handle_info
*hi
;
2157 NICKSERV_MIN_PARMS(2);
2159 if (!(hi
= get_victim_oper(user
, argv
[1])))
2163 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2167 nickserv_eat_cookie(hi
->cookie
);
2168 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2173 static NICKSERV_FUNC(cmd_resetpass
)
2175 struct handle_info
*hi
;
2176 char crypted
[MD5_CRYPT_LENGTH
];
2179 NICKSERV_MIN_PARMS(3);
2180 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2184 if (user
->handle_info
) {
2185 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2188 if (IsStamped(user
)) {
2189 /* Unauthenticated users might still have been stamped
2190 previously and could therefore have a hidden host;
2191 do not allow them to activate an account. */
2192 reply("NSMSG_STAMPED_RESETPASS");
2195 if (!(hi
= get_handle_info(argv
[1]))) {
2196 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2199 if (!hi
->email_addr
) {
2200 reply("MSG_SET_EMAIL_ADDR");
2203 cryptpass(argv
[2], crypted
);
2205 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2209 static NICKSERV_FUNC(cmd_cookie
)
2211 struct handle_info
*hi
;
2214 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2217 NICKSERV_MIN_PARMS(3);
2218 if (!(hi
= get_handle_info(argv
[1]))) {
2219 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2225 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2226 reply("NSMSG_HANDLE_SUSPENDED");
2231 reply("NSMSG_NO_COOKIE");
2235 /* Check validity of operation before comparing cookie to
2236 * prohibit guessing by authed users. */
2237 if (user
->handle_info
2238 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2239 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2240 reply("NSMSG_CANNOT_COOKIE");
2244 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2245 reply("NSMSG_BAD_COOKIE");
2249 switch (hi
->cookie
->type
) {
2251 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2252 set_user_handle_info(user
, hi
, 1);
2253 reply("NSMSG_HANDLE_ACTIVATED");
2254 if (nickserv_conf
.sync_log
)
2255 SyncLog("ACCOUNTACC %s", hi
->handle
);
2257 case PASSWORD_CHANGE
:
2258 set_user_handle_info(user
, hi
, 1);
2259 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2260 reply("NSMSG_PASSWORD_CHANGED");
2261 if (nickserv_conf
.sync_log
)
2262 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2265 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2267 * This should only happen if an OREGISTER was sent. Require
2268 * email must be enabled! - SiRVulcaN
2270 if (nickserv_conf
.sync_log
)
2271 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2273 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2274 reply("NSMSG_EMAIL_CHANGED");
2275 if (nickserv_conf
.sync_log
)
2276 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2279 set_user_handle_info(user
, hi
, 1);
2280 reply("NSMSG_AUTH_SUCCESS");
2283 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2284 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2288 nickserv_eat_cookie(hi
->cookie
);
2290 process_adduser_pending(user
);
2295 static NICKSERV_FUNC(cmd_oregnick
) {
2297 struct handle_info
*target
;
2298 struct nick_info
*ni
;
2300 NICKSERV_MIN_PARMS(3);
2301 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2304 if (!is_registerable_nick(nick
)) {
2305 reply("NSMSG_BAD_NICK", nick
);
2308 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2310 reply("NSMSG_NICK_EXISTS", nick
);
2313 register_nick(nick
, target
);
2314 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2318 static NICKSERV_FUNC(cmd_regnick
) {
2320 struct nick_info
*ni
;
2322 if (!is_registerable_nick(user
->nick
)) {
2323 reply("NSMSG_BAD_NICK", user
->nick
);
2326 /* count their nicks, see if it's too many */
2327 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2328 if (n
>= nickserv_conf
.nicks_per_handle
) {
2329 reply("NSMSG_TOO_MANY_NICKS");
2332 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2334 reply("NSMSG_NICK_EXISTS", user
->nick
);
2337 register_nick(user
->nick
, user
->handle_info
);
2338 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2342 static NICKSERV_FUNC(cmd_pass
)
2344 struct handle_info
*hi
;
2345 const char *old_pass
, *new_pass
;
2347 NICKSERV_MIN_PARMS(3);
2348 hi
= user
->handle_info
;
2352 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2353 if (!checkpass(old_pass
, hi
->passwd
)) {
2354 argv
[1] = "BADPASS";
2355 reply("NSMSG_PASSWORD_INVALID");
2358 cryptpass(new_pass
, hi
->passwd
);
2359 if (nickserv_conf
.sync_log
)
2360 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2362 reply("NSMSG_PASS_SUCCESS");
2367 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2370 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2371 for (i
=0; i
<hi
->masks
->used
; i
++) {
2372 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2373 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2378 string_list_append(hi
->masks
, new_mask
);
2379 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2383 static NICKSERV_FUNC(cmd_addmask
)
2386 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2387 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2391 if (!is_gline(argv
[1])) {
2392 reply("NSMSG_MASK_INVALID", argv
[1]);
2395 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2399 static NICKSERV_FUNC(cmd_oaddmask
)
2401 struct handle_info
*hi
;
2403 NICKSERV_MIN_PARMS(3);
2404 if (!(hi
= get_victim_oper(user
, argv
[1])))
2406 return nickserv_addmask(user
, hi
, argv
[2]);
2410 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2413 for (i
=0; i
<hi
->masks
->used
; i
++) {
2414 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2415 char *old_mask
= hi
->masks
->list
[i
];
2416 if (hi
->masks
->used
== 1) {
2417 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2420 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2421 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2426 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2430 static NICKSERV_FUNC(cmd_delmask
)
2432 NICKSERV_MIN_PARMS(2);
2433 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2436 static NICKSERV_FUNC(cmd_odelmask
)
2438 struct handle_info
*hi
;
2439 NICKSERV_MIN_PARMS(3);
2440 if (!(hi
= get_victim_oper(user
, argv
[1])))
2442 return nickserv_delmask(user
, hi
, argv
[2]);
2446 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2447 unsigned int nn
, add
= 1, pos
;
2448 unsigned long added
, removed
, flag
;
2450 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2452 case '+': add
= 1; break;
2453 case '-': add
= 0; break;
2455 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2456 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2459 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2460 /* cheesy avoidance of looking up the flag name.. */
2461 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2464 flag
= 1 << (pos
- 1);
2466 added
|= flag
, removed
&= ~flag
;
2468 removed
|= flag
, added
&= ~flag
;
2473 *premoved
= removed
;
2478 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2480 unsigned long before
, after
, added
, removed
;
2481 struct userNode
*uNode
;
2483 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2484 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2486 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2487 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2489 /* Strip helping flag if they're only a support helper and not
2490 * currently in #support. */
2491 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2492 struct channelList
*schannels
;
2494 schannels
= chanserv_support_channels();
2495 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2496 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2497 if (GetUserMode(schannels
->list
[ii
], uNode
))
2499 if (ii
< schannels
->used
)
2503 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2506 if (after
&& !before
) {
2507 /* Add user to current helper list. */
2508 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2509 userList_append(&curr_helpers
, uNode
);
2510 } else if (!after
&& before
) {
2511 /* Remove user from current helper list. */
2512 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2513 userList_remove(&curr_helpers
, uNode
);
2520 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2524 char *set_display
[] = {
2525 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2526 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2527 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2530 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2531 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_HEADER");
2533 /* Do this so options are presented in a consistent order. */
2534 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2535 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2536 opt(user
, hi
, override
, 0, NULL
);
2537 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_END");
2540 static NICKSERV_FUNC(cmd_set
)
2542 struct handle_info
*hi
;
2545 hi
= user
->handle_info
;
2547 set_list(user
, hi
, 0);
2550 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2551 reply("NSMSG_INVALID_OPTION", argv
[1]);
2554 return opt(user
, hi
, 0, argc
-1, argv
+1);
2557 static NICKSERV_FUNC(cmd_oset
)
2559 struct handle_info
*hi
;
2562 NICKSERV_MIN_PARMS(2);
2564 if (!(hi
= get_victim_oper(user
, argv
[1])))
2568 set_list(user
, hi
, 0);
2572 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2573 reply("NSMSG_INVALID_OPTION", argv
[2]);
2577 return opt(user
, hi
, 1, argc
-2, argv
+2);
2580 static OPTION_FUNC(opt_info
)
2584 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2586 hi
->infoline
= NULL
;
2588 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2592 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2593 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2597 static OPTION_FUNC(opt_width
)
2600 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2602 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2603 hi
->screen_width
= MIN_LINE_SIZE
;
2604 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2605 hi
->screen_width
= MAX_LINE_SIZE
;
2607 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2611 static OPTION_FUNC(opt_tablewidth
)
2614 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2616 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2617 hi
->table_width
= MIN_LINE_SIZE
;
2618 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2619 hi
->table_width
= MAX_LINE_SIZE
;
2621 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2625 static OPTION_FUNC(opt_color
)
2628 if (enabled_string(argv
[1]))
2629 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2630 else if (disabled_string(argv
[1]))
2631 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2633 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2638 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2642 static OPTION_FUNC(opt_privmsg
)
2645 if (enabled_string(argv
[1]))
2646 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2647 else if (disabled_string(argv
[1]))
2648 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2650 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2655 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2659 static OPTION_FUNC(opt_autohide
)
2662 if (enabled_string(argv
[1]))
2663 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2664 else if (disabled_string(argv
[1]))
2665 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2667 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2672 send_message(user
, nickserv
, "NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2676 static OPTION_FUNC(opt_style
)
2681 if (!irccasecmp(argv
[1], "Clean"))
2682 hi
->userlist_style
= HI_STYLE_CLEAN
;
2683 else if (!irccasecmp(argv
[1], "Advanced"))
2684 hi
->userlist_style
= HI_STYLE_ADVANCED
;
2685 else if (!irccasecmp(argv
[1], "Classic"))
2686 hi
->userlist_style
= HI_STYLE_CLASSIC
;
2687 else /* Default to normal */
2688 hi
->userlist_style
= HI_STYLE_NORMAL
;
2689 } /* TODO: give error if unknow style is chosen */
2691 switch (hi
->userlist_style
) {
2692 case HI_STYLE_ADVANCED
:
2695 case HI_STYLE_CLASSIC
:
2698 case HI_STYLE_CLEAN
:
2701 case HI_STYLE_NORMAL
:
2706 send_message(user
, nickserv
, "NSMSG_SET_STYLE", style
);
2710 static OPTION_FUNC(opt_announcements
)
2715 if (enabled_string(argv
[1]))
2716 hi
->announcements
= 'y';
2717 else if (disabled_string(argv
[1]))
2718 hi
->announcements
= 'n';
2719 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2720 hi
->announcements
= '?';
2722 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2727 switch (hi
->announcements
) {
2728 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2729 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2730 case '?': choice
= "default"; break;
2731 default: choice
= "unknown"; break;
2733 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2737 static OPTION_FUNC(opt_password
)
2740 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2745 cryptpass(argv
[1], hi
->passwd
);
2747 if (nickserv_conf
.sync_log
)
2748 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2750 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2754 static OPTION_FUNC(opt_flags
)
2757 unsigned int ii
, flen
;
2760 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2765 nickserv_apply_flags(user
, hi
, argv
[1]);
2767 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2768 if (hi
->flags
& (1 << ii
))
2769 flags
[flen
++] = handle_flags
[ii
];
2772 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2774 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2778 static OPTION_FUNC(opt_email
)
2782 if (!valid_email(argv
[1])) {
2783 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2786 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2787 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2790 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2791 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2793 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2795 nickserv_set_email_addr(hi
, argv
[1]);
2797 nickserv_eat_cookie(hi
->cookie
);
2798 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2801 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2805 static OPTION_FUNC(opt_maxlogins
)
2807 unsigned char maxlogins
;
2809 maxlogins
= strtoul(argv
[1], NULL
, 0);
2810 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2811 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2814 hi
->maxlogins
= maxlogins
;
2816 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2817 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2821 static OPTION_FUNC(opt_advanced
)
2824 if (enabled_string(argv
[1]))
2825 HANDLE_SET_FLAG(hi
, ADVANCED
);
2826 else if (disabled_string(argv
[1]))
2827 HANDLE_CLEAR_FLAG(hi
, ADVANCED
);
2829 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2834 send_message(user
, nickserv
, "NSMSG_SET_ADVANCED", user_find_message(user
, HANDLE_FLAGGED(hi
, ADVANCED
) ? "MSG_ON" : "MSG_OFF"));
2838 static OPTION_FUNC(opt_language
)
2840 struct language
*lang
;
2842 lang
= language_find(argv
[1]);
2843 if (irccasecmp(lang
->name
, argv
[1]))
2844 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2845 hi
->language
= lang
;
2847 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2852 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2853 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2855 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2856 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2857 && (user
->handle_info
->opserv_level
< 1000))) {
2858 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2861 if ((user
->handle_info
->opserv_level
< new_level
)
2862 || ((user
->handle_info
->opserv_level
== new_level
)
2863 && (user
->handle_info
->opserv_level
< 1000))) {
2864 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2867 if (user
->handle_info
== target
) {
2868 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2871 if (target
->opserv_level
== new_level
)
2873 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2874 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2875 target
->opserv_level
= new_level
;
2879 static OPTION_FUNC(opt_level
)
2884 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2888 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2889 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2893 static OPTION_FUNC(opt_epithet
)
2895 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2897 struct userNode
*target
, *next_un
;
2900 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2904 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2908 if ((epithet
[0] == '*') && !epithet
[1])
2911 hi
->epithet
= strdup(epithet
);
2913 for (target
= hi
->users
; target
; target
= next_un
) {
2914 irc_swhois(nickserv
, target
, hi
->epithet
);
2916 next_un
= target
->next_authed
;
2921 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2923 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2927 static OPTION_FUNC(opt_title
)
2931 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2933 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2938 if (strchr(title
, '.')) {
2939 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2942 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2943 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2944 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2949 if (!strcmp(title
, "*")) {
2950 hi
->fakehost
= NULL
;
2952 hi
->fakehost
= malloc(strlen(title
)+2);
2953 hi
->fakehost
[0] = '.';
2954 strcpy(hi
->fakehost
+1, title
);
2957 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2958 title
= hi
->fakehost
+ 1;
2962 title
= user_find_message(user
, "MSG_NONE");
2963 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2968 check_vhost(char *vhost
, struct userNode
*user
)
2970 unsigned int y
, depth
;
2973 // check for a dot in the vhost
2974 if(strchr(vhost
, '.') == NULL
) {
2975 send_message(user
, nickserv
, "NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
2979 // check for a @ in the vhost
2980 if(strchr(vhost
, '@') != NULL
) {
2981 send_message(user
, nickserv
, "NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
2985 // check for denied words, inspired by monk at paki.sex
2986 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
2987 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
2988 send_message(user
, nickserv
, "NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
2993 // check for ircu's HOSTLEN length.
2994 if(strlen(vhost
) >= HOSTLEN
) {
2995 send_message(user
, nickserv
, "NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
2999 if (vhost
[strspn(vhost
, "0123456789.")]) {
3000 hostname
= vhost
+ strlen(vhost
);
3001 for (depth
= 1; depth
&& (hostname
> vhost
); depth
--) {
3003 while ((hostname
> vhost
) && (*hostname
!= '.')) hostname
--;
3006 if (*hostname
== '.') hostname
++; /* advance past last dot we saw */
3007 if(strlen(hostname
) > 4) {
3008 send_message(user
, nickserv
, "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost
);
3016 static OPTION_FUNC(opt_fakehost
)
3020 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
3022 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
3027 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3028 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3032 if (!strcmp(fake
, "*")) {
3033 hi
->fakehost
= NULL
;
3035 if (!check_vhost(argv
[1], user
))
3038 hi
->fakehost
= strdup(fake
);
3040 fake
= hi
->fakehost
;
3043 fake
= generate_fakehost(hi
);
3046 fake
= user_find_message(user
, "MSG_NONE");
3047 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
3051 static OPTION_FUNC(opt_note
)
3054 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
3059 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3064 if ((text
[0] == '*') && !text
[1])
3067 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3072 send_message(user
, nickserv
, "NSMSG_SET_NOTE", hi
->note
->note
);
3076 static NICKSERV_FUNC(cmd_reclaim
)
3078 struct handle_info
*hi
;
3079 struct nick_info
*ni
;
3080 struct userNode
*victim
;
3082 NICKSERV_MIN_PARMS(2);
3083 hi
= user
->handle_info
;
3084 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3086 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3089 if (ni
->owner
!= user
->handle_info
) {
3090 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3093 victim
= GetUserH(ni
->nick
);
3095 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3098 if (victim
== user
) {
3099 reply("NSMSG_NICK_USER_YOU");
3102 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3103 switch (nickserv_conf
.reclaim_action
) {
3104 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3105 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3106 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3107 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3112 static NICKSERV_FUNC(cmd_unregnick
)
3115 struct handle_info
*hi
;
3116 struct nick_info
*ni
;
3118 hi
= user
->handle_info
;
3119 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
3120 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
3122 reply("NSMSG_UNKNOWN_NICK", nick
);
3125 if (hi
!= ni
->owner
) {
3126 reply("NSMSG_NOT_YOUR_NICK", nick
);
3129 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3134 static NICKSERV_FUNC(cmd_ounregnick
)
3136 struct nick_info
*ni
;
3138 NICKSERV_MIN_PARMS(2);
3139 if (!(ni
= get_nick_info(argv
[1]))) {
3140 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
3143 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
3144 reply("MSG_USER_OUTRANKED", ni
->nick
);
3147 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3152 static NICKSERV_FUNC(cmd_unregister
)
3154 struct handle_info
*hi
;
3157 NICKSERV_MIN_PARMS(2);
3158 hi
= user
->handle_info
;
3161 if (checkpass(passwd
, hi
->passwd
)) {
3162 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3165 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
3166 reply("NSMSG_PASSWORD_INVALID");
3171 static NICKSERV_FUNC(cmd_ounregister
)
3173 struct handle_info
*hi
;
3175 NICKSERV_MIN_PARMS(2);
3176 if (!(hi
= get_victim_oper(user
, argv
[1])))
3178 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3182 static NICKSERV_FUNC(cmd_status
)
3184 if (nickserv_conf
.disable_nicks
) {
3185 reply("NSMSG_GLOBAL_STATS_NONICK",
3186 dict_size(nickserv_handle_dict
));
3188 if (user
->handle_info
) {
3190 struct nick_info
*ni
;
3191 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
3192 reply("NSMSG_HANDLE_STATS", cnt
);
3194 reply("NSMSG_HANDLE_NONE");
3196 reply("NSMSG_GLOBAL_STATS",
3197 dict_size(nickserv_handle_dict
),
3198 dict_size(nickserv_nick_dict
));
3203 static NICKSERV_FUNC(cmd_ghost
)
3205 struct userNode
*target
;
3206 char reason
[MAXLEN
];
3208 NICKSERV_MIN_PARMS(2);
3209 if (!(target
= GetUserH(argv
[1]))) {
3210 reply("MSG_NICK_UNKNOWN", argv
[1]);
3213 if (target
== user
) {
3214 reply("NSMSG_CANNOT_GHOST_SELF");
3217 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3218 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3221 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3222 DelUser(target
, nickserv
, 1, reason
);
3223 reply("NSMSG_GHOST_KILLED", argv
[1]);
3227 static NICKSERV_FUNC(cmd_vacation
)
3229 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3230 reply("NSMSG_ON_VACATION");
3235 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3237 struct handle_info
*hi
;
3240 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3242 #ifdef WITH_PROTOCOL_BAHAMUT
3245 saxdb_start_record(ctx
, iter_key(it
), 0);
3246 if (hi
->announcements
!= '?') {
3247 flags
[0] = hi
->announcements
;
3249 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3252 struct handle_cookie
*cookie
= hi
->cookie
;
3255 switch (cookie
->type
) {
3256 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3257 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3258 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3259 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3260 default: type
= NULL
; break;
3263 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3264 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3265 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3267 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3268 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3269 saxdb_end_record(ctx
);
3273 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3275 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3277 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3278 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3279 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3280 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3281 saxdb_end_record(ctx
);
3285 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3289 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3290 if (hi
->flags
& (1 << ii
))
3291 flags
[flen
++] = handle_flags
[ii
];
3293 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3295 #ifdef WITH_PROTOCOL_BAHAMUT
3296 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
3299 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3300 if (hi
->last_quit_host
[0])
3301 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3302 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3303 if (hi
->masks
->used
)
3304 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3305 if (hi
->ignores
->used
)
3306 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
3308 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3310 struct string_list
*slist
;
3311 struct nick_info
*ni
;
3313 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3314 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3315 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3319 if (hi
->opserv_level
)
3320 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3321 if (hi
->language
!= lang_C
)
3322 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3323 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3324 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3325 if (hi
->screen_width
)
3326 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3327 if (hi
->table_width
)
3328 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3329 flags
[0] = hi
->userlist_style
;
3331 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3332 saxdb_end_record(ctx
);
3338 static handle_merge_func_t
*handle_merge_func_list
;
3339 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3342 reg_handle_merge_func(handle_merge_func_t func
)
3344 if (handle_merge_func_used
== handle_merge_func_size
) {
3345 if (handle_merge_func_size
) {
3346 handle_merge_func_size
<<= 1;
3347 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3349 handle_merge_func_size
= 8;
3350 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3353 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3356 static NICKSERV_FUNC(cmd_merge
)
3358 struct handle_info
*hi_from
, *hi_to
;
3359 struct userNode
*last_user
;
3360 struct userData
*cList
, *cListNext
;
3361 unsigned int ii
, jj
, n
;
3362 char buffer
[MAXLEN
];
3364 NICKSERV_MIN_PARMS(3);
3366 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
3368 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
3370 if (hi_to
== hi_from
) {
3371 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3375 for (n
=0; n
<handle_merge_func_used
; n
++)
3376 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3378 /* Append "from" handle's nicks to "to" handle's nick list. */
3380 struct nick_info
*last_ni
;
3381 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3382 last_ni
->next
= hi_from
->nicks
;
3384 while (hi_from
->nicks
) {
3385 hi_from
->nicks
->owner
= hi_to
;
3386 hi_from
->nicks
= hi_from
->nicks
->next
;
3389 /* Merge the hostmasks. */
3390 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3391 char *mask
= hi_from
->masks
->list
[ii
];
3392 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3393 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3395 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3396 string_list_append(hi_to
->masks
, strdup(mask
));
3399 /* Merge the ignores. */
3400 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
3401 char *ignore
= hi_from
->ignores
->list
[ii
];
3402 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
3403 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
3405 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3406 string_list_append(hi_to
->ignores
, strdup(ignore
));
3409 /* Merge the lists of authed users. */
3411 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3412 last_user
->next_authed
= hi_from
->users
;
3414 hi_to
->users
= hi_from
->users
;
3416 /* Repoint the old "from" handle's users. */
3417 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3418 last_user
->handle_info
= hi_to
;
3420 hi_from
->users
= NULL
;
3422 /* Merge channel userlists. */
3423 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3424 struct userData
*cList2
;
3425 cListNext
= cList
->u_next
;
3426 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3427 if (cList
->channel
== cList2
->channel
)
3429 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3430 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
);
3431 /* keep cList2 in hi_to; remove cList from hi_from */
3432 del_channel_user(cList
, 1);
3435 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
);
3436 /* remove the lower-ranking cList2 from hi_to */
3437 del_channel_user(cList2
, 1);
3439 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3441 /* cList needs to be moved from hi_from to hi_to */
3442 cList
->handle
= hi_to
;
3443 /* Remove from linked list for hi_from */
3444 assert(!cList
->u_prev
);
3445 hi_from
->channels
= cList
->u_next
;
3447 cList
->u_next
->u_prev
= cList
->u_prev
;
3448 /* Add to linked list for hi_to */
3449 cList
->u_prev
= NULL
;
3450 cList
->u_next
= hi_to
->channels
;
3451 if (hi_to
->channels
)
3452 hi_to
->channels
->u_prev
= cList
;
3453 hi_to
->channels
= cList
;
3457 /* Do they get an OpServ level promotion? */
3458 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3459 hi_to
->opserv_level
= hi_from
->opserv_level
;
3461 /* What about last seen time? */
3462 if (hi_from
->lastseen
> hi_to
->lastseen
)
3463 hi_to
->lastseen
= hi_from
->lastseen
;
3465 /* Does a fakehost carry over? (This intentionally doesn't set it
3466 * for users previously attached to hi_to. They'll just have to
3469 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3470 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3472 /* Notify of success. */
3473 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3474 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3475 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3477 /* Unregister the "from" handle. */
3478 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3483 struct nickserv_discrim
{
3484 unsigned int limit
, min_level
, max_level
;
3485 unsigned long flags_on
, flags_off
;
3486 time_t min_registered
, max_registered
;
3488 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3489 const char *nickmask
;
3490 const char *hostmask
;
3491 const char *handlemask
;
3492 const char *emailmask
;
3495 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3497 struct discrim_apply_info
{
3498 struct nickserv_discrim
*discrim
;
3499 discrim_search_func func
;
3500 struct userNode
*source
;
3501 unsigned int matched
;
3504 static struct nickserv_discrim
*
3505 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3508 struct nickserv_discrim
*discrim
;
3510 discrim
= malloc(sizeof(*discrim
));
3511 memset(discrim
, 0, sizeof(*discrim
));
3512 discrim
->min_level
= 0;
3513 discrim
->max_level
= ~0;
3514 discrim
->limit
= 50;
3515 discrim
->min_registered
= 0;
3516 discrim
->max_registered
= INT_MAX
;
3517 discrim
->lastseen
= now
;
3519 for (i
=0; i
<argc
; i
++) {
3520 if (i
== argc
- 1) {
3521 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3524 if (!irccasecmp(argv
[i
], "limit")) {
3525 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3526 } else if (!irccasecmp(argv
[i
], "flags")) {
3527 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3528 } else if (!irccasecmp(argv
[i
], "registered")) {
3529 const char *cmp
= argv
[++i
];
3530 if (cmp
[0] == '<') {
3531 if (cmp
[1] == '=') {
3532 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3534 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3536 } else if (cmp
[0] == '=') {
3537 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3538 } else if (cmp
[0] == '>') {
3539 if (cmp
[1] == '=') {
3540 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3542 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3545 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3547 } else if (!irccasecmp(argv
[i
], "seen")) {
3548 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3549 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3550 discrim
->nickmask
= argv
[++i
];
3551 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3553 if (!irccasecmp(argv
[i
], "exact")) {
3554 if (i
== argc
- 1) {
3555 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3558 discrim
->hostmask_type
= EXACT
;
3559 } else if (!irccasecmp(argv
[i
], "subset")) {
3560 if (i
== argc
- 1) {
3561 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3564 discrim
->hostmask_type
= SUBSET
;
3565 } else if (!irccasecmp(argv
[i
], "superset")) {
3566 if (i
== argc
- 1) {
3567 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3570 discrim
->hostmask_type
= SUPERSET
;
3571 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3572 if (i
== argc
- 1) {
3573 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3576 discrim
->hostmask_type
= LASTQUIT
;
3579 discrim
->hostmask_type
= SUPERSET
;
3581 discrim
->hostmask
= argv
[++i
];
3582 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3583 if (!irccasecmp(argv
[++i
], "*")) {
3584 discrim
->handlemask
= 0;
3586 discrim
->handlemask
= argv
[i
];
3588 } else if (!irccasecmp(argv
[i
], "email")) {
3589 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3590 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3592 } else if (!irccasecmp(argv
[++i
], "*")) {
3593 discrim
->emailmask
= 0;
3595 discrim
->emailmask
= argv
[i
];
3597 } else if (!irccasecmp(argv
[i
], "access")) {
3598 const char *cmp
= argv
[++i
];
3599 if (cmp
[0] == '<') {
3600 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3601 if (cmp
[1] == '=') {
3602 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3604 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3606 } else if (cmp
[0] == '=') {
3607 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3608 } else if (cmp
[0] == '>') {
3609 if (cmp
[1] == '=') {
3610 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3612 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3615 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3618 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3629 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3631 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3632 || (discrim
->flags_off
& hi
->flags
)
3633 || (discrim
->min_registered
> hi
->registered
)
3634 || (discrim
->max_registered
< hi
->registered
)
3635 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3636 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3637 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3638 || (discrim
->min_level
> hi
->opserv_level
)
3639 || (discrim
->max_level
< hi
->opserv_level
)) {
3642 if (discrim
->hostmask
) {
3644 for (i
=0; i
<hi
->masks
->used
; i
++) {
3645 const char *mask
= hi
->masks
->list
[i
];
3646 if ((discrim
->hostmask_type
== SUBSET
)
3647 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3648 else if ((discrim
->hostmask_type
== EXACT
)
3649 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3650 else if ((discrim
->hostmask_type
== SUPERSET
)
3651 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3652 else if ((discrim
->hostmask_type
== LASTQUIT
)
3653 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3655 if (i
==hi
->masks
->used
) return 0;
3657 if (discrim
->nickmask
) {
3658 struct nick_info
*nick
= hi
->nicks
;
3660 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3663 if (!nick
) return 0;
3669 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3671 dict_iterator_t it
, next
;
3672 unsigned int matched
;
3674 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3675 it
&& (matched
< discrim
->limit
);
3677 next
= iter_next(it
);
3678 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3679 dsf(source
, iter_data(it
));
3687 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3689 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3693 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3698 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3700 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3701 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
3705 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3707 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3708 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3709 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3710 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3711 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3715 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3717 struct handle_info_list hil
;
3718 struct helpfile_table tbl
;
3723 memset(&hil
, 0, sizeof(hil
));
3724 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3725 struct handle_info
*hi
= iter_data(it
);
3726 if (hi
->opserv_level
)
3727 handle_info_list_append(&hil
, hi
);
3729 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3730 tbl
.length
= hil
.used
+ 1;
3732 tbl
.flags
= TABLE_NO_FREE
;
3733 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3734 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3737 for (ii
= 0; ii
< hil
.used
; ) {
3738 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3739 ary
[0] = hil
.list
[ii
]->handle
;
3740 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3741 tbl
.contents
[++ii
] = ary
;
3743 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3744 reply("MSG_MATCH_COUNT", hil
.used
);
3745 for (ii
= 0; ii
< hil
.used
; ii
++)
3746 free(tbl
.contents
[ii
]);
3751 static NICKSERV_FUNC(cmd_search
)
3753 struct nickserv_discrim
*discrim
;
3754 discrim_search_func action
;
3755 struct svccmd
*subcmd
;
3756 unsigned int matches
;
3759 NICKSERV_MIN_PARMS(3);
3760 sprintf(buf
, "search %s", argv
[1]);
3761 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3762 if (!irccasecmp(argv
[1], "print"))
3763 action
= search_print_func
;
3764 else if (!irccasecmp(argv
[1], "count"))
3765 action
= search_count_func
;
3766 else if (!irccasecmp(argv
[1], "unregister"))
3767 action
= search_unregister_func
;
3769 reply("NSMSG_INVALID_ACTION", argv
[1]);
3773 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3776 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3780 if (action
== search_print_func
)
3781 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3782 else if (action
== search_count_func
)
3783 discrim
->limit
= INT_MAX
;
3785 matches
= nickserv_discrim_search(discrim
, action
, user
);
3788 reply("MSG_MATCH_COUNT", matches
);
3790 reply("MSG_NO_MATCHES");
3796 static MODCMD_FUNC(cmd_checkpass
)
3798 struct handle_info
*hi
;
3800 NICKSERV_MIN_PARMS(3);
3801 if (!(hi
= get_handle_info(argv
[1]))) {
3802 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3805 if (checkpass(argv
[2], hi
->passwd
))
3806 reply("CHECKPASS_YES");
3808 reply("CHECKPASS_NO");
3814 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3817 struct string_list
*masks
, *slist
, *ignores
;
3818 struct handle_info
*hi
;
3819 struct userNode
*authed_users
;
3820 struct userData
*channels
;
3821 unsigned long int id
;
3824 char *setter
, *note
;
3827 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3828 id
= str
? strtoul(str
, NULL
, 0) : 0;
3829 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3831 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3834 if ((hi
= get_handle_info(handle
))) {
3835 authed_users
= hi
->users
;
3836 channels
= hi
->channels
;
3838 hi
->channels
= NULL
;
3839 dict_remove(nickserv_handle_dict
, hi
->handle
);
3841 authed_users
= NULL
;
3844 hi
= register_handle(handle
, str
, id
);
3846 hi
->users
= authed_users
;
3847 while (authed_users
) {
3848 authed_users
->handle_info
= hi
;
3849 authed_users
= authed_users
->next_authed
;
3852 hi
->channels
= channels
;
3853 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3854 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3855 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
3856 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
3857 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3858 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3859 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3860 hi
->language
= language_find(str
? str
: "C");
3861 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3862 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3863 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3865 hi
->infoline
= strdup(str
);
3866 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3867 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3868 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3869 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3870 /* We want to read the nicks even if disable_nicks is set. This is so
3871 * that we don't lose the nick data entirely. */
3872 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3874 for (ii
=0; ii
<slist
->used
; ii
++)
3875 register_nick(slist
->list
[ii
], hi
);
3877 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3879 for (ii
=0; str
[ii
]; ii
++)
3880 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3882 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3883 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
3884 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3885 hi
->announcements
= str
? str
[0] : '?';
3886 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3887 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3888 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3889 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3890 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3892 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3894 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3895 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3897 nickserv_set_email_addr(hi
, str
);
3898 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3900 hi
->epithet
= strdup(str
);
3901 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
3903 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
3904 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
3905 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3906 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
3907 if (setter
&& date
&& note
)
3909 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
3914 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3916 hi
->fakehost
= strdup(str
);
3918 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3920 const char *data
, *type
, *expires
, *cookie_str
;
3921 struct handle_cookie
*cookie
;
3923 cookie
= calloc(1, sizeof(*cookie
));
3924 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3925 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3926 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3927 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3928 if (!type
|| !expires
|| !cookie_str
) {
3929 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3932 if (!irccasecmp(type
, KEY_ACTIVATION
))
3933 cookie
->type
= ACTIVATION
;
3934 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3935 cookie
->type
= PASSWORD_CHANGE
;
3936 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3937 cookie
->type
= EMAIL_CHANGE
;
3938 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3939 cookie
->type
= ALLOWAUTH
;
3941 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3944 cookie
->expires
= strtoul(expires
, NULL
, 0);
3945 if (cookie
->expires
< now
)
3948 cookie
->data
= strdup(data
);
3949 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3953 nickserv_bake_cookie(cookie
);
3955 nickserv_free_cookie(cookie
);
3960 nickserv_saxdb_read(dict_t db
) {
3962 struct record_data
*rd
;
3964 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3966 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3971 static NICKSERV_FUNC(cmd_mergedb
)
3973 struct timeval start
, stop
;
3976 NICKSERV_MIN_PARMS(2);
3977 gettimeofday(&start
, NULL
);
3978 if (!(db
= parse_database(argv
[1]))) {
3979 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3982 nickserv_saxdb_read(db
);
3984 gettimeofday(&stop
, NULL
);
3985 stop
.tv_sec
-= start
.tv_sec
;
3986 stop
.tv_usec
-= start
.tv_usec
;
3987 if (stop
.tv_usec
< 0) {
3989 stop
.tv_usec
+= 1000000;
3991 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3996 expire_handles(UNUSED_ARG(void *data
))
3998 dict_iterator_t it
, next
;
4000 struct handle_info
*hi
;
4002 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
4003 next
= iter_next(it
);
4005 if ((hi
->opserv_level
> 0)
4007 || HANDLE_FLAGGED(hi
, FROZEN
)
4008 || HANDLE_FLAGGED(hi
, NODELETE
)) {
4011 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
4012 if ((now
- hi
->lastseen
) > expiry
) {
4013 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
4014 nickserv_unregister_handle(hi
, NULL
, NULL
);
4018 if (nickserv_conf
.handle_expire_frequency
)
4019 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4023 nickserv_load_dict(const char *fname
)
4027 if (!(file
= fopen(fname
, "r"))) {
4028 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
4031 while (!feof(file
)) {
4032 fgets(line
, sizeof(line
), file
);
4035 if (line
[strlen(line
)-1] == '\n')
4036 line
[strlen(line
)-1] = 0;
4037 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
4040 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
4043 static enum reclaim_action
4044 reclaim_action_from_string(const char *str
) {
4046 return RECLAIM_NONE
;
4047 else if (!irccasecmp(str
, "warn"))
4048 return RECLAIM_WARN
;
4049 else if (!irccasecmp(str
, "svsnick"))
4050 return RECLAIM_SVSNICK
;
4051 else if (!irccasecmp(str
, "kill"))
4052 return RECLAIM_KILL
;
4054 return RECLAIM_NONE
;
4058 nickserv_conf_read(void)
4060 dict_t conf_node
, child
;
4063 struct string_list
*strlist
;
4065 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
4066 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
4069 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
4071 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
4072 if (nickserv_conf
.valid_handle_regex_set
)
4073 regfree(&nickserv_conf
.valid_handle_regex
);
4075 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4076 nickserv_conf
.valid_handle_regex_set
= !err
;
4077 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
4079 nickserv_conf
.valid_handle_regex_set
= 0;
4081 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
4082 if (nickserv_conf
.valid_nick_regex_set
)
4083 regfree(&nickserv_conf
.valid_nick_regex
);
4085 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4086 nickserv_conf
.valid_nick_regex_set
= !err
;
4087 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
4089 nickserv_conf
.valid_nick_regex_set
= 0;
4091 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
4093 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
4094 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
4095 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
4096 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
4097 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
4098 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
4099 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
4100 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
4101 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
4102 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
4103 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
4104 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
4105 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
4106 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
4107 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
4108 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
4109 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
4110 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
4111 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
4112 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
4113 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
4114 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
4115 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
4116 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
4117 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
4119 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
4120 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
4121 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4123 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4124 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
4125 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4127 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4128 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
4129 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
4130 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
4131 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
4132 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
4133 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
4134 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
4135 if (!nickserv_conf
.disable_nicks
) {
4136 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
4137 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4138 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
4139 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
4140 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
4141 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4142 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
4143 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
4145 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
4146 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
4147 const char *key
= iter_key(it
), *value
;
4151 if (!strncasecmp(key
, "uc_", 3))
4152 flag
= toupper(key
[3]);
4153 else if (!strncasecmp(key
, "lc_", 3))
4154 flag
= tolower(key
[3]);
4158 if ((pos
= handle_inverse_flags
[flag
])) {
4159 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
4160 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
4163 if (nickserv_conf
.weak_password_dict
)
4164 dict_delete(nickserv_conf
.weak_password_dict
);
4165 nickserv_conf
.weak_password_dict
= dict_new();
4166 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
4167 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
4168 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
4169 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
4171 nickserv_load_dict(str
);
4172 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
4173 if (nickserv
&& str
)
4174 NickChange(nickserv
, str
, 0);
4175 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
4176 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
4177 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
4178 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
4179 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
4180 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
4181 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
4182 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
4183 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
4184 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
4185 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
4186 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
4187 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
4188 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
4189 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
4190 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
4191 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
4192 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
4193 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
4194 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
4196 free_string_list(nickserv_conf
.denied_fakehost_words
);
4197 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
4199 strlist
= string_list_copy(strlist
);
4201 strlist
= alloc_string_list(4);
4202 string_list_append(strlist
, strdup("sex"));
4203 string_list_append(strlist
, strdup("fuck"));
4205 nickserv_conf
.denied_fakehost_words
= strlist
;
4207 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
4208 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4210 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
4211 nickserv_conf
.auto_oper
= str
? str
: "";
4213 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
4214 nickserv_conf
.auto_admin
= str
? str
: "";
4216 str
= conf_get_data("server/network", RECDB_QSTRING
);
4217 nickserv_conf
.network_name
= str
? str
: "some IRC network";
4218 if (!nickserv_conf
.auth_policer_params
) {
4219 nickserv_conf
.auth_policer_params
= policer_params_new();
4220 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
4221 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4223 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4224 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4225 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4229 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
4231 char newnick
[NICKLEN
+1];
4240 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4242 case RECLAIM_SVSNICK
:
4244 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4245 } while (GetUserH(newnick
));
4246 irc_svsnick(nickserv
, user
, newnick
);
4249 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4250 irc_kill(nickserv
, user
, msg
);
4256 nickserv_reclaim_p(void *data
) {
4257 struct userNode
*user
= data
;
4258 struct nick_info
*ni
= get_nick_info(user
->nick
);
4260 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4264 check_user_nick(struct userNode
*user
) {
4265 struct nick_info
*ni
;
4266 user
->modes
&= ~FLAGS_REGNICK
;
4267 if (!(ni
= get_nick_info(user
->nick
)))
4269 if (user
->handle_info
== ni
->owner
) {
4270 user
->modes
|= FLAGS_REGNICK
;
4274 if (nickserv_conf
.warn_nick_owned
)
4275 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4276 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
4278 if (nickserv_conf
.auto_reclaim_delay
)
4279 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
4281 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4286 handle_new_user(struct userNode
*user
)
4288 return check_user_nick(user
);
4292 handle_account(struct userNode
*user
, const char *stamp
)
4294 struct handle_info
*hi
;
4297 #ifdef WITH_PROTOCOL_P10
4298 time_t timestamp
= 0;
4300 colon
= strchr(stamp
, ':');
4301 if(colon
&& colon
[1])
4304 timestamp
= atoi(colon
+1);
4306 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
4307 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
4309 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
);
4313 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4314 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4318 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4321 set_user_handle_info(user
, hi
, 0);
4323 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4328 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4330 struct handle_info
*hi
;
4332 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4333 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4334 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4336 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4337 check_user_nick(user
);
4341 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4343 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4344 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4345 set_user_handle_info(user
, NULL
, 0);
4348 static struct modcmd
*
4349 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4351 if (min_level
> 0) {
4353 sprintf(buf
, "%u", min_level
);
4354 if (must_be_qualified
) {
4355 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4357 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4359 } else if (min_level
== 0) {
4360 if (must_be_qualified
) {
4361 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4363 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4366 if (must_be_qualified
) {
4367 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4369 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4375 nickserv_db_cleanup(void)
4377 unreg_del_user_func(nickserv_remove_user
);
4378 userList_clean(&curr_helpers
);
4379 policer_params_delete(nickserv_conf
.auth_policer_params
);
4380 dict_delete(nickserv_handle_dict
);
4381 dict_delete(nickserv_nick_dict
);
4382 dict_delete(nickserv_opt_dict
);
4383 dict_delete(nickserv_allow_auth_dict
);
4384 dict_delete(nickserv_email_dict
);
4385 dict_delete(nickserv_id_dict
);
4386 dict_delete(nickserv_conf
.weak_password_dict
);
4387 free(auth_func_list
);
4388 free(unreg_func_list
);
4390 free(allowauth_func_list
);
4391 free(handle_merge_func_list
);
4392 free(failpw_func_list
);
4393 if (nickserv_conf
.valid_handle_regex_set
)
4394 regfree(&nickserv_conf
.valid_handle_regex
);
4395 if (nickserv_conf
.valid_nick_regex_set
)
4396 regfree(&nickserv_conf
.valid_nick_regex
);
4400 init_nickserv(const char *nick
)
4402 struct chanNode
*chan
;
4404 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4405 reg_new_user_func(handle_new_user
);
4406 reg_nick_change_func(handle_nick_change
);
4407 reg_del_user_func(nickserv_remove_user
);
4408 reg_account_func(handle_account
);
4410 /* set up handle_inverse_flags */
4411 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4412 for (i
=0; handle_flags
[i
]; i
++) {
4413 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4414 flag_access_levels
[i
] = 0;
4417 conf_register_reload(nickserv_conf_read
);
4418 nickserv_opt_dict
= dict_new();
4419 nickserv_email_dict
= dict_new();
4421 dict_set_free_keys(nickserv_email_dict
, free
);
4422 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4424 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4425 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4426 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4427 * a big pain to disable since its nolonger in the config file. ) -Rubin
4429 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4430 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4431 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4432 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4433 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4434 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4435 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4436 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4437 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4438 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4439 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4440 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4441 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4442 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4443 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4444 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4445 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4446 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4447 if (!nickserv_conf
.disable_nicks
) {
4448 /* nick management commands */
4449 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4450 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4451 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4452 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4453 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4454 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4456 if (nickserv_conf
.email_enabled
) {
4457 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4458 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4459 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4460 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4461 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4462 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4464 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4465 /* ignore commands */
4466 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
4467 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
4468 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
4469 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
4470 /* miscellaneous commands */
4471 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4472 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4473 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4474 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4475 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4477 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4478 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4479 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4480 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4481 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4482 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
4483 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
4484 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4485 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4486 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4487 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4488 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4489 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4490 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
4491 if (nickserv_conf
.titlehost_suffix
) {
4492 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4493 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4495 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4496 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4497 dict_insert(nickserv_opt_dict
, "ADVANCED", opt_advanced
);
4498 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4500 nickserv_handle_dict
= dict_new();
4501 dict_set_free_keys(nickserv_handle_dict
, free
);
4502 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4504 nickserv_id_dict
= dict_new();
4505 dict_set_free_keys(nickserv_id_dict
, free
);
4507 nickserv_nick_dict
= dict_new();
4508 dict_set_free_data(nickserv_nick_dict
, free
);
4510 nickserv_allow_auth_dict
= dict_new();
4512 userList_init(&curr_helpers
);
4515 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4516 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4517 nickserv_service
= service_register(nickserv
);
4519 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4520 reg_exit_func(nickserv_db_cleanup
);
4521 if(nickserv_conf
.handle_expire_frequency
)
4522 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4524 if(autojoin_channels
&& nickserv
) {
4525 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
4526 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
4527 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
4531 message_register_table(msgtab
);