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() */
32 #define NICKSERV_CONF_NAME "services/nickserv"
34 #define KEY_DISABLE_NICKS "disable_nicks"
35 #define KEY_DEFAULT_HOSTMASK "default_hostmask"
36 #define KEY_NICKS_PER_HANDLE "nicks_per_handle"
37 #define KEY_NICKS_PER_ACCOUNT "nicks_per_account"
38 #define KEY_PASSWORD_MIN_LENGTH "password_min_length"
39 #define KEY_PASSWORD_MIN_DIGITS "password_min_digits"
40 #define KEY_PASSWORD_MIN_UPPER "password_min_upper"
41 #define KEY_PASSWORD_MIN_LOWER "password_min_lower"
42 #define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
43 #define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
44 #define KEY_VALID_NICK_REGEX "valid_nick_regex"
45 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
46 #define KEY_MODOPER_LEVEL "modoper_level"
47 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
48 #define KEY_SET_TITLE_LEVEL "set_title_level"
49 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
50 #define KEY_DENIED_FAKEHOST_WORDS "denied_fakehost_words"
51 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
52 #define KEY_AUTO_OPER "auto_oper"
53 #define KEY_AUTO_ADMIN "auto_admin"
54 #define KEY_FLAG_LEVELS "flag_levels"
55 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
56 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
57 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
58 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
59 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
60 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
61 #define KEY_DICT_FILE "dict_file"
62 #define KEY_NICK "nick"
63 #define KEY_LANGUAGE "language"
64 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
65 #define KEY_AUTOGAG_DURATION "autogag_duration"
66 #define KEY_AUTH_POLICER "auth_policer"
67 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
68 #define KEY_EMAIL_ENABLED "email_enabled"
69 #define KEY_EMAIL_REQUIRED "email_required"
70 #define KEY_SYNC_LOG "sync_log"
71 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
72 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
73 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
74 #define KEY_DEFAULT_STYLE "default_style"
77 #define KEY_PASSWD "passwd"
78 #define KEY_NICKS "nicks"
79 #define KEY_MASKS "masks"
80 #define KEY_IGNORES "ignores"
81 #define KEY_OPSERV_LEVEL "opserv_level"
82 #define KEY_FLAGS "flags"
83 #define KEY_REGISTER_ON "register"
84 #define KEY_LAST_SEEN "lastseen"
85 #define KEY_INFO "info"
86 #define KEY_USERLIST_STYLE "user_style"
87 #define KEY_SCREEN_WIDTH "screen_width"
88 #define KEY_LAST_AUTHED_HOST "last_authed_host"
89 #define KEY_LAST_QUIT_HOST "last_quit_host"
90 #define KEY_EMAIL_ADDR "email_addr"
91 #define KEY_COOKIE "cookie"
92 #define KEY_COOKIE_DATA "data"
93 #define KEY_COOKIE_TYPE "type"
94 #define KEY_COOKIE_EXPIRES "expires"
95 #define KEY_ACTIVATION "activation"
96 #define KEY_PASSWORD_CHANGE "password change"
97 #define KEY_EMAIL_CHANGE "email change"
98 #define KEY_ALLOWAUTH "allowauth"
99 #define KEY_EPITHET "epithet"
100 #define KEY_TABLE_WIDTH "table_width"
101 #define KEY_ANNOUNCEMENTS "announcements"
102 #define KEY_MAXLOGINS "maxlogins"
103 #define KEY_FAKEHOST "fakehost"
104 #define KEY_NOTE_NOTE "note"
105 #define KEY_NOTE_SETTER "setter"
106 #define KEY_NOTE_DATE "date"
109 #define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
111 #define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
112 #define OPTION_FUNC(NAME) int NAME(struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
113 typedef OPTION_FUNC(option_func_t
);
115 DEFINE_LIST(handle_info_list
, struct handle_info
*);
117 #define NICKSERV_MIN_PARMS(N) do { \
119 reply("MSG_MISSING_PARAMS", argv[0]); \
120 svccmd_send_help_brief(user, nickserv, cmd); \
124 struct userNode
*nickserv
;
125 struct userList curr_helpers
;
126 const char *handle_flags
= HANDLE_FLAGS
;
128 extern struct string_list
*autojoin_channels
;
129 static struct module *nickserv_module
;
130 static struct service
*nickserv_service
;
131 static struct log_type
*NS_LOG
;
132 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
133 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
134 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
135 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
136 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
137 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
138 static char handle_inverse_flags
[256];
139 static unsigned int flag_access_levels
[32];
140 static const struct message_entry msgtab
[] = {
141 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
142 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu charactors or less."},
143 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
144 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
145 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
146 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
147 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
148 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
149 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
150 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
151 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
152 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
153 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
154 { "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." },
155 { "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." },
156 { "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." },
157 { "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." },
158 { "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." },
159 { "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." },
160 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
161 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
162 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
163 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
164 { "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." },
165 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
166 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
167 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
168 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
169 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
170 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
171 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
172 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
173 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
174 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
175 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
176 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
177 { "NSMSG_REGISTER_BAD_NICKMASK", "You must provide a hostmask, or online nick to generate one automatically. (or set a default hostmask in the config such as *@*)." },
178 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
179 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
180 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
181 { "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)" },
182 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
183 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
184 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
185 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
186 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
187 { "NSMSG_BAD_ADVANCED", "Advanced must be either 1 to enable it or 0 to disable it." },
188 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
189 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
190 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
191 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
192 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
193 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
194 { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
195 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
196 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
197 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
198 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
199 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
200 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
201 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
202 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
203 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
204 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
205 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
206 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
207 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
208 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
209 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
210 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
211 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
212 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
213 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
214 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
215 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
216 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
217 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
218 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
219 { "NSMSG_HANDLEINFO_IGNORES", "Ignore(s): %s" },
220 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
221 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
222 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
223 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
224 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
225 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
226 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
227 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
228 { "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)." },
229 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
230 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
231 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
232 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
233 { "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." },
234 { "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." },
235 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
236 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
237 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
238 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
239 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
240 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
241 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
242 { "NSMSG_PASS_SUCCESS", "Password changed." },
243 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
244 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
245 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
246 { "NSMSG_ADDIGNORE_ALREADY", "$b%s$b is already an ignored hostmask in your account." },
247 { "NSMSG_ADDIGNORE_SUCCESS", "Hostmask %s added." },
248 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
249 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
250 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
251 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
252 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
253 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
254 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
255 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
256 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
257 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
258 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
259 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
260 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
261 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
262 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
263 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
264 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
265 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
266 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
267 { "NSMSG_NO_ACCESS", "Access denied." },
268 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
269 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
270 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
271 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
272 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
273 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
274 { "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." },
275 { "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." },
276 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
277 { "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." },
278 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
279 { "NSMSG_SEARCH_MATCH", "Match: %s" },
280 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
281 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
282 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
283 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
284 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
285 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
286 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
287 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
288 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
289 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
290 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
291 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
292 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
293 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
294 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
295 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
296 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
297 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
298 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
299 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
300 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
301 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
302 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
303 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
304 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
305 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
306 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
307 { "NSMSG_SET_ADVANCED", "$bADVANCED: $b%s" },
308 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
309 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
310 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
311 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
312 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
313 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
315 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
316 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
318 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
319 { "NSEMAIL_ACTIVATION_BODY",
320 "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n"
322 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
323 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
324 "This command is only used once to complete your account registration, and never again. Once you have run this command, you will need to authenticate everytime you reconnect to the network. To do this, you will have to type this command every time you reconnect:\n"
325 "/msg %3$s@%4$s AUTH %5$s your-password\n"
326 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
327 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
329 "If you did NOT request this account, you do not need to do anything.\n"
330 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
331 { "NSEMAIL_ACTIVATION_BODY_WEB",
332 "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n"
334 "To verify your email address and complete the account registration, visit the following URL:\n"
335 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
337 "If you did NOT request this account, you do not need to do anything.\n"
338 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
339 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
340 { "NSEMAIL_PASSWORD_CHANGE_BODY",
341 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
342 "To complete the password change, log on to %1$s and type the following command:\n"
343 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
344 "If you did NOT request your password to be changed, you do not need to do anything.\n"
345 "Please contact the %1$s staff if you have questions." },
346 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
347 "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\n"
348 "To complete the password change, click the following URL:\n"
349 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%2$s\n"
350 "If you did NOT request your password to be changed, you do not need to do anything.\n"
351 "Please contact the %1$s staff if you have questions." },
352 { "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
353 #ifdef stupid_verify_old_email
354 { "NSEMAIL_EMAIL_CHANGE_BODY_NEW", "This email has been sent to verify that your email address belongs to the same person as account %5$s on %1$s. The SECOND HALF of your cookie is %2$.*6$s.\nTo verify your address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s ?????%2$.*6$s\n(Replace the ????? with the FIRST HALF of the cookie, as sent to your OLD email address.)\nIf you did NOT request this email address to be associated with this account, you do not need to do anything. Please contact the %1$s staff if you have questions." },
355 { "NSEMAIL_EMAIL_CHANGE_BODY_OLD", "This email has been sent to verify that you want to change your email for account %5$s on %1$s from this address to %7$s. The FIRST HALF of your cookie is %2$.*6$s\nTo verify your new address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$.*6$s?????\n(Replace the ????? with the SECOND HALF of the cookie, as sent to your NEW email address.)\nIf you did NOT request this change of email address, you do not need to do anything. Please contact the %1$s staff if you have questions." },
357 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
358 { "NSEMAIL_EMAIL_VERIFY_BODY", "This email has been sent to verify that this address belongs to the same person as %5$s on %1$s. Your cookie is %2$s.\nTo verify your address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nIf you did NOT request this email address to be associated with this account, you do not need to do anything. Please contact the %1$s staff if you have questions." },
359 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
360 { "NSEMAIL_ALLOWAUTH_BODY", "This email has been sent to let you authenticate (auth) to account %5$s on %1$s. Your cookie is %2$s.\nTo auth to that account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nIf you did NOT request this authorization, you do not need to do anything. Please contact the %1$s staff if you have questions." },
361 { "NSMSG_NOT_VALID_FAKEHOST_DOT", "$b%s$b is not a valid vhost. (needs at least one dot)" },
362 { "NSMSG_NOT_VALID_FAKEHOST_AT", "$b%s$b is not a valid vhost. (it can not have a '@')" },
363 { "NSMSG_DENIED_FAKEHOST_WORD", "Access denied because there's a prohibited word in $b%s$b (%s)." },
364 { "NSMSG_NOT_VALID_FAKEHOST_LEN", "$b%s$b is not a valid vhost. (can only be 63 characters)" },
365 { "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", "$b%s$b is not a valid vhost. (TLD can only be 4 characters and less)" },
366 { "CHECKPASS_YES", "Yes." },
367 { "CHECKPASS_NO", "No." },
371 enum reclaim_action
{
377 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
378 static void nickserv_reclaim_p(void *data
);
381 unsigned int disable_nicks
: 1;
382 unsigned int valid_handle_regex_set
: 1;
383 unsigned int valid_nick_regex_set
: 1;
384 unsigned int autogag_enabled
: 1;
385 unsigned int email_enabled
: 1;
386 unsigned int email_required
: 1;
387 unsigned int default_hostmask
: 1;
388 unsigned int warn_nick_owned
: 1;
389 unsigned int warn_clone_auth
: 1;
390 unsigned int sync_log
: 1;
391 unsigned long nicks_per_handle
;
392 unsigned long password_min_length
;
393 unsigned long password_min_digits
;
394 unsigned long password_min_upper
;
395 unsigned long password_min_lower
;
396 unsigned long db_backup_frequency
;
397 unsigned long handle_expire_frequency
;
398 unsigned long autogag_duration
;
399 unsigned long email_visible_level
;
400 unsigned long cookie_timeout
;
401 unsigned long handle_expire_delay
;
402 unsigned long nochan_handle_expire_delay
;
403 unsigned long modoper_level
;
404 unsigned long set_epithet_level
;
405 unsigned long set_title_level
;
406 unsigned long set_fakehost_level
;
407 unsigned long handles_per_email
;
408 unsigned long email_search_level
;
409 const char *network_name
;
410 const char *titlehost_suffix
;
411 regex_t valid_handle_regex
;
412 regex_t valid_nick_regex
;
413 dict_t weak_password_dict
;
414 struct policer_params
*auth_policer_params
;
415 enum reclaim_action reclaim_action
;
416 enum reclaim_action auto_reclaim_action
;
417 unsigned long auto_reclaim_delay
;
418 unsigned char default_maxlogins
;
419 unsigned char hard_maxlogins
;
420 const char *auto_oper
;
421 const char *auto_admin
;
423 struct string_list
*denied_fakehost_words
;
426 /* We have 2^32 unique account IDs to use. */
427 unsigned long int highest_id
= 0;
430 canonicalize_hostmask(char *mask
)
432 char *out
= mask
, *temp
;
433 if ((temp
= strchr(mask
, '!'))) {
435 while (*temp
) *out
++ = *temp
++;
441 static struct handle_note
*
442 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
444 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
446 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
448 memcpy(note
->note
, text
, strlen(text
));
452 static struct handle_info
*
453 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
455 struct handle_info
*hi
;
457 #ifdef WITH_PROTOCOL_BAHAMUT
458 char id_base64
[IDLEN
+ 1];
461 /* Assign a unique account ID to the account; note that 0 is
462 an invalid account ID. 1 is therefore the first account ID. */
464 id
= 1 + highest_id
++;
466 /* Note: highest_id is and must always be the highest ID. */
467 if(id
> highest_id
) {
471 inttobase64(id_base64
, id
, IDLEN
);
473 /* Make sure an account with the same ID doesn't exist. If a
474 duplicate is found, log some details and assign a new one.
475 This should be impossible, but it never hurts to expect it. */
476 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
477 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
483 hi
= calloc(1, sizeof(*hi
));
484 hi
->userlist_style
= HI_DEFAULT_STYLE
;
485 hi
->announcements
= '?';
486 hi
->handle
= strdup(handle
);
487 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
489 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
491 #ifdef WITH_PROTOCOL_BAHAMUT
493 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
500 register_nick(const char *nick
, struct handle_info
*owner
)
502 struct nick_info
*ni
;
503 ni
= malloc(sizeof(struct nick_info
));
504 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
506 ni
->next
= owner
->nicks
;
508 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
512 delete_nick(struct nick_info
*ni
)
514 struct nick_info
*last
, *next
;
515 struct userNode
*user
;
516 /* Check to see if we should mark a user as unregistered. */
517 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
518 user
->modes
&= ~FLAGS_REGNICK
;
521 /* Remove ni from the nick_info linked list. */
522 if (ni
== ni
->owner
->nicks
) {
523 ni
->owner
->nicks
= ni
->next
;
525 last
= ni
->owner
->nicks
;
531 last
->next
= next
->next
;
533 dict_remove(nickserv_nick_dict
, ni
->nick
);
536 static unreg_func_t
*unreg_func_list
;
537 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
540 reg_unreg_func(unreg_func_t func
)
542 if (unreg_func_used
== unreg_func_size
) {
543 if (unreg_func_size
) {
544 unreg_func_size
<<= 1;
545 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
548 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
551 unreg_func_list
[unreg_func_used
++] = func
;
555 nickserv_free_cookie(void *data
)
557 struct handle_cookie
*cookie
= data
;
558 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
559 if (cookie
->data
) free(cookie
->data
);
564 free_handle_info(void *vhi
)
566 struct handle_info
*hi
= vhi
;
568 #ifdef WITH_PROTOCOL_BAHAMUT
571 inttobase64(id
, hi
->id
, IDLEN
);
572 dict_remove(nickserv_id_dict
, id
);
575 free_string_list(hi
->masks
);
576 free_string_list(hi
->ignores
);
580 delete_nick(hi
->nicks
);
586 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
587 nickserv_free_cookie(hi
->cookie
);
589 if (hi
->email_addr
) {
590 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
591 handle_info_list_remove(hil
, hi
);
593 dict_remove(nickserv_email_dict
, hi
->email_addr
);
598 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
601 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
604 struct userNode
*uNode
;
606 for (n
=0; n
<unreg_func_used
; n
++)
607 unreg_func_list
[n
](notify
, hi
);
609 if (nickserv_conf
.sync_log
) {
610 uNode
= GetUserH(hi
->users
->nick
);
614 set_user_handle_info(hi
->users
, NULL
, 0);
617 if (nickserv_conf
.disable_nicks
)
618 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
620 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
623 if (nickserv_conf
.sync_log
)
624 SyncLog("UNREGISTER %s", hi
->handle
);
626 dict_remove(nickserv_handle_dict
, hi
->handle
);
630 get_handle_info(const char *handle
)
632 return dict_find(nickserv_handle_dict
, handle
, 0);
636 get_nick_info(const char *nick
)
638 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
642 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
647 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
648 mn
= channel
->members
.list
[nn
];
649 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
656 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
657 if (!user
->handle_info
) {
659 send_message(user
, bot
, "MSG_AUTHENTICATE");
663 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
665 send_message(user
, bot
, "NSMSG_NO_ACCESS");
669 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
671 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
675 if (user
->handle_info
->opserv_level
< min_level
) {
677 send_message(user
, bot
, "NSMSG_NO_ACCESS");
685 is_valid_handle(const char *handle
)
687 struct userNode
*user
;
688 /* cant register a juped nick/service nick as handle, to prevent confusion */
689 user
= GetUserH(handle
);
690 if (user
&& IsLocal(user
))
692 /* check against maximum length */
693 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
695 /* for consistency, only allow account names that could be nicks */
696 if (!is_valid_nick(handle
))
698 /* disallow account names that look like bad words */
699 if (opserv_bad_channel(handle
))
701 /* test either regex or containing all valid chars */
702 if (nickserv_conf
.valid_handle_regex_set
) {
703 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
706 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
707 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
711 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
716 is_registerable_nick(const char *nick
)
718 /* make sure it could be used as an account name */
719 if (!is_valid_handle(nick
))
722 if (strlen(nick
) > NICKLEN
)
724 /* test either regex or as valid handle */
725 if (nickserv_conf
.valid_nick_regex_set
) {
726 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
729 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
730 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
736 /* this has been replaced with one in tools.c
739 is_valid_email_addr(const char *email)
741 return strchr(email, '@') != NULL;
747 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
749 if (hi
->email_addr
) {
750 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
751 return hi
->email_addr
;
761 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
763 struct handle_info
*hi
;
764 struct userNode
*target
;
768 if (!(hi
= get_handle_info(++name
))) {
769 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
774 if (!(target
= GetUserH(name
))) {
775 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
778 if (IsLocal(target
)) {
779 if (IsService(target
))
780 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
782 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
785 if (!(hi
= target
->handle_info
)) {
786 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
794 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
795 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
797 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
798 if ((user
->handle_info
->opserv_level
== 1000)
799 || (user
->handle_info
== hi
)
800 || ((user
->handle_info
->opserv_level
== 0)
801 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
802 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
806 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
811 get_victim_oper(struct userNode
*user
, const char *target
)
813 struct handle_info
*hi
;
814 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
816 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
817 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
820 return oper_outranks(user
, hi
) ? hi
: NULL
;
824 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
828 /* If no hostmasks on the account, allow it. */
829 if (!hi
->masks
->used
)
831 /* If any hostmask matches, allow it. */
832 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
833 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
835 /* If they are allowauthed to this account, allow it (removing the aa). */
836 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
837 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
840 /* The user is not allowed to use this account. */
845 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
848 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
852 if (len
< nickserv_conf
.password_min_length
) {
854 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
857 if (!irccasecmp(pass
, handle
)) {
859 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
862 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
865 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
868 for (i
=0; i
<len
; i
++) {
869 if (isdigit(pass
[i
]))
871 if (isupper(pass
[i
]))
873 if (islower(pass
[i
]))
876 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
877 || (cnt_upper
< nickserv_conf
.password_min_upper
)
878 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
880 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
886 static auth_func_t
*auth_func_list
;
887 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
890 reg_auth_func(auth_func_t func
)
892 if (auth_func_used
== auth_func_size
) {
893 if (auth_func_size
) {
894 auth_func_size
<<= 1;
895 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
898 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
901 auth_func_list
[auth_func_used
++] = func
;
904 static handle_rename_func_t
*rf_list
;
905 static unsigned int rf_list_size
, rf_list_used
;
908 reg_handle_rename_func(handle_rename_func_t func
)
910 if (rf_list_used
== rf_list_size
) {
913 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
916 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
919 rf_list
[rf_list_used
++] = func
;
923 generate_fakehost(struct handle_info
*handle
)
925 extern const char *hidden_host_suffix
;
926 static char buffer
[HOSTLEN
+1];
928 if (!handle
->fakehost
) {
929 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
931 } else if (handle
->fakehost
[0] == '.') {
932 /* A leading dot indicates the stored value is actually a title. */
933 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
936 return handle
->fakehost
;
940 apply_fakehost(struct handle_info
*handle
)
942 struct userNode
*target
;
947 fake
= generate_fakehost(handle
);
948 for (target
= handle
->users
; target
; target
= target
->next_authed
)
949 assign_fakehost(target
, fake
, 1);
952 void send_func_list(struct userNode
*user
)
955 struct handle_info
*old_info
;
957 old_info
= user
->handle_info
;
959 for (n
=0; n
<auth_func_used
; n
++)
960 auth_func_list
[n
](user
, old_info
);
964 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
967 struct handle_info
*old_info
;
969 /* This can happen if somebody uses COOKIE while authed, or if
970 * they re-auth to their current handle (which is silly, but users
972 if (user
->handle_info
== hi
)
975 if (user
->handle_info
) {
976 struct userNode
*other
;
979 userList_remove(&curr_helpers
, user
);
981 /* remove from next_authed linked list */
982 if (user
->handle_info
->users
== user
) {
983 user
->handle_info
->users
= user
->next_authed
;
985 for (other
= user
->handle_info
->users
;
986 other
->next_authed
!= user
;
987 other
= other
->next_authed
) ;
988 other
->next_authed
= user
->next_authed
;
990 /* if nobody left on old handle, and they're not an oper, remove !god */
991 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
992 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
993 /* record them as being last seen at this time */
994 user
->handle_info
->lastseen
= now
;
995 /* and record their hostmask */
996 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
998 old_info
= user
->handle_info
;
999 user
->handle_info
= hi
;
1000 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
1001 HANDLE_CLEAR_FLAG(hi
, HELPING
);
1003 if (GetUserH(user
->nick
)) {
1004 for (n
=0; n
<auth_func_used
; n
++)
1005 auth_func_list
[n
](user
, old_info
);
1010 struct nick_info
*ni
;
1012 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
1013 if (nickserv_conf
.warn_clone_auth
) {
1014 struct userNode
*other
;
1015 for (other
= hi
->users
; other
; other
= other
->next_authed
)
1016 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1019 user
->next_authed
= hi
->users
;
1023 userList_append(&curr_helpers
, user
);
1025 if (hi
->fakehost
|| old_info
)
1029 #ifdef WITH_PROTOCOL_BAHAMUT
1030 /* Stamp users with their account ID. */
1032 inttobase64(id
, hi
->id
, IDLEN
);
1033 #elif WITH_PROTOCOL_P10
1034 /* Stamp users with their account name. */
1035 char *id
= hi
->handle
;
1037 const char *id
= "???";
1039 if (!nickserv_conf
.disable_nicks
) {
1040 struct nick_info
*ni
;
1041 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
1042 if (!irccasecmp(user
->nick
, ni
->nick
)) {
1043 user
->modes
|= FLAGS_REGNICK
;
1048 StampUser(user
, id
, hi
->registered
);
1051 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1052 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1054 /* We cannot clear the user's account ID, unfortunately. */
1055 user
->next_authed
= NULL
;
1059 static struct handle_info
*
1060 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1062 struct handle_info
*hi
;
1063 struct nick_info
*ni
;
1064 char crypted
[MD5_CRYPT_LENGTH
];
1066 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1067 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1071 if(strlen(handle
) > 15)
1073 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1077 if (!is_secure_password(handle
, passwd
, user
))
1080 cryptpass(passwd
, crypted
);
1081 hi
= register_handle(handle
, crypted
, 0);
1082 hi
->masks
= alloc_string_list(1);
1083 hi
->ignores
= alloc_string_list(1);
1085 hi
->language
= lang_C
;
1086 hi
->registered
= now
;
1088 hi
->flags
= HI_DEFAULT_FLAGS
;
1089 if (settee
&& !no_auth
)
1090 set_user_handle_info(settee
, hi
, 1);
1093 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1094 else if (nickserv_conf
.disable_nicks
)
1095 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1096 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1097 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1099 register_nick(user
->nick
, hi
);
1100 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1102 if (settee
&& (user
!= settee
))
1103 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1108 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1110 cookie
->hi
->cookie
= cookie
;
1111 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1114 /* Contributed by the great sneep of afternet ;) */
1115 /* Since this gets used in a URL, we want to avoid stuff that confuses
1116 * email clients such as ] and ?. a-z, 0-9 only.
1118 void genpass(char *str
, int len
)
1123 for(i
= 0; i
< len
; i
++)
1127 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1128 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1136 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1138 struct handle_cookie
*cookie
;
1139 char subject
[128], body
[4096], *misc
;
1140 const char *netname
, *fmt
;
1144 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1148 cookie
= calloc(1, sizeof(*cookie
));
1150 cookie
->type
= type
;
1151 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1153 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1154 /* Adding dedicated password gen function for more control -Rubin */
1155 genpass(cookie
->cookie
, 10);
1157 *inttobase64(cookie->cookie, rand(), 5);
1158 *inttobase64(cookie->cookie+5, rand(), 5);
1161 netname
= nickserv_conf
.network_name
;
1164 switch (cookie
->type
) {
1166 hi
->passwd
[0] = 0; /* invalidate password */
1167 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1168 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1169 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1172 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1174 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1176 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1179 case PASSWORD_CHANGE
:
1180 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1181 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1182 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1184 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1186 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1187 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1190 misc
= hi
->email_addr
;
1191 hi
->email_addr
= cookie
->data
;
1192 #ifdef stupid_verify_old_email
1194 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1195 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1196 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1197 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1198 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1199 sendmail(nickserv
, hi
, subject
, body
, 1);
1200 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1201 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1204 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1205 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1206 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1207 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1208 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1209 sendmail(nickserv
, hi
, subject
, body
, 1);
1211 #ifdef stupid_verify_old_email
1214 hi
->email_addr
= misc
;
1217 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1218 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1219 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1220 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1221 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1224 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1228 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1229 nickserv_bake_cookie(cookie
);
1233 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1235 cookie
->hi
->cookie
= NULL
;
1236 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1237 nickserv_free_cookie(cookie
);
1241 nickserv_free_email_addr(void *data
)
1243 handle_info_list_clean(data
);
1248 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1250 struct handle_info_list
*hil
;
1251 /* Remove from old handle_info_list ... */
1252 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1253 handle_info_list_remove(hil
, hi
);
1254 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1255 hi
->email_addr
= NULL
;
1257 /* Add to the new list.. */
1258 if (new_email_addr
) {
1259 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1260 hil
= calloc(1, sizeof(*hil
));
1261 hil
->tag
= strdup(new_email_addr
);
1262 handle_info_list_init(hil
);
1263 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1265 handle_info_list_append(hil
, hi
);
1266 hi
->email_addr
= hil
->tag
;
1270 static NICKSERV_FUNC(cmd_register
)
1273 struct handle_info
*hi
;
1274 const char *email_addr
, *password
;
1275 char syncpass
[MD5_CRYPT_LENGTH
];
1276 int no_auth
, weblink
;
1278 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1279 /* Require the first handle registered to belong to someone +o. */
1280 reply("NSMSG_REQUIRE_OPER");
1284 if (user
->handle_info
) {
1285 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1289 if (IsRegistering(user
)) {
1290 reply("NSMSG_ALREADY_REGISTERING");
1294 if (IsStamped(user
)) {
1295 /* Unauthenticated users might still have been stamped
1296 previously and could therefore have a hidden host;
1297 do not allow them to register a new account. */
1298 reply("NSMSG_STAMPED_REGISTER");
1302 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1304 if (!is_valid_handle(argv
[1])) {
1305 reply("NSMSG_BAD_HANDLE", argv
[1]);
1310 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1311 struct handle_info_list
*hil
;
1314 /* Remember email address. */
1315 email_addr
= argv
[3];
1317 /* Check that the email address looks valid.. */
1318 if (!valid_email(email_addr
)) {
1319 reply("NSMSG_BAD_EMAIL_ADDR");
1323 /* .. and that we are allowed to send to it. */
1324 if ((str
= sendmail_prohibited_address(email_addr
))) {
1325 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1329 /* If we do email verify, make sure we don't spam the address. */
1330 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1332 for (nn
=0; nn
<hil
->used
; nn
++) {
1333 if (hil
->list
[nn
]->cookie
) {
1334 reply("NSMSG_EMAIL_UNACTIVATED");
1338 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1339 reply("NSMSG_EMAIL_OVERUSED");
1352 /* Webregister hack - send URL instead of IRC cookie
1355 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1359 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1361 /* Add any masks they should get. */
1362 if (nickserv_conf
.default_hostmask
) {
1363 string_list_append(hi
->masks
, strdup("*@*"));
1365 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1366 if (irc_in_addr_is_valid(user
->ip
) && !irc_pton(&ip
, NULL
, user
->hostname
))
1367 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1370 /* If they're the first to register, give them level 1000. */
1371 if (dict_size(nickserv_handle_dict
) == 1) {
1372 hi
->opserv_level
= 1000;
1373 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1376 /* Set their email address. */
1378 nickserv_set_email_addr(hi
, email_addr
);
1380 /* If they need to do email verification, tell them. */
1382 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1384 /* Set registering flag.. */
1385 user
->modes
|= FLAGS_REGISTERING
;
1387 if (nickserv_conf
.sync_log
) {
1388 cryptpass(password
, syncpass
);
1390 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1391 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1394 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1397 /* this wont work if email is required .. */
1398 process_adduser_pending(user
);
1403 static NICKSERV_FUNC(cmd_oregister
)
1405 struct userNode
*settee
= NULL
;
1406 struct handle_info
*hi
;
1407 char* account
= NULL
;
1413 NICKSERV_MIN_PARMS(3);
1417 if (nickserv_conf
.email_required
) {
1418 NICKSERV_MIN_PARMS(4);
1420 if (argc
>= 5) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */
1421 if (strchr(argv
[4], '@') || argc
>= 6) /* If @, its mask not nick */
1431 if (argc
>= 4) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */
1432 if (strchr(argv
[3], '@') || argc
>= 5) /* If @, its mask not nick */
1441 /* If they passed a nick, look for that user.. */
1442 if (nick
&& !(settee
= GetUserH(nick
))) {
1443 reply("MSG_NICK_UNKNOWN", argv
[4]);
1446 /* If the setee is already authed, we cant add a 2nd account for them.. */
1447 if (settee
&& settee
->handle_info
) {
1448 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1451 /* If there is no default mask in the conf, and they didn't pass a mask,
1452 * but we did find a user by nick, generate the mask */
1454 if (nickserv_conf
.default_hostmask
)
1457 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1459 reply("NSMSG_REGISTER_BAD_NICKMASK");
1464 if (!(hi
= nickserv_register(user
, settee
, account
, pass
, 0))) {
1465 return 0; /* error reply handled by above */
1468 nickserv_set_email_addr(hi
, email
);
1471 char* mask_canonicalized
= canonicalize_hostmask(strdup(mask
));
1472 string_list_append(hi
->masks
, mask_canonicalized
);
1475 if (nickserv_conf
.sync_log
)
1476 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, email
? email
: "@", user
->info
); /* Send just @ for email if none */
1481 nickserv_ignore(struct userNode
*user
, struct handle_info
*hi
, char *mask
)
1484 struct userNode
*target
;
1485 char *new_mask
= strdup(pretty_mask(mask
));
1486 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1487 if (!irccasecmp(new_mask
, hi
->ignores
->list
[i
])) {
1488 send_message(user
, nickserv
, "NSMSG_ADDIGNORE_ALREADY", new_mask
);
1493 string_list_append(hi
->ignores
, new_mask
);
1494 send_message(user
, nickserv
, "NSMSG_ADDIGNORE_SUCCESS", new_mask
);
1496 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1497 irc_silence(target
, new_mask
, 1);
1499 /* does string_list_append make a copy of new_mask and we should free() it here? */
1503 static NICKSERV_FUNC(cmd_addignore
)
1505 NICKSERV_MIN_PARMS(2);
1507 return nickserv_ignore(user
, user
->handle_info
, argv
[1]);
1510 static NICKSERV_FUNC(cmd_oaddignore
)
1512 struct handle_info
*hi
;
1514 NICKSERV_MIN_PARMS(3);
1515 if (!(hi
= get_victim_oper(user
, argv
[1])))
1518 return nickserv_ignore(user
, hi
, argv
[2]);
1522 nickserv_delignore(struct userNode
*user
, struct handle_info
*hi
, char *del_mask
)
1525 struct userNode
*target
;
1526 char *pmask
= strdup(pretty_mask(del_mask
));
1527 for (i
=0; i
<hi
->ignores
->used
; i
++) {
1528 if (!strcmp(pmask
, hi
->ignores
->list
[i
]) || !strcmp(del_mask
, hi
->ignores
->list
[i
])) {
1529 char *old_mask
= hi
->ignores
->list
[i
];
1530 hi
->ignores
->list
[i
] = hi
->ignores
->list
[--hi
->ignores
->used
];
1531 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
1532 for (target
= hi
->users
; target
; target
= target
->next_authed
) {
1533 irc_silence(user
, old_mask
, 0);
1540 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
1544 static NICKSERV_FUNC(cmd_delignore
)
1546 NICKSERV_MIN_PARMS(2);
1547 return nickserv_delignore(user
, user
->handle_info
, argv
[1]);
1550 static NICKSERV_FUNC(cmd_odelignore
)
1552 struct handle_info
*hi
;
1553 NICKSERV_MIN_PARMS(3);
1554 if (!(hi
= get_victim_oper(user
, argv
[1])))
1556 return nickserv_delignore(user
, hi
, argv
[2]);
1559 static NICKSERV_FUNC(cmd_handleinfo
)
1562 unsigned int i
, pos
=0, herelen
;
1563 struct userNode
*target
, *next_un
;
1564 struct handle_info
*hi
;
1565 const char *nsmsg_none
;
1568 if (!(hi
= user
->handle_info
)) {
1569 reply("NSMSG_MUST_AUTH");
1572 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1576 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1577 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1579 #ifdef WITH_PROTOCOL_BAHAMUT
1580 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1582 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1585 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1586 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1588 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1591 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1592 if (HANDLE_FLAGGED(hi
, FROZEN
))
1593 reply("NSMSG_HANDLEINFO_VACATION");
1595 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1596 struct do_not_register
*dnr
;
1597 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1598 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1599 if (!oper_outranks(user
, hi
))
1601 } else if (hi
!= user
->handle_info
) {
1602 reply("NSMSG_HANDLEINFO_END");
1606 if (nickserv_conf
.email_enabled
)
1607 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1611 switch (hi
->cookie
->type
) {
1612 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1613 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1614 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1615 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1616 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1622 unsigned long flen
= 1;
1623 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1625 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1626 if (hi
->flags
& 1 << i
)
1627 flags
[flen
++] = handle_flags
[i
];
1629 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1631 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1634 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1635 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1636 || (hi
->opserv_level
> 0)) {
1637 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1640 if (IsHelping(user
) || IsOper(user
))
1645 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1646 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1651 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1653 if (hi
->last_quit_host
[0])
1654 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1656 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1658 if (nickserv_conf
.disable_nicks
) {
1659 /* nicks disabled; don't show anything about registered nicks */
1660 } else if (hi
->nicks
) {
1661 struct nick_info
*ni
, *next_ni
;
1662 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1663 herelen
= strlen(ni
->nick
);
1664 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1666 goto print_nicks_buff
;
1670 memcpy(buff
+pos
, ni
->nick
, herelen
);
1671 pos
+= herelen
; buff
[pos
++] = ' ';
1675 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1680 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1683 if (hi
->masks
->used
) {
1684 for (i
=0; i
< hi
->masks
->used
; i
++) {
1685 herelen
= strlen(hi
->masks
->list
[i
]);
1686 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1688 goto print_mask_buff
;
1690 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1691 pos
+= herelen
; buff
[pos
++] = ' ';
1692 if (i
+1 == hi
->masks
->used
) {
1695 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1700 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1703 if (hi
->ignores
->used
) {
1704 for (i
=0; i
< hi
->ignores
->used
; i
++) {
1705 herelen
= strlen(hi
->ignores
->list
[i
]);
1706 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1708 goto print_ignore_buff
;
1710 memcpy(buff
+pos
, hi
->ignores
->list
[i
], herelen
);
1711 pos
+= herelen
; buff
[pos
++] = ' ';
1712 if (i
+1 == hi
->ignores
->used
) {
1715 reply("NSMSG_HANDLEINFO_IGNORES", buff
);
1720 reply("NSMSG_HANDLEINFO_IGNORES", nsmsg_none
);
1724 struct userData
*channel
, *next
;
1727 for (channel
= hi
->channels
; channel
; channel
= next
) {
1728 next
= channel
->u_next
;
1729 name
= channel
->channel
->channel
->name
;
1730 herelen
= strlen(name
);
1731 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1733 goto print_chans_buff
;
1735 if (IsUserSuspended(channel
))
1737 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1741 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1746 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1749 for (target
= hi
->users
; target
; target
= next_un
) {
1750 herelen
= strlen(target
->nick
);
1751 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1753 goto print_cnick_buff
;
1755 next_un
= target
->next_authed
;
1757 memcpy(buff
+pos
, target
->nick
, herelen
);
1758 pos
+= herelen
; buff
[pos
++] = ' ';
1762 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1767 reply("NSMSG_HANDLEINFO_END");
1771 static NICKSERV_FUNC(cmd_userinfo
)
1773 struct userNode
*target
;
1775 NICKSERV_MIN_PARMS(2);
1776 if (!(target
= GetUserH(argv
[1]))) {
1777 reply("MSG_NICK_UNKNOWN", argv
[1]);
1780 if (target
->handle_info
)
1781 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1783 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1787 static NICKSERV_FUNC(cmd_nickinfo
)
1789 struct nick_info
*ni
;
1791 NICKSERV_MIN_PARMS(2);
1792 if (!(ni
= get_nick_info(argv
[1]))) {
1793 reply("MSG_NICK_UNKNOWN", argv
[1]);
1796 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1800 static NICKSERV_FUNC(cmd_rename_handle
)
1802 struct handle_info
*hi
;
1803 struct userNode
*uNode
;
1804 char msgbuf
[MAXLEN
], *old_handle
;
1807 NICKSERV_MIN_PARMS(3);
1808 if (!(hi
= get_victim_oper(user
, argv
[1])))
1810 if (!is_valid_handle(argv
[2])) {
1811 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1814 if (get_handle_info(argv
[2])) {
1815 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1818 if(strlen(argv
[2]) > 15)
1820 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1824 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1825 hi
->handle
= strdup(argv
[2]);
1826 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1827 for (nn
=0; nn
<rf_list_used
; nn
++)
1828 rf_list
[nn
](hi
, old_handle
);
1829 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1832 if (nickserv_conf
.sync_log
) {
1833 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1834 irc_rename(uNode
, hi
->handle
);
1836 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1839 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1840 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1845 static failpw_func_t
*failpw_func_list
;
1846 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1849 reg_failpw_func(failpw_func_t func
)
1851 if (failpw_func_used
== failpw_func_size
) {
1852 if (failpw_func_size
) {
1853 failpw_func_size
<<= 1;
1854 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1856 failpw_func_size
= 8;
1857 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1860 failpw_func_list
[failpw_func_used
++] = func
;
1864 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1866 * called by nefariouses enhanced AC login-on-connect code
1869 struct handle_info
*loc_auth(char *handle
, char *password
)
1871 int pw_arg
, used
, maxlogins
;
1874 struct handle_info
*hi
;
1875 struct userNode
*other
;
1877 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1883 /* We don't know the users hostname, or anything because they
1884 * havn't registered yet. So we can only allow LOC if your
1885 * account has *@* as a hostmask.
1887 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1889 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1898 /* Responses from here on look up the language used by the handle they asked about. */
1899 if (!checkpass(password
, hi
->passwd
)) {
1902 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1905 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1906 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1907 if (++used
>= maxlogins
) {
1914 static NICKSERV_FUNC(cmd_auth
)
1916 int pw_arg
, used
, maxlogins
;
1917 struct handle_info
*hi
;
1919 struct userNode
*other
;
1921 if (user
->handle_info
) {
1922 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1925 if (IsStamped(user
)) {
1926 /* Unauthenticated users might still have been stamped
1927 previously and could therefore have a hidden host;
1928 do not allow them to authenticate. */
1929 reply("NSMSG_STAMPED_AUTH");
1933 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1935 } else if (argc
== 2) {
1936 if (nickserv_conf
.disable_nicks
) {
1937 if (!(hi
= get_handle_info(user
->nick
))) {
1938 reply("NSMSG_HANDLE_NOT_FOUND");
1942 /* try to look up their handle from their nick */
1943 struct nick_info
*ni
;
1944 ni
= get_nick_info(user
->nick
);
1946 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1953 reply("MSG_MISSING_PARAMS", argv
[0]);
1954 svccmd_send_help_brief(user
, nickserv
, cmd
);
1958 reply("NSMSG_HANDLE_NOT_FOUND");
1961 /* Responses from here on look up the language used by the handle they asked about. */
1962 passwd
= argv
[pw_arg
];
1963 if (!valid_user_for(user
, hi
)) {
1964 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1965 send_message_type(4, user
, cmd
->parent
->bot
,
1966 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1969 send_message_type(4, user
, cmd
->parent
->bot
,
1970 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1972 argv
[pw_arg
] = "BADMASK";
1975 if (!checkpass(passwd
, hi
->passwd
)) {
1977 send_message_type(4, user
, cmd
->parent
->bot
,
1978 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1979 argv
[pw_arg
] = "BADPASS";
1980 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1981 if (nickserv_conf
.autogag_enabled
) {
1982 if (!user
->auth_policer
.params
) {
1983 user
->auth_policer
.last_req
= now
;
1984 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1986 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1988 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1989 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1990 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1992 argv
[pw_arg
] = "GAGGED";
1997 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1998 send_message_type(4, user
, cmd
->parent
->bot
,
1999 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
2000 argv
[pw_arg
] = "SUSPENDED";
2003 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2004 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
2005 if (++used
>= maxlogins
) {
2006 send_message_type(4, user
, cmd
->parent
->bot
,
2007 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
2009 argv
[pw_arg
] = "MAXLOGINS";
2014 set_user_handle_info(user
, hi
, 1);
2015 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
2016 reply("NSMSG_PLEASE_SET_EMAIL");
2017 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
2018 reply("NSMSG_WEAK_PASSWORD");
2019 if (hi
->passwd
[0] != '$')
2020 cryptpass(passwd
, hi
->passwd
);
2022 /* If a channel was waiting for this user to auth,
2023 * finish adding them */
2024 process_adduser_pending(user
);
2026 reply("NSMSG_AUTH_SUCCESS");
2029 /* Set +x if autohide is on */
2030 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
2031 irc_umode(user
, "+x");
2033 if(!IsOper(user
)) /* If they arnt already opered.. */
2035 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
2036 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
2038 irc_umode(user
,nickserv_conf
.auto_admin
);
2039 reply("NSMSG_AUTO_OPER_ADMIN");
2041 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
2043 irc_umode(user
,nickserv_conf
.auto_oper
);
2044 reply("NSMSG_AUTO_OPER");
2048 /* Wipe out the pass for the logs */
2049 argv
[pw_arg
] = "****";
2053 static allowauth_func_t
*allowauth_func_list
;
2054 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
2057 reg_allowauth_func(allowauth_func_t func
)
2059 if (allowauth_func_used
== allowauth_func_size
) {
2060 if (allowauth_func_size
) {
2061 allowauth_func_size
<<= 1;
2062 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
2064 allowauth_func_size
= 8;
2065 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
2068 allowauth_func_list
[allowauth_func_used
++] = func
;
2071 static NICKSERV_FUNC(cmd_allowauth
)
2073 struct userNode
*target
;
2074 struct handle_info
*hi
;
2077 NICKSERV_MIN_PARMS(2);
2078 if (!(target
= GetUserH(argv
[1]))) {
2079 reply("MSG_NICK_UNKNOWN", argv
[1]);
2082 if (target
->handle_info
) {
2083 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
2086 if (IsStamped(target
)) {
2087 /* Unauthenticated users might still have been stamped
2088 previously and could therefore have a hidden host;
2089 do not allow them to authenticate to an account. */
2090 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
2095 else if (!(hi
= get_handle_info(argv
[2]))) {
2096 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
2100 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
2101 reply("MSG_USER_OUTRANKED", hi
->handle
);
2104 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
2105 || (hi
->opserv_level
> 0))
2106 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
2107 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
2110 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
2111 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
2112 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
2113 if (nickserv_conf
.email_enabled
)
2114 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
2116 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
2117 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
2119 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
2121 for (n
=0; n
<allowauth_func_used
; n
++)
2122 allowauth_func_list
[n
](user
, target
, hi
);
2126 static NICKSERV_FUNC(cmd_authcookie
)
2128 struct handle_info
*hi
;
2130 NICKSERV_MIN_PARMS(2);
2131 if (user
->handle_info
) {
2132 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2135 if (IsStamped(user
)) {
2136 /* Unauthenticated users might still have been stamped
2137 previously and could therefore have a hidden host;
2138 do not allow them to authenticate to an account. */
2139 reply("NSMSG_STAMPED_AUTHCOOKIE");
2142 if (!(hi
= get_handle_info(argv
[1]))) {
2143 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2146 if (!hi
->email_addr
) {
2147 reply("MSG_SET_EMAIL_ADDR");
2150 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2154 static NICKSERV_FUNC(cmd_delcookie
)
2156 struct handle_info
*hi
;
2158 hi
= user
->handle_info
;
2160 reply("NSMSG_NO_COOKIE");
2163 switch (hi
->cookie
->type
) {
2166 reply("NSMSG_MUST_TIME_OUT");
2169 nickserv_eat_cookie(hi
->cookie
);
2170 reply("NSMSG_ATE_COOKIE");
2176 static NICKSERV_FUNC(cmd_odelcookie
)
2178 struct handle_info
*hi
;
2180 NICKSERV_MIN_PARMS(2);
2182 if (!(hi
= get_victim_oper(user
, argv
[1])))
2186 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2190 nickserv_eat_cookie(hi
->cookie
);
2191 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2196 static NICKSERV_FUNC(cmd_resetpass
)
2198 struct handle_info
*hi
;
2199 char crypted
[MD5_CRYPT_LENGTH
];
2202 NICKSERV_MIN_PARMS(3);
2203 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2207 if (user
->handle_info
) {
2208 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2211 if (IsStamped(user
)) {
2212 /* Unauthenticated users might still have been stamped
2213 previously and could therefore have a hidden host;
2214 do not allow them to activate an account. */
2215 reply("NSMSG_STAMPED_RESETPASS");
2218 if (!(hi
= get_handle_info(argv
[1]))) {
2219 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2222 if (!hi
->email_addr
) {
2223 reply("MSG_SET_EMAIL_ADDR");
2226 cryptpass(argv
[2], crypted
);
2228 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2232 static NICKSERV_FUNC(cmd_cookie
)
2234 struct handle_info
*hi
;
2237 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2240 NICKSERV_MIN_PARMS(3);
2241 if (!(hi
= get_handle_info(argv
[1]))) {
2242 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2248 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2249 reply("NSMSG_HANDLE_SUSPENDED");
2254 reply("NSMSG_NO_COOKIE");
2258 /* Check validity of operation before comparing cookie to
2259 * prohibit guessing by authed users. */
2260 if (user
->handle_info
2261 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2262 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2263 reply("NSMSG_CANNOT_COOKIE");
2267 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2268 reply("NSMSG_BAD_COOKIE");
2272 switch (hi
->cookie
->type
) {
2274 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2275 set_user_handle_info(user
, hi
, 1);
2276 reply("NSMSG_HANDLE_ACTIVATED");
2277 if (nickserv_conf
.sync_log
)
2278 SyncLog("ACCOUNTACC %s", hi
->handle
);
2280 case PASSWORD_CHANGE
:
2281 set_user_handle_info(user
, hi
, 1);
2282 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2283 reply("NSMSG_PASSWORD_CHANGED");
2284 if (nickserv_conf
.sync_log
)
2285 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2288 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2290 * This should only happen if an OREGISTER was sent. Require
2291 * email must be enabled! - SiRVulcaN
2293 if (nickserv_conf
.sync_log
)
2294 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2296 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2297 reply("NSMSG_EMAIL_CHANGED");
2298 if (nickserv_conf
.sync_log
)
2299 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2302 set_user_handle_info(user
, hi
, 1);
2303 reply("NSMSG_AUTH_SUCCESS");
2306 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2307 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2311 nickserv_eat_cookie(hi
->cookie
);
2313 process_adduser_pending(user
);
2318 static NICKSERV_FUNC(cmd_oregnick
) {
2320 struct handle_info
*target
;
2321 struct nick_info
*ni
;
2323 NICKSERV_MIN_PARMS(3);
2324 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2327 if (!is_registerable_nick(nick
)) {
2328 reply("NSMSG_BAD_NICK", nick
);
2331 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2333 reply("NSMSG_NICK_EXISTS", nick
);
2336 register_nick(nick
, target
);
2337 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2341 static NICKSERV_FUNC(cmd_regnick
) {
2343 struct nick_info
*ni
;
2345 if (!is_registerable_nick(user
->nick
)) {
2346 reply("NSMSG_BAD_NICK", user
->nick
);
2349 /* count their nicks, see if it's too many */
2350 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2351 if (n
>= nickserv_conf
.nicks_per_handle
) {
2352 reply("NSMSG_TOO_MANY_NICKS");
2355 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2357 reply("NSMSG_NICK_EXISTS", user
->nick
);
2360 register_nick(user
->nick
, user
->handle_info
);
2361 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2365 static NICKSERV_FUNC(cmd_pass
)
2367 struct handle_info
*hi
;
2368 const char *old_pass
, *new_pass
;
2370 NICKSERV_MIN_PARMS(3);
2371 hi
= user
->handle_info
;
2375 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2376 if (!checkpass(old_pass
, hi
->passwd
)) {
2377 argv
[1] = "BADPASS";
2378 reply("NSMSG_PASSWORD_INVALID");
2381 cryptpass(new_pass
, hi
->passwd
);
2382 if (nickserv_conf
.sync_log
)
2383 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2385 reply("NSMSG_PASS_SUCCESS");
2390 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2393 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2394 for (i
=0; i
<hi
->masks
->used
; i
++) {
2395 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2396 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2401 string_list_append(hi
->masks
, new_mask
);
2402 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2406 static NICKSERV_FUNC(cmd_addmask
)
2409 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2410 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2414 if (!is_gline(argv
[1])) {
2415 reply("NSMSG_MASK_INVALID", argv
[1]);
2418 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2422 static NICKSERV_FUNC(cmd_oaddmask
)
2424 struct handle_info
*hi
;
2426 NICKSERV_MIN_PARMS(3);
2427 if (!(hi
= get_victim_oper(user
, argv
[1])))
2429 return nickserv_addmask(user
, hi
, argv
[2]);
2433 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2436 for (i
=0; i
<hi
->masks
->used
; i
++) {
2437 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2438 char *old_mask
= hi
->masks
->list
[i
];
2439 if (hi
->masks
->used
== 1) {
2440 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2443 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2444 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2449 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2453 static NICKSERV_FUNC(cmd_delmask
)
2455 NICKSERV_MIN_PARMS(2);
2456 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2459 static NICKSERV_FUNC(cmd_odelmask
)
2461 struct handle_info
*hi
;
2462 NICKSERV_MIN_PARMS(3);
2463 if (!(hi
= get_victim_oper(user
, argv
[1])))
2465 return nickserv_delmask(user
, hi
, argv
[2]);
2469 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2470 unsigned int nn
, add
= 1, pos
;
2471 unsigned long added
, removed
, flag
;
2473 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2475 case '+': add
= 1; break;
2476 case '-': add
= 0; break;
2478 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2479 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2482 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2483 /* cheesy avoidance of looking up the flag name.. */
2484 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2487 flag
= 1 << (pos
- 1);
2489 added
|= flag
, removed
&= ~flag
;
2491 removed
|= flag
, added
&= ~flag
;
2496 *premoved
= removed
;
2501 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2503 unsigned long before
, after
, added
, removed
;
2504 struct userNode
*uNode
;
2506 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2507 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2509 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2510 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2512 /* Strip helping flag if they're only a support helper and not
2513 * currently in #support. */
2514 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2515 struct channelList
*schannels
;
2517 schannels
= chanserv_support_channels();
2518 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2519 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2520 if (GetUserMode(schannels
->list
[ii
], uNode
))
2522 if (ii
< schannels
->used
)
2526 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2529 if (after
&& !before
) {
2530 /* Add user to current helper list. */
2531 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2532 userList_append(&curr_helpers
, uNode
);
2533 } else if (!after
&& before
) {
2534 /* Remove user from current helper list. */
2535 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2536 userList_remove(&curr_helpers
, uNode
);
2543 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2547 char *set_display
[] = {
2548 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2549 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2550 "FAKEHOST", "TITLE", "EPITHET", "ADVANCED"
2553 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2554 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_HEADER");
2556 /* Do this so options are presented in a consistent order. */
2557 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2558 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2559 opt(user
, hi
, override
, 0, NULL
);
2560 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_END");
2563 static NICKSERV_FUNC(cmd_set
)
2565 struct handle_info
*hi
;
2568 hi
= user
->handle_info
;
2570 set_list(user
, hi
, 0);
2573 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2574 reply("NSMSG_INVALID_OPTION", argv
[1]);
2577 return opt(user
, hi
, 0, argc
-1, argv
+1);
2580 static NICKSERV_FUNC(cmd_oset
)
2582 struct handle_info
*hi
;
2585 NICKSERV_MIN_PARMS(2);
2587 if (!(hi
= get_victim_oper(user
, argv
[1])))
2591 set_list(user
, hi
, 0);
2595 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2596 reply("NSMSG_INVALID_OPTION", argv
[2]);
2600 return opt(user
, hi
, 1, argc
-2, argv
+2);
2603 static OPTION_FUNC(opt_info
)
2607 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2609 hi
->infoline
= NULL
;
2611 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2615 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2616 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2620 static OPTION_FUNC(opt_width
)
2623 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2625 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2626 hi
->screen_width
= MIN_LINE_SIZE
;
2627 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2628 hi
->screen_width
= MAX_LINE_SIZE
;
2630 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2634 static OPTION_FUNC(opt_tablewidth
)
2637 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2639 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2640 hi
->table_width
= MIN_LINE_SIZE
;
2641 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2642 hi
->table_width
= MAX_LINE_SIZE
;
2644 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2648 static OPTION_FUNC(opt_color
)
2651 if (enabled_string(argv
[1]))
2652 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2653 else if (disabled_string(argv
[1]))
2654 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2656 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2661 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2665 static OPTION_FUNC(opt_privmsg
)
2668 if (enabled_string(argv
[1]))
2669 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2670 else if (disabled_string(argv
[1]))
2671 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2673 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2678 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2682 static OPTION_FUNC(opt_autohide
)
2685 if (enabled_string(argv
[1]))
2686 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2687 else if (disabled_string(argv
[1]))
2688 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2690 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2695 send_message(user
, nickserv
, "NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2699 static OPTION_FUNC(opt_style
)
2704 if (!irccasecmp(argv
[1], "Clean"))
2705 hi
->userlist_style
= HI_STYLE_CLEAN
;
2706 else if (!irccasecmp(argv
[1], "Advanced"))
2707 hi
->userlist_style
= HI_STYLE_ADVANCED
;
2708 else if (!irccasecmp(argv
[1], "Classic"))
2709 hi
->userlist_style
= HI_STYLE_CLASSIC
;
2710 else /* Default to normal */
2711 hi
->userlist_style
= HI_STYLE_NORMAL
;
2712 } /* TODO: give error if unknow style is chosen */
2714 switch (hi
->userlist_style
) {
2715 case HI_STYLE_ADVANCED
:
2718 case HI_STYLE_CLASSIC
:
2721 case HI_STYLE_CLEAN
:
2724 case HI_STYLE_NORMAL
:
2729 send_message(user
, nickserv
, "NSMSG_SET_STYLE", style
);
2733 static OPTION_FUNC(opt_announcements
)
2738 if (enabled_string(argv
[1]))
2739 hi
->announcements
= 'y';
2740 else if (disabled_string(argv
[1]))
2741 hi
->announcements
= 'n';
2742 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2743 hi
->announcements
= '?';
2745 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2750 switch (hi
->announcements
) {
2751 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2752 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2753 case '?': choice
= "default"; break;
2754 default: choice
= "unknown"; break;
2756 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2760 static OPTION_FUNC(opt_password
)
2763 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2768 cryptpass(argv
[1], hi
->passwd
);
2770 if (nickserv_conf
.sync_log
)
2771 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2773 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2777 static OPTION_FUNC(opt_flags
)
2780 unsigned int ii
, flen
;
2783 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2788 nickserv_apply_flags(user
, hi
, argv
[1]);
2790 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2791 if (hi
->flags
& (1 << ii
))
2792 flags
[flen
++] = handle_flags
[ii
];
2795 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2797 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2801 static OPTION_FUNC(opt_email
)
2805 if (!valid_email(argv
[1])) {
2806 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2809 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2810 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2813 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2814 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2816 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2818 nickserv_set_email_addr(hi
, argv
[1]);
2820 nickserv_eat_cookie(hi
->cookie
);
2821 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2824 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2828 static OPTION_FUNC(opt_maxlogins
)
2830 unsigned char maxlogins
;
2832 maxlogins
= strtoul(argv
[1], NULL
, 0);
2833 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2834 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2837 hi
->maxlogins
= maxlogins
;
2839 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2840 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2844 static OPTION_FUNC(opt_advanced
)
2847 if (enabled_string(argv
[1]))
2848 HANDLE_SET_FLAG(hi
, ADVANCED
);
2849 else if (disabled_string(argv
[1]))
2850 HANDLE_CLEAR_FLAG(hi
, ADVANCED
);
2852 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2857 send_message(user
, nickserv
, "NSMSG_SET_ADVANCED", user_find_message(user
, HANDLE_FLAGGED(hi
, ADVANCED
) ? "MSG_ON" : "MSG_OFF"));
2861 static OPTION_FUNC(opt_language
)
2863 struct language
*lang
;
2865 lang
= language_find(argv
[1]);
2866 if (irccasecmp(lang
->name
, argv
[1]))
2867 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2868 hi
->language
= lang
;
2870 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2875 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2876 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2878 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2879 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2880 && (user
->handle_info
->opserv_level
< 1000))) {
2881 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2884 if ((user
->handle_info
->opserv_level
< new_level
)
2885 || ((user
->handle_info
->opserv_level
== new_level
)
2886 && (user
->handle_info
->opserv_level
< 1000))) {
2887 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2890 if (user
->handle_info
== target
) {
2891 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2894 if (target
->opserv_level
== new_level
)
2896 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2897 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2898 target
->opserv_level
= new_level
;
2902 static OPTION_FUNC(opt_level
)
2907 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2911 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2912 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2916 static OPTION_FUNC(opt_epithet
)
2918 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2920 struct userNode
*target
, *next_un
;
2923 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2927 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2931 if ((epithet
[0] == '*') && !epithet
[1])
2934 hi
->epithet
= strdup(epithet
);
2936 for (target
= hi
->users
; target
; target
= next_un
) {
2937 irc_swhois(nickserv
, target
, hi
->epithet
);
2939 next_un
= target
->next_authed
;
2944 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2946 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2950 static OPTION_FUNC(opt_title
)
2954 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2956 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2961 if (strchr(title
, '.')) {
2962 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2965 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2966 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2967 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2972 if (!strcmp(title
, "*")) {
2973 hi
->fakehost
= NULL
;
2975 hi
->fakehost
= malloc(strlen(title
)+2);
2976 hi
->fakehost
[0] = '.';
2977 strcpy(hi
->fakehost
+1, title
);
2980 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2981 title
= hi
->fakehost
+ 1;
2985 title
= user_find_message(user
, "MSG_NONE");
2986 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2991 check_vhost(char *vhost
, struct userNode
*user
)
2993 unsigned int y
, depth
;
2996 // check for a dot in the vhost
2997 if(strchr(vhost
, '.') == NULL
) {
2998 send_message(user
, nickserv
, "NSMSG_NOT_VALID_FAKEHOST_DOT", vhost
);
3002 // check for a @ in the vhost
3003 if(strchr(vhost
, '@') != NULL
) {
3004 send_message(user
, nickserv
, "NSMSG_NOT_VALID_FAKEHOST_AT", vhost
);
3008 // check for denied words, inspired by monk at paki.sex
3009 for(y
= 0; y
< nickserv_conf
.denied_fakehost_words
->used
; y
++) {
3010 if(strstr(vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]) != NULL
) {
3011 send_message(user
, nickserv
, "NSMSG_DENIED_FAKEHOST_WORD", vhost
, nickserv_conf
.denied_fakehost_words
->list
[y
]);
3016 // check for ircu's HOSTLEN length.
3017 if(strlen(vhost
) >= HOSTLEN
) {
3018 send_message(user
, nickserv
, "NSMSG_NOT_VALID_FAKEHOST_LEN", vhost
);
3022 if (vhost
[strspn(vhost
, "0123456789.")]) {
3023 hostname
= vhost
+ strlen(vhost
);
3024 for (depth
= 1; depth
&& (hostname
> vhost
); depth
--) {
3026 while ((hostname
> vhost
) && (*hostname
!= '.')) hostname
--;
3029 if (*hostname
== '.') hostname
++; /* advance past last dot we saw */
3030 if(strlen(hostname
) > 4) {
3031 send_message(user
, nickserv
, "NSMSG_NOT_VALID_FAKEHOST_TLD_LEN", vhost
);
3039 static OPTION_FUNC(opt_fakehost
)
3043 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
3045 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
3050 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
3051 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
3055 if (!strcmp(fake
, "*")) {
3056 hi
->fakehost
= NULL
;
3058 if (!check_vhost(argv
[1], user
))
3061 hi
->fakehost
= strdup(fake
);
3063 fake
= hi
->fakehost
;
3066 fake
= generate_fakehost(hi
);
3069 fake
= user_find_message(user
, "MSG_NONE");
3070 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
3074 static OPTION_FUNC(opt_note
)
3077 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
3082 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
3087 if ((text
[0] == '*') && !text
[1])
3090 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
3095 send_message(user
, nickserv
, "NSMSG_SET_NOTE", hi
->note
->note
);
3099 static NICKSERV_FUNC(cmd_reclaim
)
3101 struct handle_info
*hi
;
3102 struct nick_info
*ni
;
3103 struct userNode
*victim
;
3105 NICKSERV_MIN_PARMS(2);
3106 hi
= user
->handle_info
;
3107 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
3109 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
3112 if (ni
->owner
!= user
->handle_info
) {
3113 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
3116 victim
= GetUserH(ni
->nick
);
3118 reply("MSG_NICK_UNKNOWN", ni
->nick
);
3121 if (victim
== user
) {
3122 reply("NSMSG_NICK_USER_YOU");
3125 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
3126 switch (nickserv_conf
.reclaim_action
) {
3127 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
3128 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
3129 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
3130 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
3135 static NICKSERV_FUNC(cmd_unregnick
)
3138 struct handle_info
*hi
;
3139 struct nick_info
*ni
;
3141 hi
= user
->handle_info
;
3142 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
3143 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
3145 reply("NSMSG_UNKNOWN_NICK", nick
);
3148 if (hi
!= ni
->owner
) {
3149 reply("NSMSG_NOT_YOUR_NICK", nick
);
3152 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3157 static NICKSERV_FUNC(cmd_ounregnick
)
3159 struct nick_info
*ni
;
3161 NICKSERV_MIN_PARMS(2);
3162 if (!(ni
= get_nick_info(argv
[1]))) {
3163 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
3166 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
3167 reply("MSG_USER_OUTRANKED", ni
->nick
);
3170 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
3175 static NICKSERV_FUNC(cmd_unregister
)
3177 struct handle_info
*hi
;
3180 NICKSERV_MIN_PARMS(2);
3181 hi
= user
->handle_info
;
3184 if (checkpass(passwd
, hi
->passwd
)) {
3185 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3188 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
3189 reply("NSMSG_PASSWORD_INVALID");
3194 static NICKSERV_FUNC(cmd_ounregister
)
3196 struct handle_info
*hi
;
3198 NICKSERV_MIN_PARMS(2);
3199 if (!(hi
= get_victim_oper(user
, argv
[1])))
3201 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
3205 static NICKSERV_FUNC(cmd_status
)
3207 if (nickserv_conf
.disable_nicks
) {
3208 reply("NSMSG_GLOBAL_STATS_NONICK",
3209 dict_size(nickserv_handle_dict
));
3211 if (user
->handle_info
) {
3213 struct nick_info
*ni
;
3214 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
3215 reply("NSMSG_HANDLE_STATS", cnt
);
3217 reply("NSMSG_HANDLE_NONE");
3219 reply("NSMSG_GLOBAL_STATS",
3220 dict_size(nickserv_handle_dict
),
3221 dict_size(nickserv_nick_dict
));
3226 static NICKSERV_FUNC(cmd_ghost
)
3228 struct userNode
*target
;
3229 char reason
[MAXLEN
];
3231 NICKSERV_MIN_PARMS(2);
3232 if (!(target
= GetUserH(argv
[1]))) {
3233 reply("MSG_NICK_UNKNOWN", argv
[1]);
3236 if (target
== user
) {
3237 reply("NSMSG_CANNOT_GHOST_SELF");
3240 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3241 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3244 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3245 DelUser(target
, nickserv
, 1, reason
);
3246 reply("NSMSG_GHOST_KILLED", argv
[1]);
3250 static NICKSERV_FUNC(cmd_vacation
)
3252 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3253 reply("NSMSG_ON_VACATION");
3258 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3260 struct handle_info
*hi
;
3263 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3265 #ifdef WITH_PROTOCOL_BAHAMUT
3268 saxdb_start_record(ctx
, iter_key(it
), 0);
3269 if (hi
->announcements
!= '?') {
3270 flags
[0] = hi
->announcements
;
3272 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3275 struct handle_cookie
*cookie
= hi
->cookie
;
3278 switch (cookie
->type
) {
3279 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3280 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3281 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3282 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3283 default: type
= NULL
; break;
3286 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3287 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3288 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3290 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3291 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3292 saxdb_end_record(ctx
);
3296 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3298 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3300 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3301 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3302 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3303 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3304 saxdb_end_record(ctx
);
3308 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3312 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3313 if (hi
->flags
& (1 << ii
))
3314 flags
[flen
++] = handle_flags
[ii
];
3316 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3318 #ifdef WITH_PROTOCOL_BAHAMUT
3319 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
3322 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3323 if (hi
->last_quit_host
[0])
3324 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3325 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3326 if (hi
->masks
->used
)
3327 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3328 if (hi
->ignores
->used
)
3329 saxdb_write_string_list(ctx
, KEY_IGNORES
, hi
->ignores
);
3331 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3333 struct string_list
*slist
;
3334 struct nick_info
*ni
;
3336 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3337 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3338 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3342 if (hi
->opserv_level
)
3343 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3344 if (hi
->language
!= lang_C
)
3345 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3346 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3347 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3348 if (hi
->screen_width
)
3349 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3350 if (hi
->table_width
)
3351 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3352 flags
[0] = hi
->userlist_style
;
3354 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3355 saxdb_end_record(ctx
);
3361 static handle_merge_func_t
*handle_merge_func_list
;
3362 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3365 reg_handle_merge_func(handle_merge_func_t func
)
3367 if (handle_merge_func_used
== handle_merge_func_size
) {
3368 if (handle_merge_func_size
) {
3369 handle_merge_func_size
<<= 1;
3370 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3372 handle_merge_func_size
= 8;
3373 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3376 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3379 static NICKSERV_FUNC(cmd_merge
)
3381 struct handle_info
*hi_from
, *hi_to
;
3382 struct userNode
*last_user
;
3383 struct userData
*cList
, *cListNext
;
3384 unsigned int ii
, jj
, n
;
3385 char buffer
[MAXLEN
];
3387 NICKSERV_MIN_PARMS(3);
3389 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
3391 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
3393 if (hi_to
== hi_from
) {
3394 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3398 for (n
=0; n
<handle_merge_func_used
; n
++)
3399 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3401 /* Append "from" handle's nicks to "to" handle's nick list. */
3403 struct nick_info
*last_ni
;
3404 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3405 last_ni
->next
= hi_from
->nicks
;
3407 while (hi_from
->nicks
) {
3408 hi_from
->nicks
->owner
= hi_to
;
3409 hi_from
->nicks
= hi_from
->nicks
->next
;
3412 /* Merge the hostmasks. */
3413 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3414 char *mask
= hi_from
->masks
->list
[ii
];
3415 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3416 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3418 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3419 string_list_append(hi_to
->masks
, strdup(mask
));
3422 /* Merge the ignores. */
3423 for (ii
=0; ii
<hi_from
->ignores
->used
; ii
++) {
3424 char *ignore
= hi_from
->ignores
->list
[ii
];
3425 for (jj
=0; jj
<hi_to
->ignores
->used
; jj
++)
3426 if (match_ircglobs(hi_to
->ignores
->list
[jj
], ignore
))
3428 if (jj
==hi_to
->ignores
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3429 string_list_append(hi_to
->ignores
, strdup(ignore
));
3432 /* Merge the lists of authed users. */
3434 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3435 last_user
->next_authed
= hi_from
->users
;
3437 hi_to
->users
= hi_from
->users
;
3439 /* Repoint the old "from" handle's users. */
3440 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3441 last_user
->handle_info
= hi_to
;
3443 hi_from
->users
= NULL
;
3445 /* Merge channel userlists. */
3446 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3447 struct userData
*cList2
;
3448 cListNext
= cList
->u_next
;
3449 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3450 if (cList
->channel
== cList2
->channel
)
3452 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3453 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
);
3454 /* keep cList2 in hi_to; remove cList from hi_from */
3455 del_channel_user(cList
, 1);
3458 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
);
3459 /* remove the lower-ranking cList2 from hi_to */
3460 del_channel_user(cList2
, 1);
3462 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3464 /* cList needs to be moved from hi_from to hi_to */
3465 cList
->handle
= hi_to
;
3466 /* Remove from linked list for hi_from */
3467 assert(!cList
->u_prev
);
3468 hi_from
->channels
= cList
->u_next
;
3470 cList
->u_next
->u_prev
= cList
->u_prev
;
3471 /* Add to linked list for hi_to */
3472 cList
->u_prev
= NULL
;
3473 cList
->u_next
= hi_to
->channels
;
3474 if (hi_to
->channels
)
3475 hi_to
->channels
->u_prev
= cList
;
3476 hi_to
->channels
= cList
;
3480 /* Do they get an OpServ level promotion? */
3481 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3482 hi_to
->opserv_level
= hi_from
->opserv_level
;
3484 /* What about last seen time? */
3485 if (hi_from
->lastseen
> hi_to
->lastseen
)
3486 hi_to
->lastseen
= hi_from
->lastseen
;
3488 /* Does a fakehost carry over? (This intentionally doesn't set it
3489 * for users previously attached to hi_to. They'll just have to
3492 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3493 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3495 /* Notify of success. */
3496 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3497 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3498 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3500 /* Unregister the "from" handle. */
3501 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3506 struct nickserv_discrim
{
3507 unsigned int limit
, min_level
, max_level
;
3508 unsigned long flags_on
, flags_off
;
3509 time_t min_registered
, max_registered
;
3511 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3512 const char *nickmask
;
3513 const char *hostmask
;
3514 const char *handlemask
;
3515 const char *emailmask
;
3518 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3520 struct discrim_apply_info
{
3521 struct nickserv_discrim
*discrim
;
3522 discrim_search_func func
;
3523 struct userNode
*source
;
3524 unsigned int matched
;
3527 static struct nickserv_discrim
*
3528 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3531 struct nickserv_discrim
*discrim
;
3533 discrim
= malloc(sizeof(*discrim
));
3534 memset(discrim
, 0, sizeof(*discrim
));
3535 discrim
->min_level
= 0;
3536 discrim
->max_level
= ~0;
3537 discrim
->limit
= 50;
3538 discrim
->min_registered
= 0;
3539 discrim
->max_registered
= INT_MAX
;
3540 discrim
->lastseen
= now
;
3542 for (i
=0; i
<argc
; i
++) {
3543 if (i
== argc
- 1) {
3544 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3547 if (!irccasecmp(argv
[i
], "limit")) {
3548 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3549 } else if (!irccasecmp(argv
[i
], "flags")) {
3550 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3551 } else if (!irccasecmp(argv
[i
], "registered")) {
3552 const char *cmp
= argv
[++i
];
3553 if (cmp
[0] == '<') {
3554 if (cmp
[1] == '=') {
3555 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3557 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3559 } else if (cmp
[0] == '=') {
3560 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3561 } else if (cmp
[0] == '>') {
3562 if (cmp
[1] == '=') {
3563 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3565 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3568 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3570 } else if (!irccasecmp(argv
[i
], "seen")) {
3571 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3572 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3573 discrim
->nickmask
= argv
[++i
];
3574 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3576 if (!irccasecmp(argv
[i
], "exact")) {
3577 if (i
== argc
- 1) {
3578 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3581 discrim
->hostmask_type
= EXACT
;
3582 } else if (!irccasecmp(argv
[i
], "subset")) {
3583 if (i
== argc
- 1) {
3584 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3587 discrim
->hostmask_type
= SUBSET
;
3588 } else if (!irccasecmp(argv
[i
], "superset")) {
3589 if (i
== argc
- 1) {
3590 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3593 discrim
->hostmask_type
= SUPERSET
;
3594 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3595 if (i
== argc
- 1) {
3596 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3599 discrim
->hostmask_type
= LASTQUIT
;
3602 discrim
->hostmask_type
= SUPERSET
;
3604 discrim
->hostmask
= argv
[++i
];
3605 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3606 if (!irccasecmp(argv
[++i
], "*")) {
3607 discrim
->handlemask
= 0;
3609 discrim
->handlemask
= argv
[i
];
3611 } else if (!irccasecmp(argv
[i
], "email")) {
3612 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3613 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3615 } else if (!irccasecmp(argv
[++i
], "*")) {
3616 discrim
->emailmask
= 0;
3618 discrim
->emailmask
= argv
[i
];
3620 } else if (!irccasecmp(argv
[i
], "access")) {
3621 const char *cmp
= argv
[++i
];
3622 if (cmp
[0] == '<') {
3623 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3624 if (cmp
[1] == '=') {
3625 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3627 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3629 } else if (cmp
[0] == '=') {
3630 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3631 } else if (cmp
[0] == '>') {
3632 if (cmp
[1] == '=') {
3633 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3635 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3638 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3641 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3652 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3654 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3655 || (discrim
->flags_off
& hi
->flags
)
3656 || (discrim
->min_registered
> hi
->registered
)
3657 || (discrim
->max_registered
< hi
->registered
)
3658 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3659 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3660 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3661 || (discrim
->min_level
> hi
->opserv_level
)
3662 || (discrim
->max_level
< hi
->opserv_level
)) {
3665 if (discrim
->hostmask
) {
3667 for (i
=0; i
<hi
->masks
->used
; i
++) {
3668 const char *mask
= hi
->masks
->list
[i
];
3669 if ((discrim
->hostmask_type
== SUBSET
)
3670 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3671 else if ((discrim
->hostmask_type
== EXACT
)
3672 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3673 else if ((discrim
->hostmask_type
== SUPERSET
)
3674 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3675 else if ((discrim
->hostmask_type
== LASTQUIT
)
3676 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3678 if (i
==hi
->masks
->used
) return 0;
3680 if (discrim
->nickmask
) {
3681 struct nick_info
*nick
= hi
->nicks
;
3683 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3686 if (!nick
) return 0;
3692 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3694 dict_iterator_t it
, next
;
3695 unsigned int matched
;
3697 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3698 it
&& (matched
< discrim
->limit
);
3700 next
= iter_next(it
);
3701 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3702 dsf(source
, iter_data(it
));
3710 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3712 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3716 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3721 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3723 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3724 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
3728 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3730 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3731 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3732 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3733 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3734 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3738 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3740 struct handle_info_list hil
;
3741 struct helpfile_table tbl
;
3746 memset(&hil
, 0, sizeof(hil
));
3747 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3748 struct handle_info
*hi
= iter_data(it
);
3749 if (hi
->opserv_level
)
3750 handle_info_list_append(&hil
, hi
);
3752 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3753 tbl
.length
= hil
.used
+ 1;
3755 tbl
.flags
= TABLE_NO_FREE
| TABLE_REPEAT_ROWS
| TABLE_REPEAT_HEADERS
;
3756 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3757 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3760 for (ii
= 0; ii
< hil
.used
; ) {
3761 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3762 ary
[0] = hil
.list
[ii
]->handle
;
3763 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3764 tbl
.contents
[++ii
] = ary
;
3766 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3767 /*reply("MSG_MATCH_COUNT", hil.used); */
3768 for (ii
= 0; ii
< hil
.used
; ii
++)
3769 free(tbl
.contents
[ii
]);
3774 static NICKSERV_FUNC(cmd_search
)
3776 struct nickserv_discrim
*discrim
;
3777 discrim_search_func action
;
3778 struct svccmd
*subcmd
;
3779 unsigned int matches
;
3782 NICKSERV_MIN_PARMS(3);
3783 sprintf(buf
, "search %s", argv
[1]);
3784 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3785 if (!irccasecmp(argv
[1], "print"))
3786 action
= search_print_func
;
3787 else if (!irccasecmp(argv
[1], "count"))
3788 action
= search_count_func
;
3789 else if (!irccasecmp(argv
[1], "unregister"))
3790 action
= search_unregister_func
;
3792 reply("NSMSG_INVALID_ACTION", argv
[1]);
3796 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3799 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3803 if (action
== search_print_func
)
3804 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3805 else if (action
== search_count_func
)
3806 discrim
->limit
= INT_MAX
;
3808 matches
= nickserv_discrim_search(discrim
, action
, user
);
3811 reply("MSG_MATCH_COUNT", matches
);
3813 reply("MSG_NO_MATCHES");
3819 static MODCMD_FUNC(cmd_checkpass
)
3821 struct handle_info
*hi
;
3823 NICKSERV_MIN_PARMS(3);
3824 if (!(hi
= get_handle_info(argv
[1]))) {
3825 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3828 if (checkpass(argv
[2], hi
->passwd
))
3829 reply("CHECKPASS_YES");
3831 reply("CHECKPASS_NO");
3837 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3840 struct string_list
*masks
, *slist
, *ignores
;
3841 struct handle_info
*hi
;
3842 struct userNode
*authed_users
;
3843 struct userData
*channels
;
3844 unsigned long int id
;
3847 char *setter
, *note
;
3850 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3851 id
= str
? strtoul(str
, NULL
, 0) : 0;
3852 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3854 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3857 if ((hi
= get_handle_info(handle
))) {
3858 authed_users
= hi
->users
;
3859 channels
= hi
->channels
;
3861 hi
->channels
= NULL
;
3862 dict_remove(nickserv_handle_dict
, hi
->handle
);
3864 authed_users
= NULL
;
3867 hi
= register_handle(handle
, str
, id
);
3869 hi
->users
= authed_users
;
3870 while (authed_users
) {
3871 authed_users
->handle_info
= hi
;
3872 authed_users
= authed_users
->next_authed
;
3875 hi
->channels
= channels
;
3876 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3877 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3878 ignores
= database_get_data(obj
, KEY_IGNORES
, RECDB_STRING_LIST
);
3879 hi
->ignores
= ignores
? string_list_copy(ignores
) : alloc_string_list(1);
3880 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3881 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3882 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3883 hi
->language
= language_find(str
? str
: "C");
3884 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3885 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3886 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3888 hi
->infoline
= strdup(str
);
3889 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3890 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3891 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3892 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3893 /* We want to read the nicks even if disable_nicks is set. This is so
3894 * that we don't lose the nick data entirely. */
3895 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3897 for (ii
=0; ii
<slist
->used
; ii
++)
3898 register_nick(slist
->list
[ii
], hi
);
3900 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3902 for (ii
=0; str
[ii
]; ii
++)
3903 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3905 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3906 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
3907 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3908 hi
->announcements
= str
? str
[0] : '?';
3909 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3910 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3911 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3912 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3913 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3915 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3917 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3918 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3920 nickserv_set_email_addr(hi
, str
);
3921 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3923 hi
->epithet
= strdup(str
);
3924 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
3926 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
3927 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
3928 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3929 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
3930 if (setter
&& date
&& note
)
3932 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
3937 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3939 hi
->fakehost
= strdup(str
);
3941 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3943 const char *data
, *type
, *expires
, *cookie_str
;
3944 struct handle_cookie
*cookie
;
3946 cookie
= calloc(1, sizeof(*cookie
));
3947 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3948 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3949 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3950 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3951 if (!type
|| !expires
|| !cookie_str
) {
3952 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3955 if (!irccasecmp(type
, KEY_ACTIVATION
))
3956 cookie
->type
= ACTIVATION
;
3957 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3958 cookie
->type
= PASSWORD_CHANGE
;
3959 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3960 cookie
->type
= EMAIL_CHANGE
;
3961 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3962 cookie
->type
= ALLOWAUTH
;
3964 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3967 cookie
->expires
= strtoul(expires
, NULL
, 0);
3968 if (cookie
->expires
< now
)
3971 cookie
->data
= strdup(data
);
3972 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3976 nickserv_bake_cookie(cookie
);
3978 nickserv_free_cookie(cookie
);
3983 nickserv_saxdb_read(dict_t db
) {
3985 struct record_data
*rd
;
3987 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3989 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3994 static NICKSERV_FUNC(cmd_mergedb
)
3996 struct timeval start
, stop
;
3999 NICKSERV_MIN_PARMS(2);
4000 gettimeofday(&start
, NULL
);
4001 if (!(db
= parse_database(argv
[1]))) {
4002 reply("NSMSG_DB_UNREADABLE", argv
[1]);
4005 nickserv_saxdb_read(db
);
4007 gettimeofday(&stop
, NULL
);
4008 stop
.tv_sec
-= start
.tv_sec
;
4009 stop
.tv_usec
-= start
.tv_usec
;
4010 if (stop
.tv_usec
< 0) {
4012 stop
.tv_usec
+= 1000000;
4014 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
4019 expire_handles(UNUSED_ARG(void *data
))
4021 dict_iterator_t it
, next
;
4023 struct handle_info
*hi
;
4025 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
4026 next
= iter_next(it
);
4028 if ((hi
->opserv_level
> 0)
4030 || HANDLE_FLAGGED(hi
, FROZEN
)
4031 || HANDLE_FLAGGED(hi
, NODELETE
)) {
4034 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
4035 if ((now
- hi
->lastseen
) > expiry
) {
4036 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
4037 nickserv_unregister_handle(hi
, NULL
, NULL
);
4041 if (nickserv_conf
.handle_expire_frequency
)
4042 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4046 nickserv_load_dict(const char *fname
)
4050 if (!(file
= fopen(fname
, "r"))) {
4051 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
4054 while (!feof(file
)) {
4055 fgets(line
, sizeof(line
), file
);
4058 if (line
[strlen(line
)-1] == '\n')
4059 line
[strlen(line
)-1] = 0;
4060 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
4063 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
4066 static enum reclaim_action
4067 reclaim_action_from_string(const char *str
) {
4069 return RECLAIM_NONE
;
4070 else if (!irccasecmp(str
, "warn"))
4071 return RECLAIM_WARN
;
4072 else if (!irccasecmp(str
, "svsnick"))
4073 return RECLAIM_SVSNICK
;
4074 else if (!irccasecmp(str
, "kill"))
4075 return RECLAIM_KILL
;
4077 return RECLAIM_NONE
;
4081 nickserv_conf_read(void)
4083 dict_t conf_node
, child
;
4086 struct string_list
*strlist
;
4088 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
4089 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
4092 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
4094 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
4095 if (nickserv_conf
.valid_handle_regex_set
)
4096 regfree(&nickserv_conf
.valid_handle_regex
);
4098 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4099 nickserv_conf
.valid_handle_regex_set
= !err
;
4100 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
4102 nickserv_conf
.valid_handle_regex_set
= 0;
4104 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
4105 if (nickserv_conf
.valid_nick_regex_set
)
4106 regfree(&nickserv_conf
.valid_nick_regex
);
4108 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
4109 nickserv_conf
.valid_nick_regex_set
= !err
;
4110 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
4112 nickserv_conf
.valid_nick_regex_set
= 0;
4114 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
4116 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
4117 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
4118 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
4119 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
4120 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
4121 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
4122 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
4123 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
4124 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
4125 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
4126 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
4127 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
4128 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
4129 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
4130 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
4131 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
4132 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
4133 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
4134 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
4135 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
4136 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
4137 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
4138 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
4139 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
4140 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
4142 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
4143 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
4144 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4146 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4147 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
4148 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
4150 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
4151 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
4152 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
4153 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
4154 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
4155 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
4156 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
4157 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
4158 if (!nickserv_conf
.disable_nicks
) {
4159 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
4160 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4161 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
4162 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
4163 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
4164 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
4165 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
4166 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
4168 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
4169 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
4170 const char *key
= iter_key(it
), *value
;
4174 if (!strncasecmp(key
, "uc_", 3))
4175 flag
= toupper(key
[3]);
4176 else if (!strncasecmp(key
, "lc_", 3))
4177 flag
= tolower(key
[3]);
4181 if ((pos
= handle_inverse_flags
[flag
])) {
4182 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
4183 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
4186 if (nickserv_conf
.weak_password_dict
)
4187 dict_delete(nickserv_conf
.weak_password_dict
);
4188 nickserv_conf
.weak_password_dict
= dict_new();
4189 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
4190 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
4191 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
4192 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
4194 nickserv_load_dict(str
);
4195 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
4196 if (nickserv
&& str
)
4197 NickChange(nickserv
, str
, 0);
4198 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
4199 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
4200 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
4201 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
4202 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
4203 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
4204 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
4205 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
4206 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
4207 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
4208 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
4209 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
4210 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
4211 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
4212 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
4213 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
4214 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
4215 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
4216 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
4217 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
4219 free_string_list(nickserv_conf
.denied_fakehost_words
);
4220 strlist
= database_get_data(conf_node
, KEY_DENIED_FAKEHOST_WORDS
, RECDB_STRING_LIST
);
4222 strlist
= string_list_copy(strlist
);
4224 strlist
= alloc_string_list(4);
4225 string_list_append(strlist
, strdup("sex"));
4226 string_list_append(strlist
, strdup("fuck"));
4228 nickserv_conf
.denied_fakehost_words
= strlist
;
4230 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
4231 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
4233 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
4234 nickserv_conf
.auto_oper
= str
? str
: "";
4236 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
4237 nickserv_conf
.auto_admin
= str
? str
: "";
4239 str
= conf_get_data("server/network", RECDB_QSTRING
);
4240 nickserv_conf
.network_name
= str
? str
: "some IRC network";
4241 if (!nickserv_conf
.auth_policer_params
) {
4242 nickserv_conf
.auth_policer_params
= policer_params_new();
4243 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
4244 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
4246 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4247 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4248 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4252 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
4254 char newnick
[NICKLEN
+1];
4263 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4265 case RECLAIM_SVSNICK
:
4267 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4268 } while (GetUserH(newnick
));
4269 irc_svsnick(nickserv
, user
, newnick
);
4272 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4273 irc_kill(nickserv
, user
, msg
);
4279 nickserv_reclaim_p(void *data
) {
4280 struct userNode
*user
= data
;
4281 struct nick_info
*ni
= get_nick_info(user
->nick
);
4283 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4287 check_user_nick(struct userNode
*user
) {
4288 struct nick_info
*ni
;
4289 user
->modes
&= ~FLAGS_REGNICK
;
4290 if (!(ni
= get_nick_info(user
->nick
)))
4292 if (user
->handle_info
== ni
->owner
) {
4293 user
->modes
|= FLAGS_REGNICK
;
4297 if (nickserv_conf
.warn_nick_owned
)
4298 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4299 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
4301 if (nickserv_conf
.auto_reclaim_delay
)
4302 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
4304 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4309 handle_new_user(struct userNode
*user
)
4311 return check_user_nick(user
);
4315 handle_account(struct userNode
*user
, const char *stamp
)
4317 struct handle_info
*hi
;
4320 #ifdef WITH_PROTOCOL_P10
4321 time_t timestamp
= 0;
4323 colon
= strchr(stamp
, ':');
4324 if(colon
&& colon
[1])
4327 timestamp
= atoi(colon
+1);
4329 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
4330 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
4332 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
);
4336 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4337 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4341 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4344 set_user_handle_info(user
, hi
, 0);
4346 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4351 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4353 struct handle_info
*hi
;
4355 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4356 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4357 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4359 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4360 check_user_nick(user
);
4364 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4366 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4367 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4368 set_user_handle_info(user
, NULL
, 0);
4371 static struct modcmd
*
4372 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4374 if (min_level
> 0) {
4376 sprintf(buf
, "%u", min_level
);
4377 if (must_be_qualified
) {
4378 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4380 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4382 } else if (min_level
== 0) {
4383 if (must_be_qualified
) {
4384 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4386 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4389 if (must_be_qualified
) {
4390 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4392 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4398 nickserv_db_cleanup(void)
4400 unreg_del_user_func(nickserv_remove_user
);
4401 userList_clean(&curr_helpers
);
4402 policer_params_delete(nickserv_conf
.auth_policer_params
);
4403 dict_delete(nickserv_handle_dict
);
4404 dict_delete(nickserv_nick_dict
);
4405 dict_delete(nickserv_opt_dict
);
4406 dict_delete(nickserv_allow_auth_dict
);
4407 dict_delete(nickserv_email_dict
);
4408 dict_delete(nickserv_id_dict
);
4409 dict_delete(nickserv_conf
.weak_password_dict
);
4410 free(auth_func_list
);
4411 free(unreg_func_list
);
4413 free(allowauth_func_list
);
4414 free(handle_merge_func_list
);
4415 free(failpw_func_list
);
4416 if (nickserv_conf
.valid_handle_regex_set
)
4417 regfree(&nickserv_conf
.valid_handle_regex
);
4418 if (nickserv_conf
.valid_nick_regex_set
)
4419 regfree(&nickserv_conf
.valid_nick_regex
);
4423 init_nickserv(const char *nick
)
4425 struct chanNode
*chan
;
4427 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4428 reg_new_user_func(handle_new_user
);
4429 reg_nick_change_func(handle_nick_change
);
4430 reg_del_user_func(nickserv_remove_user
);
4431 reg_account_func(handle_account
);
4433 /* set up handle_inverse_flags */
4434 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4435 for (i
=0; handle_flags
[i
]; i
++) {
4436 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4437 flag_access_levels
[i
] = 0;
4440 conf_register_reload(nickserv_conf_read
);
4441 nickserv_opt_dict
= dict_new();
4442 nickserv_email_dict
= dict_new();
4444 dict_set_free_keys(nickserv_email_dict
, free
);
4445 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4447 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4448 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4449 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4450 * a big pain to disable since its nolonger in the config file. ) -Rubin
4452 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4453 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4454 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4455 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4456 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4457 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4458 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4459 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4460 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4461 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4462 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4463 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4464 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4465 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4466 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4467 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4468 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4469 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4470 if (!nickserv_conf
.disable_nicks
) {
4471 /* nick management commands */
4472 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4473 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4474 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4475 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4476 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4477 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4479 if (nickserv_conf
.email_enabled
) {
4480 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4481 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4482 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4483 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4484 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4485 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4487 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4488 /* ignore commands */
4489 nickserv_define_func("ADDIGNORE", cmd_addignore
, -1, 1, 0);
4490 nickserv_define_func("OADDIGNORE", cmd_oaddignore
, 0, 1, 0);
4491 nickserv_define_func("DELIGNORE", cmd_delignore
, -1, 1, 0);
4492 nickserv_define_func("ODELIGNORE", cmd_odelignore
, 0, 1, 0);
4493 /* miscellaneous commands */
4494 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4495 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4496 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4497 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4498 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4500 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4501 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4502 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4503 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4504 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4505 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
4506 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
4507 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4508 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4509 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4510 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4511 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4512 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4513 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
4514 if (nickserv_conf
.titlehost_suffix
) {
4515 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4516 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4518 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4519 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4520 dict_insert(nickserv_opt_dict
, "ADVANCED", opt_advanced
);
4521 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4523 nickserv_handle_dict
= dict_new();
4524 dict_set_free_keys(nickserv_handle_dict
, free
);
4525 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4527 nickserv_id_dict
= dict_new();
4528 dict_set_free_keys(nickserv_id_dict
, free
);
4530 nickserv_nick_dict
= dict_new();
4531 dict_set_free_data(nickserv_nick_dict
, free
);
4533 nickserv_allow_auth_dict
= dict_new();
4535 userList_init(&curr_helpers
);
4538 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4539 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4540 nickserv_service
= service_register(nickserv
);
4542 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4543 reg_exit_func(nickserv_db_cleanup
);
4544 if(nickserv_conf
.handle_expire_frequency
)
4545 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4547 if(autojoin_channels
&& nickserv
) {
4548 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
4549 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
4550 AddChannelUser(nickserv
, chan
)->modes
|= MODE_CHANOP
;
4554 message_register_table(msgtab
);