1 /* nickserv.c - Nick/authentication service
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * srvx is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 #include "opserv.h" /* for gag_create(), opserv_bad_channel() */
34 #define NICKSERV_CONF_NAME "services/nickserv"
36 #define KEY_DISABLE_NICKS "disable_nicks"
37 #define KEY_DEFAULT_HOSTMASK "default_hostmask"
38 #define KEY_NICKS_PER_HANDLE "nicks_per_handle"
39 #define KEY_NICKS_PER_ACCOUNT "nicks_per_account"
40 #define KEY_PASSWORD_MIN_LENGTH "password_min_length"
41 #define KEY_PASSWORD_MIN_DIGITS "password_min_digits"
42 #define KEY_PASSWORD_MIN_UPPER "password_min_upper"
43 #define KEY_PASSWORD_MIN_LOWER "password_min_lower"
44 #define KEY_VALID_HANDLE_REGEX "valid_handle_regex"
45 #define KEY_VALID_ACCOUNT_REGEX "valid_account_regex"
46 #define KEY_VALID_NICK_REGEX "valid_nick_regex"
47 #define KEY_DB_BACKUP_FREQ "db_backup_freq"
48 #define KEY_MODOPER_LEVEL "modoper_level"
49 #define KEY_SET_EPITHET_LEVEL "set_epithet_level"
50 #define KEY_SET_TITLE_LEVEL "set_title_level"
51 #define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
52 #define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
53 #define KEY_AUTO_OPER "auto_oper"
54 #define KEY_AUTO_ADMIN "auto_admin"
55 #define KEY_FLAG_LEVELS "flag_levels"
56 #define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
57 #define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
58 #define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
59 #define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
60 #define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
61 #define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
62 #define KEY_DICT_FILE "dict_file"
63 #define KEY_NICK "nick"
64 #define KEY_LANGUAGE "language"
65 #define KEY_AUTOGAG_ENABLED "autogag_enabled"
66 #define KEY_AUTOGAG_DURATION "autogag_duration"
67 #define KEY_AUTH_POLICER "auth_policer"
68 #define KEY_EMAIL_VISIBLE_LEVEL "email_visible_level"
69 #define KEY_EMAIL_ENABLED "email_enabled"
70 #define KEY_EMAIL_REQUIRED "email_required"
71 #define KEY_SYNC_LOG "sync_log"
72 #define KEY_COOKIE_TIMEOUT "cookie_timeout"
73 #define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
74 #define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
75 #define KEY_DEFAULT_STYLE "default_style"
78 #define KEY_PASSWD "passwd"
79 #define KEY_NICKS "nicks"
80 #define KEY_MASKS "masks"
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 static struct module *nickserv_module
;
129 static struct service
*nickserv_service
;
130 static struct log_type
*NS_LOG
;
131 static dict_t nickserv_handle_dict
; /* contains struct handle_info* */
132 static dict_t nickserv_id_dict
; /* contains struct handle_info* */
133 static dict_t nickserv_nick_dict
; /* contains struct nick_info* */
134 static dict_t nickserv_opt_dict
; /* contains option_func_t* */
135 static dict_t nickserv_allow_auth_dict
; /* contains struct handle_info* */
136 static dict_t nickserv_email_dict
; /* contains struct handle_info_list*, indexed by email addr */
137 static char handle_inverse_flags
[256];
138 static unsigned int flag_access_levels
[32];
139 static const struct message_entry msgtab
[] = {
140 { "NSMSG_HANDLE_EXISTS", "Account $b%s$b is already registered." },
141 { "NSMSG_HANDLE_TOLONG", "The account name %s is too long. Account names must be %lu charactors or less."},
142 { "NSMSG_PASSWORD_SHORT", "Your password must be at least %lu characters long." },
143 { "NSMSG_PASSWORD_ACCOUNT", "Your password may not be the same as your account name." },
144 { "NSMSG_PASSWORD_DICTIONARY", "Your password is too simple. You must choose a password that is not just a word or name." },
145 { "NSMSG_PASSWORD_READABLE", "Your password must have at least %lu digit(s), %lu capital letter(s), and %lu lower-case letter(s)." },
146 { "NSMSG_PARTIAL_REGISTER", "Account has been registered to you; nick was already registered to someone else." },
147 { "NSMSG_OREGISTER_VICTIM", "%s has registered a new account for you (named %s)." },
148 { "NSMSG_OREGISTER_H_SUCCESS", "Account has been registered." },
149 { "NSMSG_REGISTER_H_SUCCESS", "Account has been registered to you." },
150 { "NSMSG_REGISTER_HN_SUCCESS", "Account and nick have been registered to you." },
151 { "NSMSG_REQUIRE_OPER", "You must be an $bIRC Operator$b to register the first account." },
152 { "NSMSG_ROOT_HANDLE", "Account %s has been granted $broot-level privileges$b." },
153 { "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." },
154 { "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." },
155 { "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." },
156 { "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." },
157 { "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." },
158 { "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." },
159 { "NSMSG_EMAIL_UNACTIVATED", "That email address already has an unused cookie outstanding. Please use the cookie or wait for it to expire." },
160 { "NSMSG_NO_COOKIE", "Your account does not have any cookie issued right now." },
161 { "NSMSG_NO_COOKIE_FOREIGN", "The account $b%s$b does not have any cookie issued right now." },
162 { "NSMSG_CANNOT_COOKIE", "You cannot use that kind of cookie when you are logged in." },
163 { "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." },
164 { "NSMSG_HANDLE_ACTIVATED", "Your account is now activated (with the password you entered when you registered). You are now authenticated to your account." },
165 { "NSMSG_PASSWORD_CHANGED", "You have successfully changed your password to what you requested with the $bresetpass$b command." },
166 { "NSMSG_EMAIL_PROHIBITED", "%s may not be used as an email address: %s" },
167 { "NSMSG_EMAIL_OVERUSED", "That email address already has an account. Use RESETPASS if you forgot your password." },
168 { "NSMSG_EMAIL_SAME", "That is the email address already there; no need to change it." },
169 { "NSMSG_EMAIL_CHANGED", "You have successfully changed your email address." },
170 { "NSMSG_BAD_COOKIE_TYPE", "Your account had bad cookie type %d; sorry. I am confused. Please report this bug." },
171 { "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
172 { "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
173 { "NSMSG_ATE_FOREIGN_COOKIE", "I ate the cookie for account $b%s$b. It may now have another." },
174 { "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
175 { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
176 { "NSMSG_REGISTER_BAD_NICKMASK", "Could not recognize $b%s$b as either a current nick or a hostmask." },
177 { "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
178 { "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
179 { "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
180 { "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)" },
181 { "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
182 { "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
183 { "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
184 { "NSMSG_USER_PREV_STAMP", "$b%s$b has authenticated to an account once and cannot authenticate again." },
185 { "NSMSG_BAD_MAX_LOGINS", "MaxLogins must be at most %d." },
186 { "NSMSG_LANGUAGE_NOT_FOUND", "Language $b%s$b is not supported; $b%s$b was the closest available match." },
187 { "NSMSG_MAX_LOGINS", "Your account already has its limit of %d user(s) logged in." },
188 { "NSMSG_STAMPED_REGISTER", "You have already authenticated to an account once this session; you may not register a new account." },
189 { "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
190 { "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
191 { "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
192 { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
193 { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
194 { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
195 { "NSMSG_HANDLEINFO_ON", "$bAccount Information for %s$b" },
196 { "NSMSG_HANDLEINFO_END", "----------End of Account Info-----------" },
197 { "NSMSG_HANDLEINFO_ID", "Account ID: %lu" },
198 { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" },
199 { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" },
200 { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" },
201 { "NSMSG_HANDLEINFO_VACATION", "On vacation." },
202 { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" },
203 { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" },
204 { "NSMSG_HANDLEINFO_COOKIE_PASSWORD", "Cookie: There is currently a password change cookie issued for this account" },
205 { "NSMSG_HANDLEINFO_COOKIE_EMAIL", "Cookie: There is currently an email change cookie issued for this account" },
206 { "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH", "Cookie: There is currently an allowauth cookie issued for this account" },
207 { "NSMSG_HANDLEINFO_COOKIE_UNKNOWN", "Cookie: There is currently an unknown cookie issued for this account" },
208 { "NSMSG_HANDLEINFO_INFOLINE", "Infoline: %s" },
209 { "NSMSG_HANDLEINFO_FLAGS", "Flags: %s" },
210 { "NSMSG_HANDLEINFO_EPITHET", "Epithet: %s" },
211 { "NSMSG_HANDLEINFO_NOTE", "Note (by %s on %s): %s " },
212 { "NSMSG_HANDLEINFO_FAKEHOST", "Fake host: %s" },
213 { "NSMSG_HANDLEINFO_LAST_HOST", "Last quit hostmask: %s" },
214 { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" },
215 { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" },
216 { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" },
217 { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" },
218 { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" },
219 { "NSMSG_HANDLEINFO_DNR", "Do-not-register (by %s): %s" },
220 { "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
221 { "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
222 { "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
223 { "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
224 { "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
225 { "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)." },
226 { "NSMSG_HANDLE_SUSPENDED", "Your $b$N$b account has been suspended; you may not use it." },
227 { "NSMSG_AUTH_SUCCESS", "I recognize you." },
228 { "NSMSG_ALLOWAUTH_STAFF", "$b%s$b is a helper or oper; please use $bstaff$b after the account name to allowauth." },
229 { "NSMSG_AUTH_ALLOWED", "User $b%s$b may now authenticate to account $b%s$b." },
230 { "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." },
231 { "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." },
232 { "NSMSG_AUTH_NORMAL_ONLY", "User $b%s$b may now only authenticate to accounts with matching hostmasks." },
233 { "NSMSG_AUTH_UNSPECIAL", "User $b%s$b did not have any special auth allowance." },
234 { "NSMSG_MUST_AUTH", "You must be authenticated first." },
235 { "NSMSG_TOO_MANY_NICKS", "You have already registered the maximum permitted number of nicks." },
236 { "NSMSG_NICK_EXISTS", "Nick $b%s$b already registered." },
237 { "NSMSG_REGNICK_SUCCESS", "Nick $b%s$b has been registered to you." },
238 { "NSMSG_OREGNICK_SUCCESS", "Nick $b%s$b has been registered to account $b%s$b." },
239 { "NSMSG_PASS_SUCCESS", "Password changed." },
240 { "NSMSG_MASK_INVALID", "$b%s$b is an invalid hostmask." },
241 { "NSMSG_ADDMASK_ALREADY", "$b%s$b is already a hostmask in your account." },
242 { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." },
243 { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." },
244 { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." },
245 { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." },
246 { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." },
247 { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." },
248 { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." },
249 { "NSMSG_NOT_YOUR_NICK", "The nick $b%s$b is not registered to you." },
250 { "NSMSG_NICK_USER_YOU", "I will not let you kill yourself." },
251 { "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
252 { "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
253 { "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
254 { "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
255 { "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
256 { "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
257 { "NSMSG_GLOBAL_STATS_NONICK", "There are %d accounts registered." },
258 { "NSMSG_CANNOT_GHOST_SELF", "You may not ghost-kill yourself." },
259 { "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
260 { "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
261 { "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
262 { "NSMSG_NO_ACCESS", "Access denied." },
263 { "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
264 { "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
265 { "NSMSG_FLAG_PRIVILEGED", "You have insufficient access to set flag %c." },
266 { "NSMSG_DB_UNREADABLE", "Unable to read database file %s; check the log for more information." },
267 { "NSMSG_DB_MERGED", "$N merged DB from %s (in "FMT_TIME_T
".%03lu seconds)." },
268 { "NSMSG_HANDLE_CHANGED", "$b%s$b's account name has been changed to $b%s$b." },
269 { "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." },
270 { "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." },
271 { "NSMSG_BAD_EMAIL_ADDR", "Please use a well-formed email address." },
272 { "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." },
273 { "NSMSG_ACCOUNT_SEARCH_RESULTS", "The following accounts were found:" },
274 { "NSMSG_SEARCH_MATCH", "Match: %s" },
275 { "NSMSG_INVALID_ACTION", "%s is an invalid search action." },
276 { "NSMSG_CANNOT_MERGE_SELF", "You cannot merge account $b%s$b with itself." },
277 { "NSMSG_HANDLES_MERGED", "Merged account $b%s$b into $b%s$b." },
278 { "NSMSG_RECLAIM_WARN", "%s is a registered nick - you must auth to account %s or change your nick." },
279 { "NSMSG_RECLAIM_KILL", "Unauthenticated user of nick." },
280 { "NSMSG_RECLAIMED_NONE", "You cannot manually reclaim a nick." },
281 { "NSMSG_RECLAIMED_WARN", "Sent a request for %s to change their nick." },
282 { "NSMSG_RECLAIMED_SVSNICK", "Forcibly changed %s's nick." },
283 { "NSMSG_RECLAIMED_KILL", "Disconnected %s from the network." },
284 { "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
285 { "NSMSG_SETTING_LIST", "$b$N account settings$b" },
286 { "NSMSG_SETTING_LIST_HEADER", "----------------------------------------" },
287 { "NSMSG_SETTING_LIST_END", "-------------End Of Settings------------" },
288 { "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
289 { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an invalid announcements value." },
290 { "NSMSG_SET_INFO", "$bINFO: $b%s" },
291 { "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
292 { "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
293 { "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
294 { "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
295 { "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
296 { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
297 { "NSMSG_SET_AUTOHIDE", "$bAUTOHIDE: $b%s" },
298 { "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
299 { "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
300 { "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
301 { "NSMSG_SET_MAXLOGINS", "$bMAXLOGINS: $b%d" },
302 { "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
303 { "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
304 { "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
305 { "NSMSG_SET_NOTE", "$bNOTE: $b%s"},
306 { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
307 { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
309 { "NSMSG_AUTO_OPER", "You have been auto-opered" },
310 { "NSMSG_AUTO_OPER_ADMIN", "You have been auto-admined" },
312 { "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
313 { "NSEMAIL_ACTIVATION_BODY",
314 "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"
316 "To verify your email address and complete the account registration, log on to %1$s and type the following command:\n"
317 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
318 "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"
319 "/msg %3$s@%4$s AUTH %5$s your-password\n"
320 "(Please remember to fill in 'your-password' with the actual password you gave to us when you registered.)\n"
321 "OR configure Login-On-Connect (see http://www.afternet.org/login-on-connect for instructions) to connect pre-logged in every time.\n"
323 "If you did NOT request this account, you do not need to do anything.\n"
324 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
325 { "NSEMAIL_ACTIVATION_BODY_WEB",
326 "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"
328 "To verify your email address and complete the account registration, visit the following URL:\n"
329 "http://www.afternet.org/index.php?option=com_registration&task=activate&username=%5$s&cookie=%2$s\n"
331 "If you did NOT request this account, you do not need to do anything.\n"
332 "Please contact the %1$s staff if you have questions, and be sure to check our website." },
333 { "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
334 { "NSEMAIL_PASSWORD_CHANGE_BODY",
335 "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"
336 "To complete the password change, log on to %1$s and type the following command:\n"
337 "/msg %3$s@%4$s COOKIE %5$s %2$s\n"
338 "If you did NOT request your password to be changed, you do not need to do anything.\n"
339 "Please contact the %1$s staff if you have questions." },
340 { "NSEMAIL_PASSWORD_CHANGE_BODY_WEB",
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, click the following URL:\n"
343 "http://www.afternet.org/index.php?option=com_registration&task=passcookie&username=%5$s&cookie=%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_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
347 #ifdef stupid_verify_old_email
348 { "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." },
349 { "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." },
351 { "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
352 { "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." },
353 { "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
354 { "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." },
355 { "CHECKPASS_YES", "Yes." },
356 { "CHECKPASS_NO", "No." },
360 enum reclaim_action
{
366 static void nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
);
367 static void nickserv_reclaim_p(void *data
);
370 unsigned int disable_nicks
: 1;
371 unsigned int valid_handle_regex_set
: 1;
372 unsigned int valid_nick_regex_set
: 1;
373 unsigned int autogag_enabled
: 1;
374 unsigned int email_enabled
: 1;
375 unsigned int email_required
: 1;
376 unsigned int default_hostmask
: 1;
377 unsigned int warn_nick_owned
: 1;
378 unsigned int warn_clone_auth
: 1;
379 unsigned int sync_log
: 1;
380 unsigned long nicks_per_handle
;
381 unsigned long password_min_length
;
382 unsigned long password_min_digits
;
383 unsigned long password_min_upper
;
384 unsigned long password_min_lower
;
385 unsigned long db_backup_frequency
;
386 unsigned long handle_expire_frequency
;
387 unsigned long autogag_duration
;
388 unsigned long email_visible_level
;
389 unsigned long cookie_timeout
;
390 unsigned long handle_expire_delay
;
391 unsigned long nochan_handle_expire_delay
;
392 unsigned long modoper_level
;
393 unsigned long set_epithet_level
;
394 unsigned long set_title_level
;
395 unsigned long set_fakehost_level
;
396 unsigned long handles_per_email
;
397 unsigned long email_search_level
;
398 const char *network_name
;
399 const char *titlehost_suffix
;
400 regex_t valid_handle_regex
;
401 regex_t valid_nick_regex
;
402 dict_t weak_password_dict
;
403 struct policer_params
*auth_policer_params
;
404 enum reclaim_action reclaim_action
;
405 enum reclaim_action auto_reclaim_action
;
406 unsigned long auto_reclaim_delay
;
407 unsigned char default_maxlogins
;
408 unsigned char hard_maxlogins
;
409 const char *auto_oper
;
410 const char *auto_admin
;
414 /* We have 2^32 unique account IDs to use. */
415 unsigned long int highest_id
= 0;
418 canonicalize_hostmask(char *mask
)
420 char *out
= mask
, *temp
;
421 if ((temp
= strchr(mask
, '!'))) {
423 while (*temp
) *out
++ = *temp
++;
429 static struct handle_note
*
430 nickserv_add_note(const char *setter
, time_t date
, const char *text
)
432 struct handle_note
*note
= calloc(1, sizeof(*note
) + strlen(text
));
434 strncpy(note
->setter
, setter
, sizeof(note
->setter
)-1);
436 memcpy(note
->note
, text
, strlen(text
));
440 static struct handle_info
*
441 register_handle(const char *handle
, const char *passwd
, UNUSED_ARG(unsigned long id
))
443 struct handle_info
*hi
;
445 #ifdef WITH_PROTOCOL_BAHAMUT
446 char id_base64
[IDLEN
+ 1];
449 /* Assign a unique account ID to the account; note that 0 is
450 an invalid account ID. 1 is therefore the first account ID. */
452 id
= 1 + highest_id
++;
454 /* Note: highest_id is and must always be the highest ID. */
455 if(id
> highest_id
) {
459 inttobase64(id_base64
, id
, IDLEN
);
461 /* Make sure an account with the same ID doesn't exist. If a
462 duplicate is found, log some details and assign a new one.
463 This should be impossible, but it never hurts to expect it. */
464 if ((hi
= dict_find(nickserv_id_dict
, id_base64
, NULL
))) {
465 log_module(NS_LOG
, LOG_WARNING
, "Duplicated account ID %lu (%s) found belonging to %s while inserting %s.", id
, id_base64
, hi
->handle
, handle
);
471 hi
= calloc(1, sizeof(*hi
));
472 hi
->userlist_style
= HI_DEFAULT_STYLE
;
473 hi
->announcements
= '?';
474 hi
->handle
= strdup(handle
);
475 safestrncpy(hi
->passwd
, passwd
, sizeof(hi
->passwd
));
477 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
479 #ifdef WITH_PROTOCOL_BAHAMUT
481 dict_insert(nickserv_id_dict
, strdup(id_base64
), hi
);
488 register_nick(const char *nick
, struct handle_info
*owner
)
490 struct nick_info
*ni
;
491 ni
= malloc(sizeof(struct nick_info
));
492 safestrncpy(ni
->nick
, nick
, sizeof(ni
->nick
));
494 ni
->next
= owner
->nicks
;
496 dict_insert(nickserv_nick_dict
, ni
->nick
, ni
);
500 delete_nick(struct nick_info
*ni
)
502 struct nick_info
*last
, *next
;
503 struct userNode
*user
;
504 /* Check to see if we should mark a user as unregistered. */
505 if ((user
= GetUserH(ni
->nick
)) && IsReggedNick(user
)) {
506 user
->modes
&= ~FLAGS_REGNICK
;
509 /* Remove ni from the nick_info linked list. */
510 if (ni
== ni
->owner
->nicks
) {
511 ni
->owner
->nicks
= ni
->next
;
513 last
= ni
->owner
->nicks
;
519 last
->next
= next
->next
;
521 dict_remove(nickserv_nick_dict
, ni
->nick
);
524 static unreg_func_t
*unreg_func_list
;
525 static unsigned int unreg_func_size
= 0, unreg_func_used
= 0;
528 reg_unreg_func(unreg_func_t func
)
530 if (unreg_func_used
== unreg_func_size
) {
531 if (unreg_func_size
) {
532 unreg_func_size
<<= 1;
533 unreg_func_list
= realloc(unreg_func_list
, unreg_func_size
*sizeof(unreg_func_t
));
536 unreg_func_list
= malloc(unreg_func_size
*sizeof(unreg_func_t
));
539 unreg_func_list
[unreg_func_used
++] = func
;
543 nickserv_free_cookie(void *data
)
545 struct handle_cookie
*cookie
= data
;
546 if (cookie
->hi
) cookie
->hi
->cookie
= NULL
;
547 if (cookie
->data
) free(cookie
->data
);
552 free_handle_info(void *vhi
)
554 struct handle_info
*hi
= vhi
;
556 #ifdef WITH_PROTOCOL_BAHAMUT
559 inttobase64(id
, hi
->id
, IDLEN
);
560 dict_remove(nickserv_id_dict
, id
);
563 free_string_list(hi
->masks
);
567 delete_nick(hi
->nicks
);
573 timeq_del(hi
->cookie
->expires
, nickserv_free_cookie
, hi
->cookie
, 0);
574 nickserv_free_cookie(hi
->cookie
);
576 if (hi
->email_addr
) {
577 struct handle_info_list
*hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, NULL
);
578 handle_info_list_remove(hil
, hi
);
580 dict_remove(nickserv_email_dict
, hi
->email_addr
);
585 static void set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
);
588 nickserv_unregister_handle(struct handle_info
*hi
, struct userNode
*notify
, struct userNode
*bot
)
591 struct userNode
*uNode
;
593 for (n
=0; n
<unreg_func_used
; n
++)
594 unreg_func_list
[n
](notify
, hi
);
596 if (nickserv_conf
.sync_log
) {
597 uNode
= GetUserH(hi
->users
->nick
);
601 set_user_handle_info(hi
->users
, NULL
, 0);
604 if (nickserv_conf
.disable_nicks
)
605 send_message(notify
, bot
, "NSMSG_UNREGISTER_SUCCESS", hi
->handle
);
607 send_message(notify
, bot
, "NSMSG_UNREGISTER_NICKS_SUCCESS", hi
->handle
);
610 if (nickserv_conf
.sync_log
)
611 SyncLog("UNREGISTER %s", hi
->handle
);
613 dict_remove(nickserv_handle_dict
, hi
->handle
);
617 get_handle_info(const char *handle
)
619 return dict_find(nickserv_handle_dict
, handle
, 0);
623 get_nick_info(const char *nick
)
625 return nickserv_conf
.disable_nicks
? 0 : dict_find(nickserv_nick_dict
, nick
, 0);
629 find_handle_in_channel(struct chanNode
*channel
, struct handle_info
*handle
, struct userNode
*except
)
634 for (nn
=0; nn
<channel
->members
.used
; ++nn
) {
635 mn
= channel
->members
.list
[nn
];
636 if ((mn
->user
!= except
) && (mn
->user
->handle_info
== handle
))
643 oper_has_access(struct userNode
*user
, struct userNode
*bot
, unsigned int min_level
, unsigned int quiet
) {
644 if (!user
->handle_info
) {
646 send_message(user
, bot
, "MSG_AUTHENTICATE");
650 if (!IsOper(user
) && (!IsHelping(user
) || min_level
)) {
652 send_message(user
, bot
, "NSMSG_NO_ACCESS");
656 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
658 send_message(user
, bot
, "MSG_OPER_SUSPENDED");
662 if (user
->handle_info
->opserv_level
< min_level
) {
664 send_message(user
, bot
, "NSMSG_NO_ACCESS");
672 is_valid_handle(const char *handle
)
674 struct userNode
*user
;
675 /* cant register a juped nick/service nick as handle, to prevent confusion */
676 user
= GetUserH(handle
);
677 if (user
&& IsLocal(user
))
679 /* check against maximum length */
680 if (strlen(handle
) > NICKSERV_HANDLE_LEN
)
682 /* for consistency, only allow account names that could be nicks */
683 if (!is_valid_nick(handle
))
685 /* disallow account names that look like bad words */
686 if (opserv_bad_channel(handle
))
688 /* test either regex or containing all valid chars */
689 if (nickserv_conf
.valid_handle_regex_set
) {
690 int err
= regexec(&nickserv_conf
.valid_handle_regex
, handle
, 0, 0, 0);
693 buff
[regerror(err
, &nickserv_conf
.valid_handle_regex
, buff
, sizeof(buff
))] = 0;
694 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
698 return !handle
[strspn(handle
, NICKSERV_VALID_CHARS
)];
703 is_registerable_nick(const char *nick
)
705 /* make sure it could be used as an account name */
706 if (!is_valid_handle(nick
))
709 if (strlen(nick
) > NICKLEN
)
711 /* test either regex or as valid handle */
712 if (nickserv_conf
.valid_nick_regex_set
) {
713 int err
= regexec(&nickserv_conf
.valid_nick_regex
, nick
, 0, 0, 0);
716 buff
[regerror(err
, &nickserv_conf
.valid_nick_regex
, buff
, sizeof(buff
))] = 0;
717 log_module(NS_LOG
, LOG_INFO
, "regexec error: %s (%d)", buff
, err
);
723 /* this has been replaced with one in tools.c
726 is_valid_email_addr(const char *email)
728 return strchr(email, '@') != NULL;
734 visible_email_addr(struct userNode
*user
, struct handle_info
*hi
)
736 if (hi
->email_addr
) {
737 if (oper_has_access(user
, nickserv
, nickserv_conf
.email_visible_level
, 1)) {
738 return hi
->email_addr
;
748 smart_get_handle_info(struct userNode
*service
, struct userNode
*user
, const char *name
)
750 struct handle_info
*hi
;
751 struct userNode
*target
;
755 if (!(hi
= get_handle_info(++name
))) {
756 send_message(user
, service
, "MSG_HANDLE_UNKNOWN", name
);
761 if (!(target
= GetUserH(name
))) {
762 send_message(user
, service
, "MSG_NICK_UNKNOWN", name
);
765 if (IsLocal(target
)) {
766 if (IsService(target
))
767 send_message(user
, service
, "NSMSG_USER_IS_SERVICE", target
->nick
);
769 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
772 if (!(hi
= target
->handle_info
)) {
773 send_message(user
, service
, "MSG_USER_AUTHENTICATE", target
->nick
);
781 oper_outranks(struct userNode
*user
, struct handle_info
*hi
) {
782 if (user
->handle_info
->opserv_level
> hi
->opserv_level
)
784 if (user
->handle_info
->opserv_level
== hi
->opserv_level
) {
785 if ((user
->handle_info
->opserv_level
== 1000)
786 || (user
->handle_info
== hi
)
787 || ((user
->handle_info
->opserv_level
== 0)
788 && !(HANDLE_FLAGGED(hi
, SUPPORT_HELPER
) || HANDLE_FLAGGED(hi
, NETWORK_HELPER
))
789 && HANDLE_FLAGGED(user
->handle_info
, HELPING
))) {
793 send_message(user
, nickserv
, "MSG_USER_OUTRANKED", hi
->handle
);
797 static struct handle_info
*
798 get_victim_oper(struct userNode
*user
, const char *target
)
800 struct handle_info
*hi
;
801 if (!(hi
= smart_get_handle_info(nickserv
, user
, target
)))
803 if (HANDLE_FLAGGED(user
->handle_info
, OPER_SUSPENDED
)) {
804 send_message(user
, nickserv
, "MSG_OPER_SUSPENDED");
807 return oper_outranks(user
, hi
) ? hi
: NULL
;
811 valid_user_for(struct userNode
*user
, struct handle_info
*hi
)
815 /* If no hostmasks on the account, allow it. */
816 if (!hi
->masks
->used
)
818 /* If any hostmask matches, allow it. */
819 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
820 if (user_matches_glob(user
, hi
->masks
->list
[ii
], 0))
822 /* If they are allowauthed to this account, allow it (removing the aa). */
823 if (dict_find(nickserv_allow_auth_dict
, user
->nick
, NULL
) == hi
) {
824 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
827 /* The user is not allowed to use this account. */
832 is_secure_password(const char *handle
, const char *pass
, struct userNode
*user
)
835 unsigned int cnt_digits
= 0, cnt_upper
= 0, cnt_lower
= 0;
839 if (len
< nickserv_conf
.password_min_length
) {
841 send_message(user
, nickserv
, "NSMSG_PASSWORD_SHORT", nickserv_conf
.password_min_length
);
844 if (!irccasecmp(pass
, handle
)) {
846 send_message(user
, nickserv
, "NSMSG_PASSWORD_ACCOUNT");
849 dict_find(nickserv_conf
.weak_password_dict
, pass
, &p
);
852 send_message(user
, nickserv
, "NSMSG_PASSWORD_DICTIONARY");
855 for (i
=0; i
<len
; i
++) {
856 if (isdigit(pass
[i
]))
858 if (isupper(pass
[i
]))
860 if (islower(pass
[i
]))
863 if ((cnt_lower
< nickserv_conf
.password_min_lower
)
864 || (cnt_upper
< nickserv_conf
.password_min_upper
)
865 || (cnt_digits
< nickserv_conf
.password_min_digits
)) {
867 send_message(user
, nickserv
, "NSMSG_PASSWORD_READABLE", nickserv_conf
.password_min_digits
, nickserv_conf
.password_min_upper
, nickserv_conf
.password_min_lower
);
873 static auth_func_t
*auth_func_list
;
874 static unsigned int auth_func_size
= 0, auth_func_used
= 0;
877 reg_auth_func(auth_func_t func
)
879 if (auth_func_used
== auth_func_size
) {
880 if (auth_func_size
) {
881 auth_func_size
<<= 1;
882 auth_func_list
= realloc(auth_func_list
, auth_func_size
*sizeof(auth_func_t
));
885 auth_func_list
= malloc(auth_func_size
*sizeof(auth_func_t
));
888 auth_func_list
[auth_func_used
++] = func
;
891 static handle_rename_func_t
*rf_list
;
892 static unsigned int rf_list_size
, rf_list_used
;
895 reg_handle_rename_func(handle_rename_func_t func
)
897 if (rf_list_used
== rf_list_size
) {
900 rf_list
= realloc(rf_list
, rf_list_size
*sizeof(rf_list
[0]));
903 rf_list
= malloc(rf_list_size
*sizeof(rf_list
[0]));
906 rf_list
[rf_list_used
++] = func
;
910 generate_fakehost(struct handle_info
*handle
)
912 extern const char *hidden_host_suffix
;
913 static char buffer
[HOSTLEN
+1];
915 if (!handle
->fakehost
) {
916 snprintf(buffer
, sizeof(buffer
), "%s.%s", handle
->handle
, hidden_host_suffix
);
918 } else if (handle
->fakehost
[0] == '.') {
919 /* A leading dot indicates the stored value is actually a title. */
920 snprintf(buffer
, sizeof(buffer
), "%s.%s.%s", handle
->handle
, handle
->fakehost
+1, nickserv_conf
.titlehost_suffix
);
923 return handle
->fakehost
;
927 apply_fakehost(struct handle_info
*handle
)
929 struct userNode
*target
;
934 fake
= generate_fakehost(handle
);
935 for (target
= handle
->users
; target
; target
= target
->next_authed
)
936 assign_fakehost(target
, fake
, 1);
939 void send_func_list(struct userNode
*user
)
942 struct handle_info
*old_info
;
944 old_info
= user
->handle_info
;
946 for (n
=0; n
<auth_func_used
; n
++)
947 auth_func_list
[n
](user
, old_info
);
951 set_user_handle_info(struct userNode
*user
, struct handle_info
*hi
, int stamp
)
954 struct handle_info
*old_info
;
956 /* This can happen if somebody uses COOKIE while authed, or if
957 * they re-auth to their current handle (which is silly, but users
959 if (user
->handle_info
== hi
)
962 if (user
->handle_info
) {
963 struct userNode
*other
;
966 userList_remove(&curr_helpers
, user
);
968 /* remove from next_authed linked list */
969 if (user
->handle_info
->users
== user
) {
970 user
->handle_info
->users
= user
->next_authed
;
972 for (other
= user
->handle_info
->users
;
973 other
->next_authed
!= user
;
974 other
= other
->next_authed
) ;
975 other
->next_authed
= user
->next_authed
;
977 /* if nobody left on old handle, and they're not an oper, remove !god */
978 if (!user
->handle_info
->users
&& !user
->handle_info
->opserv_level
)
979 HANDLE_CLEAR_FLAG(user
->handle_info
, HELPING
);
980 /* record them as being last seen at this time */
981 user
->handle_info
->lastseen
= now
;
982 /* and record their hostmask */
983 snprintf(user
->handle_info
->last_quit_host
, sizeof(user
->handle_info
->last_quit_host
), "%s@%s", user
->ident
, user
->hostname
);
985 old_info
= user
->handle_info
;
986 user
->handle_info
= hi
;
987 if (hi
&& !hi
->users
&& !hi
->opserv_level
)
988 HANDLE_CLEAR_FLAG(hi
, HELPING
);
990 if (GetUserH(user
->nick
)) {
991 for (n
=0; n
<auth_func_used
; n
++)
992 auth_func_list
[n
](user
, old_info
);
997 struct nick_info
*ni
;
999 HANDLE_CLEAR_FLAG(hi
, FROZEN
);
1000 if (nickserv_conf
.warn_clone_auth
) {
1001 struct userNode
*other
;
1002 for (other
= hi
->users
; other
; other
= other
->next_authed
)
1003 send_message(other
, nickserv
, "NSMSG_CLONE_AUTH", user
->nick
, user
->ident
, user
->hostname
);
1006 user
->next_authed
= hi
->users
;
1010 userList_append(&curr_helpers
, user
);
1012 if (hi
->fakehost
|| old_info
)
1016 #ifdef WITH_PROTOCOL_BAHAMUT
1017 /* Stamp users with their account ID. */
1019 inttobase64(id
, hi
->id
, IDLEN
);
1020 #elif WITH_PROTOCOL_P10
1021 /* Stamp users with their account name. */
1022 char *id
= hi
->handle
;
1024 const char *id
= "???";
1026 if (!nickserv_conf
.disable_nicks
) {
1027 struct nick_info
*ni
;
1028 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) {
1029 if (!irccasecmp(user
->nick
, ni
->nick
)) {
1030 user
->modes
|= FLAGS_REGNICK
;
1035 StampUser(user
, id
, hi
->registered
);
1038 if ((ni
= get_nick_info(user
->nick
)) && (ni
->owner
== hi
))
1039 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
1041 /* We cannot clear the user's account ID, unfortunately. */
1042 user
->next_authed
= NULL
;
1046 static struct handle_info
*
1047 nickserv_register(struct userNode
*user
, struct userNode
*settee
, const char *handle
, const char *passwd
, int no_auth
)
1049 struct handle_info
*hi
;
1050 struct nick_info
*ni
;
1051 char crypted
[MD5_CRYPT_LENGTH
];
1053 if ((hi
= dict_find(nickserv_handle_dict
, handle
, NULL
))) {
1054 send_message(user
, nickserv
, "NSMSG_HANDLE_EXISTS", handle
);
1058 if(strlen(handle
) > 15)
1060 send_message(user
, nickserv
, "NSMSG_HANDLE_TOLONG", handle
, 15);
1064 if (!is_secure_password(handle
, passwd
, user
))
1067 cryptpass(passwd
, crypted
);
1068 hi
= register_handle(handle
, crypted
, 0);
1069 hi
->masks
= alloc_string_list(1);
1071 hi
->language
= lang_C
;
1072 hi
->registered
= now
;
1074 hi
->flags
= HI_DEFAULT_FLAGS
;
1075 if (settee
&& !no_auth
)
1076 set_user_handle_info(settee
, hi
, 1);
1079 send_message(user
, nickserv
, "NSMSG_OREGISTER_H_SUCCESS");
1080 else if (nickserv_conf
.disable_nicks
)
1081 send_message(user
, nickserv
, "NSMSG_REGISTER_H_SUCCESS");
1082 else if ((ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
)))
1083 send_message(user
, nickserv
, "NSMSG_PARTIAL_REGISTER");
1085 register_nick(user
->nick
, hi
);
1086 send_message(user
, nickserv
, "NSMSG_REGISTER_HN_SUCCESS");
1088 if (settee
&& (user
!= settee
))
1089 send_message(settee
, nickserv
, "NSMSG_OREGISTER_VICTIM", user
->nick
, hi
->handle
);
1094 nickserv_bake_cookie(struct handle_cookie
*cookie
)
1096 cookie
->hi
->cookie
= cookie
;
1097 timeq_add(cookie
->expires
, nickserv_free_cookie
, cookie
);
1100 /* Contributed by the great sneep of afternet ;) */
1101 /* Since this gets used in a URL, we want to avoid stuff that confuses
1102 * email clients such as ] and ?. a-z, 0-9 only.
1104 void genpass(char *str
, int len
)
1109 for(i
= 0; i
< len
; i
++)
1113 c
= (char)((float)rand() / (float)RAND_MAX
* (float)256);
1114 } while(!((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || (c
>= '0' && c
<= '9')));
1122 nickserv_make_cookie(struct userNode
*user
, struct handle_info
*hi
, enum cookie_type type
, const char *cookie_data
, int weblink
)
1124 struct handle_cookie
*cookie
;
1125 char subject
[128], body
[4096], *misc
;
1126 const char *netname
, *fmt
;
1130 send_message(user
, nickserv
, "NSMSG_COOKIE_LIVE", hi
->handle
);
1134 cookie
= calloc(1, sizeof(*cookie
));
1136 cookie
->type
= type
;
1137 cookie
->data
= cookie_data
? strdup(cookie_data
) : NULL
;
1139 cookie
->expires
= now
+ nickserv_conf
.cookie_timeout
;
1140 /* Adding dedicated password gen function for more control -Rubin */
1141 genpass(cookie
->cookie
, 10);
1143 *inttobase64(cookie->cookie, rand(), 5);
1144 *inttobase64(cookie->cookie+5, rand(), 5);
1147 netname
= nickserv_conf
.network_name
;
1150 switch (cookie
->type
) {
1152 hi
->passwd
[0] = 0; /* invalidate password */
1153 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_REGISTER");
1154 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_SUBJECT");
1155 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1158 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY_WEB");
1160 fmt
= handle_find_message(hi
, "NSEMAIL_ACTIVATION_BODY");
1162 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1165 case PASSWORD_CHANGE
:
1166 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_RESETPASS");
1167 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
1168 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1170 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY_WEB");
1172 fmt
= handle_find_message(hi
, "NSEMAIL_PASSWORD_CHANGE_BODY");
1173 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1176 misc
= hi
->email_addr
;
1177 hi
->email_addr
= cookie
->data
;
1178 #ifdef stupid_verify_old_email
1180 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_2");
1181 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
1182 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1183 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
1184 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
+COOKIELEN
/2, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2);
1185 sendmail(nickserv
, hi
, subject
, body
, 1);
1186 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
1187 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
, COOKIELEN
/2, hi
->email_addr
);
1190 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_EMAIL_1");
1191 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
1192 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1193 fmt
= handle_find_message(hi
, "NSEMAIL_EMAIL_VERIFY_BODY");
1194 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1195 sendmail(nickserv
, hi
, subject
, body
, 1);
1197 #ifdef stupid_verify_old_email
1200 hi
->email_addr
= misc
;
1203 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_SUBJECT");
1204 snprintf(subject
, sizeof(subject
), fmt
, netname
);
1205 fmt
= handle_find_message(hi
, "NSEMAIL_ALLOWAUTH_BODY");
1206 snprintf(body
, sizeof(body
), fmt
, netname
, cookie
->cookie
, nickserv
->nick
, self
->name
, hi
->handle
);
1207 send_message(user
, nickserv
, "NSMSG_USE_COOKIE_AUTH");
1210 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d in nickserv_make_cookie.", cookie
->type
);
1214 sendmail(nickserv
, hi
, subject
, body
, first_time
);
1215 nickserv_bake_cookie(cookie
);
1219 nickserv_eat_cookie(struct handle_cookie
*cookie
)
1221 cookie
->hi
->cookie
= NULL
;
1222 timeq_del(cookie
->expires
, nickserv_free_cookie
, cookie
, 0);
1223 nickserv_free_cookie(cookie
);
1227 nickserv_free_email_addr(void *data
)
1229 handle_info_list_clean(data
);
1234 nickserv_set_email_addr(struct handle_info
*hi
, const char *new_email_addr
)
1236 struct handle_info_list
*hil
;
1237 /* Remove from old handle_info_list ... */
1238 if (hi
->email_addr
&& (hil
= dict_find(nickserv_email_dict
, hi
->email_addr
, 0))) {
1239 handle_info_list_remove(hil
, hi
);
1240 if (!hil
->used
) dict_remove(nickserv_email_dict
, hil
->tag
);
1241 hi
->email_addr
= NULL
;
1243 /* Add to the new list.. */
1244 if (new_email_addr
) {
1245 if (!(hil
= dict_find(nickserv_email_dict
, new_email_addr
, 0))) {
1246 hil
= calloc(1, sizeof(*hil
));
1247 hil
->tag
= strdup(new_email_addr
);
1248 handle_info_list_init(hil
);
1249 dict_insert(nickserv_email_dict
, hil
->tag
, hil
);
1251 handle_info_list_append(hil
, hi
);
1252 hi
->email_addr
= hil
->tag
;
1256 static NICKSERV_FUNC(cmd_register
)
1258 struct handle_info
*hi
;
1259 const char *email_addr
, *password
;
1260 char syncpass
[MD5_CRYPT_LENGTH
];
1261 int no_auth
, weblink
;
1263 if (!IsOper(user
) && !dict_size(nickserv_handle_dict
)) {
1264 /* Require the first handle registered to belong to someone +o. */
1265 reply("NSMSG_REQUIRE_OPER");
1269 if (user
->handle_info
) {
1270 reply("NSMSG_USE_RENAME", user
->handle_info
->handle
);
1274 if (IsRegistering(user
)) {
1275 reply("NSMSG_ALREADY_REGISTERING");
1279 if (IsStamped(user
)) {
1280 /* Unauthenticated users might still have been stamped
1281 previously and could therefore have a hidden host;
1282 do not allow them to register a new account. */
1283 reply("NSMSG_STAMPED_REGISTER");
1287 NICKSERV_MIN_PARMS((unsigned)3 + nickserv_conf
.email_required
);
1289 if (!is_valid_handle(argv
[1])) {
1290 reply("NSMSG_BAD_HANDLE", argv
[1]);
1295 if ((argc
>= 4) && nickserv_conf
.email_enabled
) {
1296 struct handle_info_list
*hil
;
1299 /* Remember email address. */
1300 email_addr
= argv
[3];
1302 /* Check that the email address looks valid.. */
1303 if (!valid_email(email_addr
)) {
1304 reply("NSMSG_BAD_EMAIL_ADDR");
1308 /* .. and that we are allowed to send to it. */
1309 if ((str
= sendmail_prohibited_address(email_addr
))) {
1310 reply("NSMSG_EMAIL_PROHIBITED", email_addr
, str
);
1314 /* If we do email verify, make sure we don't spam the address. */
1315 if ((hil
= dict_find(nickserv_email_dict
, email_addr
, NULL
))) {
1317 for (nn
=0; nn
<hil
->used
; nn
++) {
1318 if (hil
->list
[nn
]->cookie
) {
1319 reply("NSMSG_EMAIL_UNACTIVATED");
1323 if (hil
->used
>= nickserv_conf
.handles_per_email
) {
1324 reply("NSMSG_EMAIL_OVERUSED");
1337 /* Webregister hack - send URL instead of IRC cookie
1340 if((argc
>= 5) && !strcmp(argv
[4],"WEBLINK"))
1344 if (!(hi
= nickserv_register(user
, user
, argv
[1], password
, no_auth
)))
1346 /* Add any masks they should get. */
1347 if (nickserv_conf
.default_hostmask
) {
1348 string_list_append(hi
->masks
, strdup("*@*"));
1350 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1351 if (user
->ip
.s_addr
&& user
->hostname
[strspn(user
->hostname
, "0123456789.")])
1352 string_list_append(hi
->masks
, generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_BYIP
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
));
1355 /* If they're the first to register, give them level 1000. */
1356 if (dict_size(nickserv_handle_dict
) == 1) {
1357 hi
->opserv_level
= 1000;
1358 reply("NSMSG_ROOT_HANDLE", argv
[1]);
1361 /* Set their email address. */
1363 nickserv_set_email_addr(hi
, email_addr
);
1365 /* If they need to do email verification, tell them. */
1367 nickserv_make_cookie(user
, hi
, ACTIVATION
, hi
->passwd
, weblink
);
1369 /* Set registering flag.. */
1370 user
->modes
|= FLAGS_REGISTERING
;
1372 if (nickserv_conf
.sync_log
) {
1373 cryptpass(password
, syncpass
);
1375 * An 0 is only sent if theres no email address. Thios should only happen if email functions are
1376 * disabled which they wont be for us. Email Required MUST be set on if you are using this.
1379 SyncLog("REGISTER %s %s %s %s", hi
->handle
, syncpass
, email_addr
? email_addr
: "0", user
->info
);
1382 /* this wont work if email is required .. */
1383 process_adduser_pending(user
);
1388 static NICKSERV_FUNC(cmd_oregister
)
1391 struct userNode
*settee
;
1392 struct handle_info
*hi
;
1394 NICKSERV_MIN_PARMS(nickserv_conf
.email_required
? 5 : 4);
1396 if (!is_valid_handle(argv
[1])) {
1397 reply("NSMSG_BAD_HANDLE", argv
[1]);
1401 if (nickserv_conf
.email_required
) {
1402 if (!valid_email(argv
[4])) {
1403 reply("NSMSG_BAD_EMAIL_ADDR");
1408 if (strchr(argv
[3], '@')) {
1409 mask
= canonicalize_hostmask(strdup(argv
[3]));
1411 settee
= GetUserH(nickserv_conf
.email_required
? argv
[5] : argv
[4]);
1413 reply("MSG_NICK_UNKNOWN", nickserv_conf
.email_required
? argv
[5] : argv
[4]);
1420 } else if ((settee
= GetUserH(argv
[3]))) {
1421 mask
= generate_hostmask(settee
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
1423 reply("NSMSG_REGISTER_BAD_NICKMASK", argv
[3]);
1426 if (settee
&& settee
->handle_info
) {
1427 reply("NSMSG_USER_PREV_AUTH", settee
->nick
);
1431 if (!(hi
= nickserv_register(user
, settee
, argv
[1], argv
[2], 0))) {
1432 if (nickserv_conf
.email_required
) {
1433 nickserv_set_email_addr(hi
, argv
[4]);
1434 if (nickserv_conf
.sync_log
)
1435 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, argv
[4], user
->info
);
1440 string_list_append(hi
->masks
, mask
);
1444 static NICKSERV_FUNC(cmd_handleinfo
)
1447 unsigned int i
, pos
=0, herelen
;
1448 struct userNode
*target
, *next_un
;
1449 struct handle_info
*hi
;
1450 const char *nsmsg_none
;
1453 if (!(hi
= user
->handle_info
)) {
1454 reply("NSMSG_MUST_AUTH");
1457 } else if (!(hi
= modcmd_get_handle_info(user
, argv
[1]))) {
1461 nsmsg_none
= handle_find_message(hi
, "MSG_NONE");
1462 reply("NSMSG_HANDLEINFO_ON", hi
->handle
);
1464 #ifdef WITH_PROTOCOL_BAHAMUT
1465 reply("NSMSG_HANDLEINFO_ID", hi
->id
);
1467 reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi
->registered
));
1470 intervalString(buff
, now
- hi
->lastseen
, user
->handle_info
);
1471 reply("NSMSG_HANDLEINFO_LASTSEEN", buff
);
1473 reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
1476 reply("NSMSG_HANDLEINFO_INFOLINE", (hi
->infoline
? hi
->infoline
: nsmsg_none
));
1477 if (HANDLE_FLAGGED(hi
, FROZEN
))
1478 reply("NSMSG_HANDLEINFO_VACATION");
1480 if (oper_has_access(user
, cmd
->parent
->bot
, 0, 1)) {
1481 struct do_not_register
*dnr
;
1482 if ((dnr
= chanserv_is_dnr(NULL
, hi
)))
1483 reply("NSMSG_HANDLEINFO_DNR", dnr
->setter
, dnr
->reason
);
1484 if (!oper_outranks(user
, hi
))
1486 } else if (hi
!= user
->handle_info
) {
1487 reply("NSMSG_HANDLEINFO_END");
1491 if (nickserv_conf
.email_enabled
)
1492 reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user
, hi
));
1496 switch (hi
->cookie
->type
) {
1497 case ACTIVATION
: type
= "NSMSG_HANDLEINFO_COOKIE_ACTIVATION"; break;
1498 case PASSWORD_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_PASSWORD"; break;
1499 case EMAIL_CHANGE
: type
= "NSMSG_HANDLEINFO_COOKIE_EMAIL"; break;
1500 case ALLOWAUTH
: type
= "NSMSG_HANDLEINFO_COOKIE_ALLOWAUTH"; break;
1501 default: type
= "NSMSG_HANDLEINFO_COOKIE_UNKNOWN"; break;
1507 unsigned long flen
= 1;
1508 char flags
[34]; /* 32 bits possible plus '+' and '\0' */
1510 for (i
=0, flen
=1; handle_flags
[i
]; i
++)
1511 if (hi
->flags
& 1 << i
)
1512 flags
[flen
++] = handle_flags
[i
];
1514 reply("NSMSG_HANDLEINFO_FLAGS", flags
);
1516 reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none
);
1519 if (HANDLE_FLAGGED(hi
, SUPPORT_HELPER
)
1520 || HANDLE_FLAGGED(hi
, NETWORK_HELPER
)
1521 || (hi
->opserv_level
> 0)) {
1522 reply("NSMSG_HANDLEINFO_EPITHET", (hi
->epithet
? hi
->epithet
: nsmsg_none
));
1525 if (IsHelping(user
) || IsOper(user
))
1530 strftime(date
, 64, "%b %d %Y", localtime(&hi
->note
->date
));
1531 reply("NSMSG_HANDLEINFO_NOTE", hi
->note
->setter
, date
, hi
->note
->note
);
1536 reply("NSMSG_HANDLEINFO_FAKEHOST", (hi
->fakehost
? hi
->fakehost
: handle_find_message(hi
, "MSG_NONE")));
1538 if (hi
->last_quit_host
[0])
1539 reply("NSMSG_HANDLEINFO_LAST_HOST", hi
->last_quit_host
);
1541 reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
1543 if (nickserv_conf
.disable_nicks
) {
1544 /* nicks disabled; don't show anything about registered nicks */
1545 } else if (hi
->nicks
) {
1546 struct nick_info
*ni
, *next_ni
;
1547 for (ni
= hi
->nicks
; ni
; ni
= next_ni
) {
1548 herelen
= strlen(ni
->nick
);
1549 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1551 goto print_nicks_buff
;
1555 memcpy(buff
+pos
, ni
->nick
, herelen
);
1556 pos
+= herelen
; buff
[pos
++] = ' ';
1560 reply("NSMSG_HANDLEINFO_NICKS", buff
);
1565 reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none
);
1568 if (hi
->masks
->used
) {
1569 for (i
=0; i
< hi
->masks
->used
; i
++) {
1570 herelen
= strlen(hi
->masks
->list
[i
]);
1571 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1573 goto print_mask_buff
;
1575 memcpy(buff
+pos
, hi
->masks
->list
[i
], herelen
);
1576 pos
+= herelen
; buff
[pos
++] = ' ';
1577 if (i
+1 == hi
->masks
->used
) {
1580 reply("NSMSG_HANDLEINFO_MASKS", buff
);
1585 reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none
);
1589 struct userData
*channel
, *next
;
1592 for (channel
= hi
->channels
; channel
; channel
= next
) {
1593 next
= channel
->u_next
;
1594 name
= channel
->channel
->channel
->name
;
1595 herelen
= strlen(name
);
1596 if (pos
+ herelen
+ 7 > ArrayLength(buff
)) {
1598 goto print_chans_buff
;
1600 if (IsUserSuspended(channel
))
1602 pos
+= sprintf(buff
+pos
, "%s:%s ", user_level_name_from_level(channel
->access
), name
);
1606 reply("NSMSG_HANDLEINFO_CHANNELS", buff
);
1611 reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none
);
1614 for (target
= hi
->users
; target
; target
= next_un
) {
1615 herelen
= strlen(target
->nick
);
1616 if (pos
+ herelen
+ 1 > ArrayLength(buff
)) {
1618 goto print_cnick_buff
;
1620 next_un
= target
->next_authed
;
1622 memcpy(buff
+pos
, target
->nick
, herelen
);
1623 pos
+= herelen
; buff
[pos
++] = ' ';
1627 reply("NSMSG_HANDLEINFO_CURRENT", buff
);
1632 reply("NSMSG_HANDLEINFO_END");
1636 static NICKSERV_FUNC(cmd_userinfo
)
1638 struct userNode
*target
;
1640 NICKSERV_MIN_PARMS(2);
1641 if (!(target
= GetUserH(argv
[1]))) {
1642 reply("MSG_NICK_UNKNOWN", argv
[1]);
1645 if (target
->handle_info
)
1646 reply("NSMSG_USERINFO_AUTHED_AS", target
->nick
, target
->handle_info
->handle
);
1648 reply("NSMSG_USERINFO_NOT_AUTHED", target
->nick
);
1652 static NICKSERV_FUNC(cmd_nickinfo
)
1654 struct nick_info
*ni
;
1656 NICKSERV_MIN_PARMS(2);
1657 if (!(ni
= get_nick_info(argv
[1]))) {
1658 reply("MSG_NICK_UNKNOWN", argv
[1]);
1661 reply("NSMSG_NICKINFO_OWNER", ni
->nick
, ni
->owner
->handle
);
1665 static NICKSERV_FUNC(cmd_rename_handle
)
1667 struct handle_info
*hi
;
1668 struct userNode
*uNode
;
1669 char msgbuf
[MAXLEN
], *old_handle
;
1672 NICKSERV_MIN_PARMS(3);
1673 if (!(hi
= get_victim_oper(user
, argv
[1])))
1675 if (!is_valid_handle(argv
[2])) {
1676 reply("NSMSG_FAIL_RENAME", argv
[1], argv
[2]);
1679 if (get_handle_info(argv
[2])) {
1680 reply("NSMSG_HANDLE_EXISTS", argv
[2]);
1683 if(strlen(argv
[2]) > 15)
1685 reply("NMSG_HANDLE_TOLONG", argv
[2], 15);
1689 dict_remove2(nickserv_handle_dict
, old_handle
= hi
->handle
, 1);
1690 hi
->handle
= strdup(argv
[2]);
1691 dict_insert(nickserv_handle_dict
, hi
->handle
, hi
);
1692 for (nn
=0; nn
<rf_list_used
; nn
++)
1693 rf_list
[nn
](hi
, old_handle
);
1694 snprintf(msgbuf
, sizeof(msgbuf
), "%s renamed account %s to %s.", user
->handle_info
->handle
, old_handle
, hi
->handle
);
1697 if (nickserv_conf
.sync_log
) {
1698 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
1699 irc_rename(uNode
, hi
->handle
);
1701 SyncLog("RENAME %s %s", old_handle
, hi
->handle
);
1704 reply("NSMSG_HANDLE_CHANGED", old_handle
, hi
->handle
);
1705 global_message(MESSAGE_RECIPIENT_STAFF
, msgbuf
);
1710 static failpw_func_t
*failpw_func_list
;
1711 static unsigned int failpw_func_size
= 0, failpw_func_used
= 0;
1714 reg_failpw_func(failpw_func_t func
)
1716 if (failpw_func_used
== failpw_func_size
) {
1717 if (failpw_func_size
) {
1718 failpw_func_size
<<= 1;
1719 failpw_func_list
= realloc(failpw_func_list
, failpw_func_size
*sizeof(failpw_func_t
));
1721 failpw_func_size
= 8;
1722 failpw_func_list
= malloc(failpw_func_size
*sizeof(failpw_func_t
));
1725 failpw_func_list
[failpw_func_used
++] = func
;
1729 * Return hi if the handle/pass pair matches, NULL if it doesnt.
1731 * called by nefariouses enhanced AC login-on-connect code
1734 struct handle_info
*loc_auth(char *handle
, char *password
)
1736 int pw_arg
, used
, maxlogins
;
1739 struct handle_info
*hi
;
1740 struct userNode
*other
;
1742 hi
= dict_find(nickserv_handle_dict
, handle
, NULL
);
1748 /* We don't know the users hostname, or anything because they
1749 * havn't registered yet. So we can only allow LOC if your
1750 * account has *@* as a hostmask.
1752 for (ii
=0; ii
<hi
->masks
->used
; ii
++)
1754 if (!strcmp(hi
->masks
->list
[ii
], "*@*"))
1763 /* Responses from here on look up the language used by the handle they asked about. */
1764 if (!checkpass(password
, hi
->passwd
)) {
1767 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1770 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1771 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1772 if (++used
>= maxlogins
) {
1779 static NICKSERV_FUNC(cmd_auth
)
1781 int pw_arg
, used
, maxlogins
;
1782 struct handle_info
*hi
;
1784 struct userNode
*other
;
1786 if (user
->handle_info
) {
1787 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
1790 if (IsStamped(user
)) {
1791 /* Unauthenticated users might still have been stamped
1792 previously and could therefore have a hidden host;
1793 do not allow them to authenticate. */
1794 reply("NSMSG_STAMPED_AUTH");
1798 hi
= dict_find(nickserv_handle_dict
, argv
[1], NULL
);
1800 } else if (argc
== 2) {
1801 if (nickserv_conf
.disable_nicks
) {
1802 if (!(hi
= get_handle_info(user
->nick
))) {
1803 reply("NSMSG_HANDLE_NOT_FOUND");
1807 /* try to look up their handle from their nick */
1808 struct nick_info
*ni
;
1809 ni
= get_nick_info(user
->nick
);
1811 reply("NSMSG_NICK_NOT_REGISTERED", user
->nick
);
1818 reply("MSG_MISSING_PARAMS", argv
[0]);
1819 svccmd_send_help_brief(user
, nickserv
, cmd
);
1823 reply("NSMSG_HANDLE_NOT_FOUND");
1826 /* Responses from here on look up the language used by the handle they asked about. */
1827 passwd
= argv
[pw_arg
];
1828 if (!valid_user_for(user
, hi
)) {
1829 if (hi
->email_addr
&& nickserv_conf
.email_enabled
)
1830 send_message_type(4, user
, cmd
->parent
->bot
,
1831 handle_find_message(hi
, "NSMSG_USE_AUTHCOOKIE"),
1834 send_message_type(4, user
, cmd
->parent
->bot
,
1835 handle_find_message(hi
, "NSMSG_HOSTMASK_INVALID"),
1837 argv
[pw_arg
] = "BADMASK";
1840 if (!checkpass(passwd
, hi
->passwd
)) {
1842 send_message_type(4, user
, cmd
->parent
->bot
,
1843 handle_find_message(hi
, "NSMSG_PASSWORD_INVALID"));
1844 argv
[pw_arg
] = "BADPASS";
1845 for (n
=0; n
<failpw_func_used
; n
++) failpw_func_list
[n
](user
, hi
);
1846 if (nickserv_conf
.autogag_enabled
) {
1847 if (!user
->auth_policer
.params
) {
1848 user
->auth_policer
.last_req
= now
;
1849 user
->auth_policer
.params
= nickserv_conf
.auth_policer_params
;
1851 if (!policer_conforms(&user
->auth_policer
, now
, 1.0)) {
1853 hostmask
= generate_hostmask(user
, GENMASK_STRICT_HOST
|GENMASK_BYIP
|GENMASK_NO_HIDING
);
1854 log_module(NS_LOG
, LOG_INFO
, "%s auto-gagged for repeated password guessing.", hostmask
);
1855 gag_create(hostmask
, nickserv
->nick
, "Repeated password guessing.", now
+nickserv_conf
.autogag_duration
);
1857 argv
[pw_arg
] = "GAGGED";
1862 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
1863 send_message_type(4, user
, cmd
->parent
->bot
,
1864 handle_find_message(hi
, "NSMSG_HANDLE_SUSPENDED"));
1865 argv
[pw_arg
] = "SUSPENDED";
1868 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
1869 for (used
= 0, other
= hi
->users
; other
; other
= other
->next_authed
) {
1870 if (++used
>= maxlogins
) {
1871 send_message_type(4, user
, cmd
->parent
->bot
,
1872 handle_find_message(hi
, "NSMSG_MAX_LOGINS"),
1874 argv
[pw_arg
] = "MAXLOGINS";
1879 set_user_handle_info(user
, hi
, 1);
1880 if (nickserv_conf
.email_required
&& !hi
->email_addr
)
1881 reply("NSMSG_PLEASE_SET_EMAIL");
1882 if (!is_secure_password(hi
->handle
, passwd
, NULL
))
1883 reply("NSMSG_WEAK_PASSWORD");
1884 if (hi
->passwd
[0] != '$')
1885 cryptpass(passwd
, hi
->passwd
);
1887 /* If a channel was waiting for this user to auth,
1888 * finish adding them */
1889 process_adduser_pending(user
);
1891 reply("NSMSG_AUTH_SUCCESS");
1894 /* Set +x if autohide is on */
1895 if(HANDLE_FLAGGED(hi
, AUTOHIDE
))
1896 irc_umode(user
, "+x");
1898 if(!IsOper(user
)) /* If they arnt already opered.. */
1900 /* Auto Oper users with Opserv access -Life4Christ 8-10-2005 */
1901 if( nickserv_conf
.auto_admin
[0] && hi
->opserv_level
>= opserv_conf_admin_level())
1903 irc_umode(user
,nickserv_conf
.auto_admin
);
1904 reply("NSMSG_AUTO_OPER_ADMIN");
1906 else if (nickserv_conf
.auto_oper
[0] && hi
->opserv_level
> 0)
1908 irc_umode(user
,nickserv_conf
.auto_oper
);
1909 reply("NSMSG_AUTO_OPER");
1913 /* Wipe out the pass for the logs */
1914 argv
[pw_arg
] = "****";
1918 static allowauth_func_t
*allowauth_func_list
;
1919 static unsigned int allowauth_func_size
= 0, allowauth_func_used
= 0;
1922 reg_allowauth_func(allowauth_func_t func
)
1924 if (allowauth_func_used
== allowauth_func_size
) {
1925 if (allowauth_func_size
) {
1926 allowauth_func_size
<<= 1;
1927 allowauth_func_list
= realloc(allowauth_func_list
, allowauth_func_size
*sizeof(allowauth_func_t
));
1929 allowauth_func_size
= 8;
1930 allowauth_func_list
= malloc(allowauth_func_size
*sizeof(allowauth_func_t
));
1933 allowauth_func_list
[allowauth_func_used
++] = func
;
1936 static NICKSERV_FUNC(cmd_allowauth
)
1938 struct userNode
*target
;
1939 struct handle_info
*hi
;
1942 NICKSERV_MIN_PARMS(2);
1943 if (!(target
= GetUserH(argv
[1]))) {
1944 reply("MSG_NICK_UNKNOWN", argv
[1]);
1947 if (target
->handle_info
) {
1948 reply("NSMSG_USER_PREV_AUTH", target
->nick
);
1951 if (IsStamped(target
)) {
1952 /* Unauthenticated users might still have been stamped
1953 previously and could therefore have a hidden host;
1954 do not allow them to authenticate to an account. */
1955 reply("NSMSG_USER_PREV_STAMP", target
->nick
);
1960 else if (!(hi
= get_handle_info(argv
[2]))) {
1961 reply("MSG_HANDLE_UNKNOWN", argv
[2]);
1965 if (hi
->opserv_level
> user
->handle_info
->opserv_level
) {
1966 reply("MSG_USER_OUTRANKED", hi
->handle
);
1969 if (((hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
))
1970 || (hi
->opserv_level
> 0))
1971 && ((argc
< 4) || irccasecmp(argv
[3], "staff"))) {
1972 reply("NSMSG_ALLOWAUTH_STAFF", hi
->handle
);
1975 dict_insert(nickserv_allow_auth_dict
, target
->nick
, hi
);
1976 reply("NSMSG_AUTH_ALLOWED", target
->nick
, hi
->handle
);
1977 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_MSG", hi
->handle
, hi
->handle
);
1978 if (nickserv_conf
.email_enabled
)
1979 send_message(target
, nickserv
, "NSMSG_AUTH_ALLOWED_EMAIL");
1981 if (dict_remove(nickserv_allow_auth_dict
, target
->nick
))
1982 reply("NSMSG_AUTH_NORMAL_ONLY", target
->nick
);
1984 reply("NSMSG_AUTH_UNSPECIAL", target
->nick
);
1986 for (n
=0; n
<allowauth_func_used
; n
++)
1987 allowauth_func_list
[n
](user
, target
, hi
);
1991 static NICKSERV_FUNC(cmd_authcookie
)
1993 struct handle_info
*hi
;
1995 NICKSERV_MIN_PARMS(2);
1996 if (user
->handle_info
) {
1997 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2000 if (IsStamped(user
)) {
2001 /* Unauthenticated users might still have been stamped
2002 previously and could therefore have a hidden host;
2003 do not allow them to authenticate to an account. */
2004 reply("NSMSG_STAMPED_AUTHCOOKIE");
2007 if (!(hi
= get_handle_info(argv
[1]))) {
2008 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2011 if (!hi
->email_addr
) {
2012 reply("MSG_SET_EMAIL_ADDR");
2015 nickserv_make_cookie(user
, hi
, ALLOWAUTH
, NULL
, 0);
2019 static NICKSERV_FUNC(cmd_delcookie
)
2021 struct handle_info
*hi
;
2023 hi
= user
->handle_info
;
2025 reply("NSMSG_NO_COOKIE");
2028 switch (hi
->cookie
->type
) {
2031 reply("NSMSG_MUST_TIME_OUT");
2034 nickserv_eat_cookie(hi
->cookie
);
2035 reply("NSMSG_ATE_COOKIE");
2041 static NICKSERV_FUNC(cmd_odelcookie
)
2043 struct handle_info
*hi
;
2045 NICKSERV_MIN_PARMS(2);
2047 if (!(hi
= get_victim_oper(user
, argv
[1])))
2051 reply("NSMSG_NO_COOKIE_FOREIGN", hi
->handle
);
2055 nickserv_eat_cookie(hi
->cookie
);
2056 reply("NSMSG_ATE_FOREIGN_COOKIE", hi
->handle
);
2061 static NICKSERV_FUNC(cmd_resetpass
)
2063 struct handle_info
*hi
;
2064 char crypted
[MD5_CRYPT_LENGTH
];
2067 NICKSERV_MIN_PARMS(3);
2068 if(argc
>= 4 && !strcmp(argv
[3], "WEBLINK"))
2072 if (user
->handle_info
) {
2073 reply("NSMSG_ALREADY_AUTHED", user
->handle_info
->handle
);
2076 if (IsStamped(user
)) {
2077 /* Unauthenticated users might still have been stamped
2078 previously and could therefore have a hidden host;
2079 do not allow them to activate an account. */
2080 reply("NSMSG_STAMPED_RESETPASS");
2083 if (!(hi
= get_handle_info(argv
[1]))) {
2084 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2087 if (!hi
->email_addr
) {
2088 reply("MSG_SET_EMAIL_ADDR");
2091 cryptpass(argv
[2], crypted
);
2093 nickserv_make_cookie(user
, hi
, PASSWORD_CHANGE
, crypted
, weblink
);
2097 static NICKSERV_FUNC(cmd_cookie
)
2099 struct handle_info
*hi
;
2102 if ((argc
== 2) && (hi
= user
->handle_info
) && hi
->cookie
&& (hi
->cookie
->type
== EMAIL_CHANGE
)) {
2105 NICKSERV_MIN_PARMS(3);
2106 if (!(hi
= get_handle_info(argv
[1]))) {
2107 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
2113 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
2114 reply("NSMSG_HANDLE_SUSPENDED");
2119 reply("NSMSG_NO_COOKIE");
2123 /* Check validity of operation before comparing cookie to
2124 * prohibit guessing by authed users. */
2125 if (user
->handle_info
2126 && (hi
->cookie
->type
!= EMAIL_CHANGE
)
2127 && (hi
->cookie
->type
!= PASSWORD_CHANGE
)) {
2128 reply("NSMSG_CANNOT_COOKIE");
2132 if (strcmp(cookie
, hi
->cookie
->cookie
)) {
2133 reply("NSMSG_BAD_COOKIE");
2137 switch (hi
->cookie
->type
) {
2139 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2140 set_user_handle_info(user
, hi
, 1);
2141 reply("NSMSG_HANDLE_ACTIVATED");
2142 if (nickserv_conf
.sync_log
)
2143 SyncLog("ACCOUNTACC %s", hi
->handle
);
2145 case PASSWORD_CHANGE
:
2146 set_user_handle_info(user
, hi
, 1);
2147 safestrncpy(hi
->passwd
, hi
->cookie
->data
, sizeof(hi
->passwd
));
2148 reply("NSMSG_PASSWORD_CHANGED");
2149 if (nickserv_conf
.sync_log
)
2150 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2153 if (!hi
->email_addr
&& nickserv_conf
.sync_log
) {
2155 * This should only happen if an OREGISTER was sent. Require
2156 * email must be enabled! - SiRVulcaN
2158 if (nickserv_conf
.sync_log
)
2159 SyncLog("REGISTER %s %s %s %s", hi
->handle
, hi
->passwd
, hi
->cookie
->data
, user
->info
);
2161 nickserv_set_email_addr(hi
, hi
->cookie
->data
);
2162 reply("NSMSG_EMAIL_CHANGED");
2163 if (nickserv_conf
.sync_log
)
2164 SyncLog("EMAILCHANGE %s %s", hi
->handle
, hi
->cookie
->data
);
2167 set_user_handle_info(user
, hi
, 1);
2168 reply("NSMSG_AUTH_SUCCESS");
2171 reply("NSMSG_BAD_COOKIE_TYPE", hi
->cookie
->type
);
2172 log_module(NS_LOG
, LOG_ERROR
, "Bad cookie type %d for account %s.", hi
->cookie
->type
, hi
->handle
);
2176 nickserv_eat_cookie(hi
->cookie
);
2178 process_adduser_pending(user
);
2183 static NICKSERV_FUNC(cmd_oregnick
) {
2185 struct handle_info
*target
;
2186 struct nick_info
*ni
;
2188 NICKSERV_MIN_PARMS(3);
2189 if (!(target
= modcmd_get_handle_info(user
, argv
[1])))
2192 if (!is_registerable_nick(nick
)) {
2193 reply("NSMSG_BAD_NICK", nick
);
2196 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2198 reply("NSMSG_NICK_EXISTS", nick
);
2201 register_nick(nick
, target
);
2202 reply("NSMSG_OREGNICK_SUCCESS", nick
, target
->handle
);
2206 static NICKSERV_FUNC(cmd_regnick
) {
2208 struct nick_info
*ni
;
2210 if (!is_registerable_nick(user
->nick
)) {
2211 reply("NSMSG_BAD_NICK", user
->nick
);
2214 /* count their nicks, see if it's too many */
2215 for (n
=0,ni
=user
->handle_info
->nicks
; ni
; n
++,ni
=ni
->next
) ;
2216 if (n
>= nickserv_conf
.nicks_per_handle
) {
2217 reply("NSMSG_TOO_MANY_NICKS");
2220 ni
= dict_find(nickserv_nick_dict
, user
->nick
, NULL
);
2222 reply("NSMSG_NICK_EXISTS", user
->nick
);
2225 register_nick(user
->nick
, user
->handle_info
);
2226 reply("NSMSG_REGNICK_SUCCESS", user
->nick
);
2230 static NICKSERV_FUNC(cmd_pass
)
2232 struct handle_info
*hi
;
2233 const char *old_pass
, *new_pass
;
2235 NICKSERV_MIN_PARMS(3);
2236 hi
= user
->handle_info
;
2240 if (!is_secure_password(hi
->handle
, new_pass
, user
)) return 0;
2241 if (!checkpass(old_pass
, hi
->passwd
)) {
2242 argv
[1] = "BADPASS";
2243 reply("NSMSG_PASSWORD_INVALID");
2246 cryptpass(new_pass
, hi
->passwd
);
2247 if (nickserv_conf
.sync_log
)
2248 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2250 reply("NSMSG_PASS_SUCCESS");
2255 nickserv_addmask(struct userNode
*user
, struct handle_info
*hi
, const char *mask
)
2258 char *new_mask
= canonicalize_hostmask(strdup(mask
));
2259 for (i
=0; i
<hi
->masks
->used
; i
++) {
2260 if (!irccasecmp(new_mask
, hi
->masks
->list
[i
])) {
2261 send_message(user
, nickserv
, "NSMSG_ADDMASK_ALREADY", new_mask
);
2266 string_list_append(hi
->masks
, new_mask
);
2267 send_message(user
, nickserv
, "NSMSG_ADDMASK_SUCCESS", new_mask
);
2271 static NICKSERV_FUNC(cmd_addmask
)
2274 char *mask
= generate_hostmask(user
, GENMASK_OMITNICK
|GENMASK_NO_HIDING
|GENMASK_ANY_IDENT
);
2275 int res
= nickserv_addmask(user
, user
->handle_info
, mask
);
2279 if (!is_gline(argv
[1])) {
2280 reply("NSMSG_MASK_INVALID", argv
[1]);
2283 return nickserv_addmask(user
, user
->handle_info
, argv
[1]);
2287 static NICKSERV_FUNC(cmd_oaddmask
)
2289 struct handle_info
*hi
;
2291 NICKSERV_MIN_PARMS(3);
2292 if (!(hi
= get_victim_oper(user
, argv
[1])))
2294 return nickserv_addmask(user
, hi
, argv
[2]);
2298 nickserv_delmask(struct userNode
*user
, struct handle_info
*hi
, const char *del_mask
)
2301 for (i
=0; i
<hi
->masks
->used
; i
++) {
2302 if (!strcmp(del_mask
, hi
->masks
->list
[i
])) {
2303 char *old_mask
= hi
->masks
->list
[i
];
2304 if (hi
->masks
->used
== 1) {
2305 send_message(user
, nickserv
, "NSMSG_DELMASK_NOTLAST");
2308 hi
->masks
->list
[i
] = hi
->masks
->list
[--hi
->masks
->used
];
2309 send_message(user
, nickserv
, "NSMSG_DELMASK_SUCCESS", old_mask
);
2314 send_message(user
, nickserv
, "NSMSG_DELMASK_NOT_FOUND");
2318 static NICKSERV_FUNC(cmd_delmask
)
2320 NICKSERV_MIN_PARMS(2);
2321 return nickserv_delmask(user
, user
->handle_info
, argv
[1]);
2324 static NICKSERV_FUNC(cmd_odelmask
)
2326 struct handle_info
*hi
;
2327 NICKSERV_MIN_PARMS(3);
2328 if (!(hi
= get_victim_oper(user
, argv
[1])))
2330 return nickserv_delmask(user
, hi
, argv
[2]);
2334 nickserv_modify_handle_flags(struct userNode
*user
, struct userNode
*bot
, const char *str
, unsigned long *padded
, unsigned long *premoved
) {
2335 unsigned int nn
, add
= 1, pos
;
2336 unsigned long added
, removed
, flag
;
2338 for (added
=removed
=nn
=0; str
[nn
]; nn
++) {
2340 case '+': add
= 1; break;
2341 case '-': add
= 0; break;
2343 if (!(pos
= handle_inverse_flags
[(unsigned char)str
[nn
]])) {
2344 send_message(user
, bot
, "NSMSG_INVALID_FLAG", str
[nn
]);
2347 if (user
&& (user
->handle_info
->opserv_level
< flag_access_levels
[pos
-1])) {
2348 /* cheesy avoidance of looking up the flag name.. */
2349 send_message(user
, bot
, "NSMSG_FLAG_PRIVILEGED", str
[nn
]);
2352 flag
= 1 << (pos
- 1);
2354 added
|= flag
, removed
&= ~flag
;
2356 removed
|= flag
, added
&= ~flag
;
2361 *premoved
= removed
;
2366 nickserv_apply_flags(struct userNode
*user
, struct handle_info
*hi
, const char *flags
)
2368 unsigned long before
, after
, added
, removed
;
2369 struct userNode
*uNode
;
2371 before
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2372 if (!nickserv_modify_handle_flags(user
, nickserv
, flags
, &added
, &removed
))
2374 hi
->flags
= (hi
->flags
| added
) & ~removed
;
2375 after
= hi
->flags
& (HI_FLAG_SUPPORT_HELPER
|HI_FLAG_NETWORK_HELPER
);
2377 /* Strip helping flag if they're only a support helper and not
2378 * currently in #support. */
2379 if (HANDLE_FLAGGED(hi
, HELPING
) && (after
== HI_FLAG_SUPPORT_HELPER
)) {
2380 struct channelList
*schannels
;
2382 schannels
= chanserv_support_channels();
2383 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
) {
2384 for (ii
= 0; ii
< schannels
->used
; ++ii
)
2385 if (GetUserMode(schannels
->list
[ii
], uNode
))
2387 if (ii
< schannels
->used
)
2391 HANDLE_CLEAR_FLAG(hi
, HELPING
);
2394 if (after
&& !before
) {
2395 /* Add user to current helper list. */
2396 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2397 userList_append(&curr_helpers
, uNode
);
2398 } else if (!after
&& before
) {
2399 /* Remove user from current helper list. */
2400 for (uNode
= hi
->users
; uNode
; uNode
= uNode
->next_authed
)
2401 userList_remove(&curr_helpers
, uNode
);
2408 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
2412 char *set_display
[] = {
2413 "INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
2414 "EMAIL", "ANNOUNCEMENTS", "AUTOHIDE", "MAXLOGINS", "LANGUAGE",
2415 "FAKEHOST", "TITLE", "EPITHET"
2418 send_message(user
, nickserv
, "NSMSG_SETTING_LIST");
2419 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_HEADER");
2421 /* Do this so options are presented in a consistent order. */
2422 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
2423 if ((opt
= dict_find(nickserv_opt_dict
, set_display
[i
], NULL
)))
2424 opt(user
, hi
, override
, 0, NULL
);
2425 send_message(user
, nickserv
, "NSMSG_SETTING_LIST_END");
2428 static NICKSERV_FUNC(cmd_set
)
2430 struct handle_info
*hi
;
2433 hi
= user
->handle_info
;
2435 set_list(user
, hi
, 0);
2438 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[1], NULL
))) {
2439 reply("NSMSG_INVALID_OPTION", argv
[1]);
2442 return opt(user
, hi
, 0, argc
-1, argv
+1);
2445 static NICKSERV_FUNC(cmd_oset
)
2447 struct handle_info
*hi
;
2450 NICKSERV_MIN_PARMS(2);
2452 if (!(hi
= get_victim_oper(user
, argv
[1])))
2456 set_list(user
, hi
, 0);
2460 if (!(opt
= dict_find(nickserv_opt_dict
, argv
[2], NULL
))) {
2461 reply("NSMSG_INVALID_OPTION", argv
[2]);
2465 return opt(user
, hi
, 1, argc
-2, argv
+2);
2468 static OPTION_FUNC(opt_info
)
2472 if ((argv
[1][0] == '*') && (argv
[1][1] == 0)) {
2474 hi
->infoline
= NULL
;
2476 hi
->infoline
= strdup(unsplit_string(argv
+1, argc
-1, NULL
));
2480 info
= hi
->infoline
? hi
->infoline
: user_find_message(user
, "MSG_NONE");
2481 send_message(user
, nickserv
, "NSMSG_SET_INFO", info
);
2485 static OPTION_FUNC(opt_width
)
2488 hi
->screen_width
= strtoul(argv
[1], NULL
, 0);
2490 if ((hi
->screen_width
> 0) && (hi
->screen_width
< MIN_LINE_SIZE
))
2491 hi
->screen_width
= MIN_LINE_SIZE
;
2492 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2493 hi
->screen_width
= MAX_LINE_SIZE
;
2495 send_message(user
, nickserv
, "NSMSG_SET_WIDTH", hi
->screen_width
);
2499 static OPTION_FUNC(opt_tablewidth
)
2502 hi
->table_width
= strtoul(argv
[1], NULL
, 0);
2504 if ((hi
->table_width
> 0) && (hi
->table_width
< MIN_LINE_SIZE
))
2505 hi
->table_width
= MIN_LINE_SIZE
;
2506 else if (hi
->screen_width
> MAX_LINE_SIZE
)
2507 hi
->table_width
= MAX_LINE_SIZE
;
2509 send_message(user
, nickserv
, "NSMSG_SET_TABLEWIDTH", hi
->table_width
);
2513 static OPTION_FUNC(opt_color
)
2516 if (enabled_string(argv
[1]))
2517 HANDLE_SET_FLAG(hi
, MIRC_COLOR
);
2518 else if (disabled_string(argv
[1]))
2519 HANDLE_CLEAR_FLAG(hi
, MIRC_COLOR
);
2521 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2526 send_message(user
, nickserv
, "NSMSG_SET_COLOR", user_find_message(user
, HANDLE_FLAGGED(hi
, MIRC_COLOR
) ? "MSG_ON" : "MSG_OFF"));
2530 static OPTION_FUNC(opt_privmsg
)
2533 if (enabled_string(argv
[1]))
2534 HANDLE_SET_FLAG(hi
, USE_PRIVMSG
);
2535 else if (disabled_string(argv
[1]))
2536 HANDLE_CLEAR_FLAG(hi
, USE_PRIVMSG
);
2538 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2543 send_message(user
, nickserv
, "NSMSG_SET_PRIVMSG", user_find_message(user
, HANDLE_FLAGGED(hi
, USE_PRIVMSG
) ? "MSG_ON" : "MSG_OFF"));
2547 static OPTION_FUNC(opt_autohide
)
2550 if (enabled_string(argv
[1]))
2551 HANDLE_SET_FLAG(hi
, AUTOHIDE
);
2552 else if (disabled_string(argv
[1]))
2553 HANDLE_CLEAR_FLAG(hi
, AUTOHIDE
);
2555 send_message(user
, nickserv
, "MSG_INVALID_BINARY", argv
[1]);
2560 send_message(user
, nickserv
, "NSMSG_SET_AUTOHIDE", user_find_message(user
, HANDLE_FLAGGED(hi
, AUTOHIDE
) ? "MSG_ON" : "MSG_OFF"));
2564 static OPTION_FUNC(opt_style
)
2569 if (!irccasecmp(argv
[1], "Clean"))
2570 hi
->userlist_style
= HI_STYLE_CLEAN
;
2571 else if (!irccasecmp(argv
[1], "Advanced"))
2572 hi
->userlist_style
= HI_STYLE_ADVANCED
;
2573 else /* Default to normal */
2574 hi
->userlist_style
= HI_STYLE_NORMAL
;
2575 } /* TODO: give error if unknow style is chosen */
2577 switch (hi
->userlist_style
) {
2578 case HI_STYLE_ADVANCED
:
2581 case HI_STYLE_CLEAN
:
2584 case HI_STYLE_NORMAL
:
2589 send_message(user
, nickserv
, "NSMSG_SET_STYLE", style
);
2593 static OPTION_FUNC(opt_announcements
)
2598 if (enabled_string(argv
[1]))
2599 hi
->announcements
= 'y';
2600 else if (disabled_string(argv
[1]))
2601 hi
->announcements
= 'n';
2602 else if (!strcmp(argv
[1], "?") || !irccasecmp(argv
[1], "default"))
2603 hi
->announcements
= '?';
2605 send_message(user
, nickserv
, "NSMSG_INVALID_ANNOUNCE", argv
[1]);
2610 switch (hi
->announcements
) {
2611 case 'y': choice
= user_find_message(user
, "MSG_ON"); break;
2612 case 'n': choice
= user_find_message(user
, "MSG_OFF"); break;
2613 case '?': choice
= "default"; break;
2614 default: choice
= "unknown"; break;
2616 send_message(user
, nickserv
, "NSMSG_SET_ANNOUNCEMENTS", choice
);
2620 static OPTION_FUNC(opt_password
)
2623 send_message(user
, nickserv
, "NSMSG_USE_CMD_PASS");
2628 cryptpass(argv
[1], hi
->passwd
);
2630 if (nickserv_conf
.sync_log
)
2631 SyncLog("PASSCHANGE %s %s", hi
->handle
, hi
->passwd
);
2633 send_message(user
, nickserv
, "NSMSG_SET_PASSWORD", "***");
2637 static OPTION_FUNC(opt_flags
)
2640 unsigned int ii
, flen
;
2643 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2648 nickserv_apply_flags(user
, hi
, argv
[1]);
2650 for (ii
= flen
= 0; handle_flags
[ii
]; ii
++)
2651 if (hi
->flags
& (1 << ii
))
2652 flags
[flen
++] = handle_flags
[ii
];
2655 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", flags
);
2657 send_message(user
, nickserv
, "NSMSG_SET_FLAGS", user_find_message(user
, "MSG_NONE"));
2661 static OPTION_FUNC(opt_email
)
2665 if (!valid_email(argv
[1])) {
2666 send_message(user
, nickserv
, "NSMSG_BAD_EMAIL_ADDR");
2669 if ((str
= sendmail_prohibited_address(argv
[1]))) {
2670 send_message(user
, nickserv
, "NSMSG_EMAIL_PROHIBITED", argv
[1], str
);
2673 if (hi
->email_addr
&& !irccasecmp(hi
->email_addr
, argv
[1]))
2674 send_message(user
, nickserv
, "NSMSG_EMAIL_SAME");
2676 nickserv_make_cookie(user
, hi
, EMAIL_CHANGE
, argv
[1], 0);
2678 nickserv_set_email_addr(hi
, argv
[1]);
2680 nickserv_eat_cookie(hi
->cookie
);
2681 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2684 send_message(user
, nickserv
, "NSMSG_SET_EMAIL", visible_email_addr(user
, hi
));
2688 static OPTION_FUNC(opt_maxlogins
)
2690 unsigned char maxlogins
;
2692 maxlogins
= strtoul(argv
[1], NULL
, 0);
2693 if ((maxlogins
> nickserv_conf
.hard_maxlogins
) && !override
) {
2694 send_message(user
, nickserv
, "NSMSG_BAD_MAX_LOGINS", nickserv_conf
.hard_maxlogins
);
2697 hi
->maxlogins
= maxlogins
;
2699 maxlogins
= hi
->maxlogins
? hi
->maxlogins
: nickserv_conf
.default_maxlogins
;
2700 send_message(user
, nickserv
, "NSMSG_SET_MAXLOGINS", maxlogins
);
2704 static OPTION_FUNC(opt_language
)
2706 struct language
*lang
;
2708 lang
= language_find(argv
[1]);
2709 if (irccasecmp(lang
->name
, argv
[1]))
2710 send_message(user
, nickserv
, "NSMSG_LANGUAGE_NOT_FOUND", argv
[1], lang
->name
);
2711 hi
->language
= lang
;
2713 send_message(user
, nickserv
, "NSMSG_SET_LANGUAGE", hi
->language
->name
);
2718 oper_try_set_access(struct userNode
*user
, struct userNode
*bot
, struct handle_info
*target
, unsigned int new_level
) {
2719 if (!oper_has_access(user
, bot
, nickserv_conf
.modoper_level
, 0))
2721 if ((user
->handle_info
->opserv_level
< target
->opserv_level
)
2722 || ((user
->handle_info
->opserv_level
== target
->opserv_level
)
2723 && (user
->handle_info
->opserv_level
< 1000))) {
2724 send_message(user
, bot
, "MSG_USER_OUTRANKED", target
->handle
);
2727 if ((user
->handle_info
->opserv_level
< new_level
)
2728 || ((user
->handle_info
->opserv_level
== new_level
)
2729 && (user
->handle_info
->opserv_level
< 1000))) {
2730 send_message(user
, bot
, "NSMSG_OPSERV_LEVEL_BAD");
2733 if (user
->handle_info
== target
) {
2734 send_message(user
, bot
, "MSG_STUPID_ACCESS_CHANGE");
2737 if (target
->opserv_level
== new_level
)
2739 log_module(NS_LOG
, LOG_INFO
, "Account %s setting oper level for account %s to %d (from %d).",
2740 user
->handle_info
->handle
, target
->handle
, new_level
, target
->opserv_level
);
2741 target
->opserv_level
= new_level
;
2745 static OPTION_FUNC(opt_level
)
2750 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2754 res
= (argc
> 1) ? oper_try_set_access(user
, nickserv
, hi
, strtoul(argv
[1], NULL
, 0)) : 0;
2755 send_message(user
, nickserv
, "NSMSG_SET_LEVEL", hi
->opserv_level
);
2759 static OPTION_FUNC(opt_epithet
)
2761 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_epithet_level
, 0)) {
2764 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2768 epithet
= unsplit_string(argv
+1, argc
-1, NULL
);
2772 if ((epithet
[0] == '*') && !epithet
[1])
2775 hi
->epithet
= strdup(epithet
);
2779 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", hi
->epithet
);
2781 send_message(user
, nickserv
, "NSMSG_SET_EPITHET", user_find_message(user
, "MSG_NONE"));
2785 static OPTION_FUNC(opt_title
)
2789 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_title_level
, 0)) {
2791 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2796 if (strchr(title
, '.')) {
2797 send_message(user
, nickserv
, "NSMSG_TITLE_INVALID");
2800 if ((strlen(user
->handle_info
->handle
) + strlen(title
) +
2801 strlen(nickserv_conf
.titlehost_suffix
) + 2) > HOSTLEN
) {
2802 send_message(user
, nickserv
, "NSMSG_TITLE_TRUNCATED");
2807 if (!strcmp(title
, "*")) {
2808 hi
->fakehost
= NULL
;
2810 hi
->fakehost
= malloc(strlen(title
)+2);
2811 hi
->fakehost
[0] = '.';
2812 strcpy(hi
->fakehost
+1, title
);
2815 } else if (hi
->fakehost
&& (hi
->fakehost
[0] == '.'))
2816 title
= hi
->fakehost
+ 1;
2820 title
= user_find_message(user
, "MSG_NONE");
2821 send_message(user
, nickserv
, "NSMSG_SET_TITLE", title
);
2825 static OPTION_FUNC(opt_fakehost
)
2829 if ((argc
> 1) && oper_has_access(user
, nickserv
, nickserv_conf
.set_fakehost_level
, 0)) {
2831 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2836 if ((strlen(fake
) > HOSTLEN
) || (fake
[0] == '.')) {
2837 send_message(user
, nickserv
, "NSMSG_FAKEHOST_INVALID", HOSTLEN
);
2841 if (!strcmp(fake
, "*"))
2842 hi
->fakehost
= NULL
;
2844 hi
->fakehost
= strdup(fake
);
2845 fake
= hi
->fakehost
;
2848 fake
= generate_fakehost(hi
);
2850 fake
= user_find_message(user
, "MSG_NONE");
2851 send_message(user
, nickserv
, "NSMSG_SET_FAKEHOST", fake
);
2855 static OPTION_FUNC(opt_note
)
2858 send_message(user
, nickserv
, "MSG_SETTING_PRIVILEGED", argv
[0]);
2863 char *text
= unsplit_string(argv
+ 1, argc
- 1, NULL
);
2868 if ((text
[0] == '*') && !text
[1])
2871 if (!(hi
->note
= nickserv_add_note(user
->handle_info
->handle
, now
, text
)))
2876 send_message(user
, nickserv
, "NSMSG_SET_NOTE", hi
->note
->note
);
2880 static NICKSERV_FUNC(cmd_reclaim
)
2882 struct handle_info
*hi
;
2883 struct nick_info
*ni
;
2884 struct userNode
*victim
;
2886 NICKSERV_MIN_PARMS(2);
2887 hi
= user
->handle_info
;
2888 ni
= dict_find(nickserv_nick_dict
, argv
[1], 0);
2890 reply("NSMSG_UNKNOWN_NICK", argv
[1]);
2893 if (ni
->owner
!= user
->handle_info
) {
2894 reply("NSMSG_NOT_YOUR_NICK", ni
->nick
);
2897 victim
= GetUserH(ni
->nick
);
2899 reply("MSG_NICK_UNKNOWN", ni
->nick
);
2902 if (victim
== user
) {
2903 reply("NSMSG_NICK_USER_YOU");
2906 nickserv_reclaim(victim
, ni
, nickserv_conf
.reclaim_action
);
2907 switch (nickserv_conf
.reclaim_action
) {
2908 case RECLAIM_NONE
: reply("NSMSG_RECLAIMED_NONE"); break;
2909 case RECLAIM_WARN
: reply("NSMSG_RECLAIMED_WARN", victim
->nick
); break;
2910 case RECLAIM_SVSNICK
: reply("NSMSG_RECLAIMED_SVSNICK", victim
->nick
); break;
2911 case RECLAIM_KILL
: reply("NSMSG_RECLAIMED_KILL", victim
->nick
); break;
2916 static NICKSERV_FUNC(cmd_unregnick
)
2919 struct handle_info
*hi
;
2920 struct nick_info
*ni
;
2922 hi
= user
->handle_info
;
2923 nick
= (argc
< 2) ? user
->nick
: (const char*)argv
[1];
2924 ni
= dict_find(nickserv_nick_dict
, nick
, NULL
);
2926 reply("NSMSG_UNKNOWN_NICK", nick
);
2929 if (hi
!= ni
->owner
) {
2930 reply("NSMSG_NOT_YOUR_NICK", nick
);
2933 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2938 static NICKSERV_FUNC(cmd_ounregnick
)
2940 struct nick_info
*ni
;
2942 NICKSERV_MIN_PARMS(2);
2943 if (!(ni
= get_nick_info(argv
[1]))) {
2944 reply("NSMSG_NICK_NOT_REGISTERED", argv
[1]);
2947 if (ni
->owner
->opserv_level
>= user
->handle_info
->opserv_level
) {
2948 reply("MSG_USER_OUTRANKED", ni
->nick
);
2951 reply("NSMSG_UNREGNICK_SUCCESS", ni
->nick
);
2956 static NICKSERV_FUNC(cmd_unregister
)
2958 struct handle_info
*hi
;
2961 NICKSERV_MIN_PARMS(2);
2962 hi
= user
->handle_info
;
2965 if (checkpass(passwd
, hi
->passwd
)) {
2966 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
2969 log_module(NS_LOG
, LOG_INFO
, "Account '%s' tried to unregister with the wrong password.", hi
->handle
);
2970 reply("NSMSG_PASSWORD_INVALID");
2975 static NICKSERV_FUNC(cmd_ounregister
)
2977 struct handle_info
*hi
;
2979 NICKSERV_MIN_PARMS(2);
2980 if (!(hi
= get_victim_oper(user
, argv
[1])))
2982 nickserv_unregister_handle(hi
, user
, cmd
->parent
->bot
);
2986 static NICKSERV_FUNC(cmd_status
)
2988 if (nickserv_conf
.disable_nicks
) {
2989 reply("NSMSG_GLOBAL_STATS_NONICK",
2990 dict_size(nickserv_handle_dict
));
2992 if (user
->handle_info
) {
2994 struct nick_info
*ni
;
2995 for (ni
=user
->handle_info
->nicks
; ni
; ni
=ni
->next
) cnt
++;
2996 reply("NSMSG_HANDLE_STATS", cnt
);
2998 reply("NSMSG_HANDLE_NONE");
3000 reply("NSMSG_GLOBAL_STATS",
3001 dict_size(nickserv_handle_dict
),
3002 dict_size(nickserv_nick_dict
));
3007 static NICKSERV_FUNC(cmd_ghost
)
3009 struct userNode
*target
;
3010 char reason
[MAXLEN
];
3012 NICKSERV_MIN_PARMS(2);
3013 if (!(target
= GetUserH(argv
[1]))) {
3014 reply("MSG_NICK_UNKNOWN", argv
[1]);
3017 if (target
== user
) {
3018 reply("NSMSG_CANNOT_GHOST_SELF");
3021 if (!target
->handle_info
|| (target
->handle_info
!= user
->handle_info
)) {
3022 reply("NSMSG_CANNOT_GHOST_USER", target
->nick
);
3025 snprintf(reason
, sizeof(reason
), "Ghost kill on account %s (requested by %s).", target
->handle_info
->handle
, user
->nick
);
3026 DelUser(target
, nickserv
, 1, reason
);
3027 reply("NSMSG_GHOST_KILLED", argv
[1]);
3031 static NICKSERV_FUNC(cmd_vacation
)
3033 HANDLE_SET_FLAG(user
->handle_info
, FROZEN
);
3034 reply("NSMSG_ON_VACATION");
3039 nickserv_saxdb_write(struct saxdb_context
*ctx
) {
3041 struct handle_info
*hi
;
3044 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3046 #ifdef WITH_PROTOCOL_BAHAMUT
3049 saxdb_start_record(ctx
, iter_key(it
), 0);
3050 if (hi
->announcements
!= '?') {
3051 flags
[0] = hi
->announcements
;
3053 saxdb_write_string(ctx
, KEY_ANNOUNCEMENTS
, flags
);
3056 struct handle_cookie
*cookie
= hi
->cookie
;
3059 switch (cookie
->type
) {
3060 case ACTIVATION
: type
= KEY_ACTIVATION
; break;
3061 case PASSWORD_CHANGE
: type
= KEY_PASSWORD_CHANGE
; break;
3062 case EMAIL_CHANGE
: type
= KEY_EMAIL_CHANGE
; break;
3063 case ALLOWAUTH
: type
= KEY_ALLOWAUTH
; break;
3064 default: type
= NULL
; break;
3067 saxdb_start_record(ctx
, KEY_COOKIE
, 0);
3068 saxdb_write_string(ctx
, KEY_COOKIE_TYPE
, type
);
3069 saxdb_write_int(ctx
, KEY_COOKIE_EXPIRES
, cookie
->expires
);
3071 saxdb_write_string(ctx
, KEY_COOKIE_DATA
, cookie
->data
);
3072 saxdb_write_string(ctx
, KEY_COOKIE
, cookie
->cookie
);
3073 saxdb_end_record(ctx
);
3077 saxdb_write_string(ctx
, KEY_EMAIL_ADDR
, hi
->email_addr
);
3079 saxdb_write_string(ctx
, KEY_EPITHET
, hi
->epithet
);
3081 saxdb_start_record(ctx
, KEY_NOTE_NOTE
, 0);
3082 saxdb_write_string(ctx
, KEY_NOTE_SETTER
, hi
->note
->setter
);
3083 saxdb_write_int(ctx
, KEY_NOTE_DATE
, hi
->note
->date
);
3084 saxdb_write_string(ctx
, KEY_NOTE_NOTE
, hi
->note
->note
);
3085 saxdb_end_record(ctx
);
3089 saxdb_write_string(ctx
, KEY_FAKEHOST
, hi
->fakehost
);
3093 for (ii
=flen
=0; handle_flags
[ii
]; ++ii
)
3094 if (hi
->flags
& (1 << ii
))
3095 flags
[flen
++] = handle_flags
[ii
];
3097 saxdb_write_string(ctx
, KEY_FLAGS
, flags
);
3099 #ifdef WITH_PROTOCOL_BAHAMUT
3100 saxdb_write_int(ctx
, KEY_ID
, hi
->id
);
3103 saxdb_write_string(ctx
, KEY_INFO
, hi
->infoline
);
3104 if (hi
->last_quit_host
[0])
3105 saxdb_write_string(ctx
, KEY_LAST_QUIT_HOST
, hi
->last_quit_host
);
3106 saxdb_write_int(ctx
, KEY_LAST_SEEN
, hi
->lastseen
);
3107 if (hi
->masks
->used
)
3108 saxdb_write_string_list(ctx
, KEY_MASKS
, hi
->masks
);
3110 saxdb_write_int(ctx
, KEY_MAXLOGINS
, hi
->maxlogins
);
3112 struct string_list
*slist
;
3113 struct nick_info
*ni
;
3115 slist
= alloc_string_list(nickserv_conf
.nicks_per_handle
);
3116 for (ni
= hi
->nicks
; ni
; ni
= ni
->next
) string_list_append(slist
, ni
->nick
);
3117 saxdb_write_string_list(ctx
, KEY_NICKS
, slist
);
3121 if (hi
->opserv_level
)
3122 saxdb_write_int(ctx
, KEY_OPSERV_LEVEL
, hi
->opserv_level
);
3123 if (hi
->language
!= lang_C
)
3124 saxdb_write_string(ctx
, KEY_LANGUAGE
, hi
->language
->name
);
3125 saxdb_write_string(ctx
, KEY_PASSWD
, hi
->passwd
);
3126 saxdb_write_int(ctx
, KEY_REGISTER_ON
, hi
->registered
);
3127 if (hi
->screen_width
)
3128 saxdb_write_int(ctx
, KEY_SCREEN_WIDTH
, hi
->screen_width
);
3129 if (hi
->table_width
)
3130 saxdb_write_int(ctx
, KEY_TABLE_WIDTH
, hi
->table_width
);
3131 flags
[0] = hi
->userlist_style
;
3133 saxdb_write_string(ctx
, KEY_USERLIST_STYLE
, flags
);
3134 saxdb_end_record(ctx
);
3139 static handle_merge_func_t
*handle_merge_func_list
;
3140 static unsigned int handle_merge_func_size
= 0, handle_merge_func_used
= 0;
3143 reg_handle_merge_func(handle_merge_func_t func
)
3145 if (handle_merge_func_used
== handle_merge_func_size
) {
3146 if (handle_merge_func_size
) {
3147 handle_merge_func_size
<<= 1;
3148 handle_merge_func_list
= realloc(handle_merge_func_list
, handle_merge_func_size
*sizeof(handle_merge_func_t
));
3150 handle_merge_func_size
= 8;
3151 handle_merge_func_list
= malloc(handle_merge_func_size
*sizeof(handle_merge_func_t
));
3154 handle_merge_func_list
[handle_merge_func_used
++] = func
;
3157 static NICKSERV_FUNC(cmd_merge
)
3159 struct handle_info
*hi_from
, *hi_to
;
3160 struct userNode
*last_user
;
3161 struct userData
*cList
, *cListNext
;
3162 unsigned int ii
, jj
, n
;
3163 char buffer
[MAXLEN
];
3165 NICKSERV_MIN_PARMS(3);
3167 if (!(hi_from
= get_victim_oper(user
, argv
[1])))
3169 if (!(hi_to
= get_victim_oper(user
, argv
[2])))
3171 if (hi_to
== hi_from
) {
3172 reply("NSMSG_CANNOT_MERGE_SELF", hi_to
->handle
);
3176 for (n
=0; n
<handle_merge_func_used
; n
++)
3177 handle_merge_func_list
[n
](user
, hi_to
, hi_from
);
3179 /* Append "from" handle's nicks to "to" handle's nick list. */
3181 struct nick_info
*last_ni
;
3182 for (last_ni
=hi_to
->nicks
; last_ni
->next
; last_ni
=last_ni
->next
) ;
3183 last_ni
->next
= hi_from
->nicks
;
3185 while (hi_from
->nicks
) {
3186 hi_from
->nicks
->owner
= hi_to
;
3187 hi_from
->nicks
= hi_from
->nicks
->next
;
3190 /* Merge the hostmasks. */
3191 for (ii
=0; ii
<hi_from
->masks
->used
; ii
++) {
3192 char *mask
= hi_from
->masks
->list
[ii
];
3193 for (jj
=0; jj
<hi_to
->masks
->used
; jj
++)
3194 if (match_ircglobs(hi_to
->masks
->list
[jj
], mask
))
3196 if (jj
==hi_to
->masks
->used
) /* Nothing from the "to" handle covered this mask, so add it. */
3197 string_list_append(hi_to
->masks
, strdup(mask
));
3200 /* Merge the lists of authed users. */
3202 for (last_user
=hi_to
->users
; last_user
->next_authed
; last_user
=last_user
->next_authed
) ;
3203 last_user
->next_authed
= hi_from
->users
;
3205 hi_to
->users
= hi_from
->users
;
3207 /* Repoint the old "from" handle's users. */
3208 for (last_user
=hi_from
->users
; last_user
; last_user
=last_user
->next_authed
) {
3209 last_user
->handle_info
= hi_to
;
3211 hi_from
->users
= NULL
;
3213 /* Merge channel userlists. */
3214 for (cList
=hi_from
->channels
; cList
; cList
=cListNext
) {
3215 struct userData
*cList2
;
3216 cListNext
= cList
->u_next
;
3217 for (cList2
=hi_to
->channels
; cList2
; cList2
=cList2
->u_next
)
3218 if (cList
->channel
== cList2
->channel
)
3220 if (cList2
&& (cList2
->access
>= cList
->access
)) {
3221 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
);
3222 /* keep cList2 in hi_to; remove cList from hi_from */
3223 del_channel_user(cList
, 1);
3226 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
);
3227 /* remove the lower-ranking cList2 from hi_to */
3228 del_channel_user(cList2
, 1);
3230 log_module(NS_LOG
, LOG_INFO
, "Merge: %s had no access in %s", hi_to
->handle
, cList
->channel
->channel
->name
);
3232 /* cList needs to be moved from hi_from to hi_to */
3233 cList
->handle
= hi_to
;
3234 /* Remove from linked list for hi_from */
3235 assert(!cList
->u_prev
);
3236 hi_from
->channels
= cList
->u_next
;
3238 cList
->u_next
->u_prev
= cList
->u_prev
;
3239 /* Add to linked list for hi_to */
3240 cList
->u_prev
= NULL
;
3241 cList
->u_next
= hi_to
->channels
;
3242 if (hi_to
->channels
)
3243 hi_to
->channels
->u_prev
= cList
;
3244 hi_to
->channels
= cList
;
3248 /* Do they get an OpServ level promotion? */
3249 if (hi_from
->opserv_level
> hi_to
->opserv_level
)
3250 hi_to
->opserv_level
= hi_from
->opserv_level
;
3252 /* What about last seen time? */
3253 if (hi_from
->lastseen
> hi_to
->lastseen
)
3254 hi_to
->lastseen
= hi_from
->lastseen
;
3256 /* Does a fakehost carry over? (This intentionally doesn't set it
3257 * for users previously attached to hi_to. They'll just have to
3260 if (hi_from
->fakehost
&& !hi_to
->fakehost
)
3261 hi_to
->fakehost
= strdup(hi_from
->fakehost
);
3263 /* Notify of success. */
3264 sprintf(buffer
, "%s (%s) merged account %s into %s.", user
->nick
, user
->handle_info
->handle
, hi_from
->handle
, hi_to
->handle
);
3265 reply("NSMSG_HANDLES_MERGED", hi_from
->handle
, hi_to
->handle
);
3266 global_message(MESSAGE_RECIPIENT_STAFF
, buffer
);
3268 /* Unregister the "from" handle. */
3269 nickserv_unregister_handle(hi_from
, NULL
, cmd
->parent
->bot
);
3274 struct nickserv_discrim
{
3275 unsigned int limit
, min_level
, max_level
;
3276 unsigned long flags_on
, flags_off
;
3277 time_t min_registered
, max_registered
;
3279 enum { SUBSET
, EXACT
, SUPERSET
, LASTQUIT
} hostmask_type
;
3280 const char *nickmask
;
3281 const char *hostmask
;
3282 const char *handlemask
;
3283 const char *emailmask
;
3286 typedef void (*discrim_search_func
)(struct userNode
*source
, struct handle_info
*hi
);
3288 struct discrim_apply_info
{
3289 struct nickserv_discrim
*discrim
;
3290 discrim_search_func func
;
3291 struct userNode
*source
;
3292 unsigned int matched
;
3295 static struct nickserv_discrim
*
3296 nickserv_discrim_create(struct userNode
*user
, unsigned int argc
, char *argv
[])
3299 struct nickserv_discrim
*discrim
;
3301 discrim
= malloc(sizeof(*discrim
));
3302 memset(discrim
, 0, sizeof(*discrim
));
3303 discrim
->min_level
= 0;
3304 discrim
->max_level
= ~0;
3305 discrim
->limit
= 50;
3306 discrim
->min_registered
= 0;
3307 discrim
->max_registered
= INT_MAX
;
3308 discrim
->lastseen
= now
;
3310 for (i
=0; i
<argc
; i
++) {
3311 if (i
== argc
- 1) {
3312 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3315 if (!irccasecmp(argv
[i
], "limit")) {
3316 discrim
->limit
= strtoul(argv
[++i
], NULL
, 0);
3317 } else if (!irccasecmp(argv
[i
], "flags")) {
3318 nickserv_modify_handle_flags(user
, nickserv
, argv
[++i
], &discrim
->flags_on
, &discrim
->flags_off
);
3319 } else if (!irccasecmp(argv
[i
], "registered")) {
3320 const char *cmp
= argv
[++i
];
3321 if (cmp
[0] == '<') {
3322 if (cmp
[1] == '=') {
3323 discrim
->min_registered
= now
- ParseInterval(cmp
+2);
3325 discrim
->min_registered
= now
- ParseInterval(cmp
+1) + 1;
3327 } else if (cmp
[0] == '=') {
3328 discrim
->min_registered
= discrim
->max_registered
= now
- ParseInterval(cmp
+1);
3329 } else if (cmp
[0] == '>') {
3330 if (cmp
[1] == '=') {
3331 discrim
->max_registered
= now
- ParseInterval(cmp
+2);
3333 discrim
->max_registered
= now
- ParseInterval(cmp
+1) - 1;
3336 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3338 } else if (!irccasecmp(argv
[i
], "seen")) {
3339 discrim
->lastseen
= now
- ParseInterval(argv
[++i
]);
3340 } else if (!nickserv_conf
.disable_nicks
&& !irccasecmp(argv
[i
], "nickmask")) {
3341 discrim
->nickmask
= argv
[++i
];
3342 } else if (!irccasecmp(argv
[i
], "hostmask")) {
3344 if (!irccasecmp(argv
[i
], "exact")) {
3345 if (i
== argc
- 1) {
3346 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3349 discrim
->hostmask_type
= EXACT
;
3350 } else if (!irccasecmp(argv
[i
], "subset")) {
3351 if (i
== argc
- 1) {
3352 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3355 discrim
->hostmask_type
= SUBSET
;
3356 } else if (!irccasecmp(argv
[i
], "superset")) {
3357 if (i
== argc
- 1) {
3358 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3361 discrim
->hostmask_type
= SUPERSET
;
3362 } else if (!irccasecmp(argv
[i
], "lastquit") || !irccasecmp(argv
[i
], "lastauth")) {
3363 if (i
== argc
- 1) {
3364 send_message(user
, nickserv
, "MSG_MISSING_PARAMS", argv
[i
]);
3367 discrim
->hostmask_type
= LASTQUIT
;
3370 discrim
->hostmask_type
= SUPERSET
;
3372 discrim
->hostmask
= argv
[++i
];
3373 } else if (!irccasecmp(argv
[i
], "handlemask") || !irccasecmp(argv
[i
], "accountmask")) {
3374 if (!irccasecmp(argv
[++i
], "*")) {
3375 discrim
->handlemask
= 0;
3377 discrim
->handlemask
= argv
[i
];
3379 } else if (!irccasecmp(argv
[i
], "email")) {
3380 if (user
->handle_info
->opserv_level
< nickserv_conf
.email_search_level
) {
3381 send_message(user
, nickserv
, "MSG_NO_SEARCH_ACCESS", "email");
3383 } else if (!irccasecmp(argv
[++i
], "*")) {
3384 discrim
->emailmask
= 0;
3386 discrim
->emailmask
= argv
[i
];
3388 } else if (!irccasecmp(argv
[i
], "access")) {
3389 const char *cmp
= argv
[++i
];
3390 if (cmp
[0] == '<') {
3391 if (discrim
->min_level
== 0) discrim
->min_level
= 1;
3392 if (cmp
[1] == '=') {
3393 discrim
->max_level
= strtoul(cmp
+2, NULL
, 0);
3395 discrim
->max_level
= strtoul(cmp
+1, NULL
, 0) - 1;
3397 } else if (cmp
[0] == '=') {
3398 discrim
->min_level
= discrim
->max_level
= strtoul(cmp
+1, NULL
, 0);
3399 } else if (cmp
[0] == '>') {
3400 if (cmp
[1] == '=') {
3401 discrim
->min_level
= strtoul(cmp
+2, NULL
, 0);
3403 discrim
->min_level
= strtoul(cmp
+1, NULL
, 0) + 1;
3406 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", cmp
);
3409 send_message(user
, nickserv
, "MSG_INVALID_CRITERIA", argv
[i
]);
3420 nickserv_discrim_match(struct nickserv_discrim
*discrim
, struct handle_info
*hi
)
3422 if (((discrim
->flags_on
& hi
->flags
) != discrim
->flags_on
)
3423 || (discrim
->flags_off
& hi
->flags
)
3424 || (discrim
->min_registered
> hi
->registered
)
3425 || (discrim
->max_registered
< hi
->registered
)
3426 || (discrim
->lastseen
< (hi
->users
?now
:hi
->lastseen
))
3427 || (discrim
->handlemask
&& !match_ircglob(hi
->handle
, discrim
->handlemask
))
3428 || (discrim
->emailmask
&& (!hi
->email_addr
|| !match_ircglob(hi
->email_addr
, discrim
->emailmask
)))
3429 || (discrim
->min_level
> hi
->opserv_level
)
3430 || (discrim
->max_level
< hi
->opserv_level
)) {
3433 if (discrim
->hostmask
) {
3435 for (i
=0; i
<hi
->masks
->used
; i
++) {
3436 const char *mask
= hi
->masks
->list
[i
];
3437 if ((discrim
->hostmask_type
== SUBSET
)
3438 && (match_ircglobs(discrim
->hostmask
, mask
))) break;
3439 else if ((discrim
->hostmask_type
== EXACT
)
3440 && !irccasecmp(discrim
->hostmask
, mask
)) break;
3441 else if ((discrim
->hostmask_type
== SUPERSET
)
3442 && (match_ircglobs(mask
, discrim
->hostmask
))) break;
3443 else if ((discrim
->hostmask_type
== LASTQUIT
)
3444 && (match_ircglobs(discrim
->hostmask
, hi
->last_quit_host
))) break;
3446 if (i
==hi
->masks
->used
) return 0;
3448 if (discrim
->nickmask
) {
3449 struct nick_info
*nick
= hi
->nicks
;
3451 if (match_ircglob(nick
->nick
, discrim
->nickmask
)) break;
3454 if (!nick
) return 0;
3460 nickserv_discrim_search(struct nickserv_discrim
*discrim
, discrim_search_func dsf
, struct userNode
*source
)
3462 dict_iterator_t it
, next
;
3463 unsigned int matched
;
3465 for (it
= dict_first(nickserv_handle_dict
), matched
= 0;
3466 it
&& (matched
< discrim
->limit
);
3468 next
= iter_next(it
);
3469 if (nickserv_discrim_match(discrim
, iter_data(it
))) {
3470 dsf(source
, iter_data(it
));
3478 search_print_func(struct userNode
*source
, struct handle_info
*match
)
3480 send_message(source
, nickserv
, "NSMSG_SEARCH_MATCH", match
->handle
);
3484 search_count_func(UNUSED_ARG(struct userNode
*source
), UNUSED_ARG(struct handle_info
*match
))
3489 search_unregister_func (struct userNode
*source
, struct handle_info
*match
)
3491 if (oper_has_access(source
, nickserv
, match
->opserv_level
, 0))
3492 nickserv_unregister_handle(match
, source
, nickserv
); // XXX nickserv hard coded
3496 nickserv_sort_accounts_by_access(const void *a
, const void *b
)
3498 const struct handle_info
*hi_a
= *(const struct handle_info
**)a
;
3499 const struct handle_info
*hi_b
= *(const struct handle_info
**)b
;
3500 if (hi_a
->opserv_level
!= hi_b
->opserv_level
)
3501 return hi_b
->opserv_level
- hi_a
->opserv_level
;
3502 return irccasecmp(hi_a
->handle
, hi_b
->handle
);
3506 nickserv_show_oper_accounts(struct userNode
*user
, struct svccmd
*cmd
)
3508 struct handle_info_list hil
;
3509 struct helpfile_table tbl
;
3514 memset(&hil
, 0, sizeof(hil
));
3515 for (it
= dict_first(nickserv_handle_dict
); it
; it
= iter_next(it
)) {
3516 struct handle_info
*hi
= iter_data(it
);
3517 if (hi
->opserv_level
)
3518 handle_info_list_append(&hil
, hi
);
3520 qsort(hil
.list
, hil
.used
, sizeof(hil
.list
[0]), nickserv_sort_accounts_by_access
);
3521 tbl
.length
= hil
.used
+ 1;
3523 tbl
.flags
= TABLE_NO_FREE
;
3524 tbl
.contents
= malloc(tbl
.length
* sizeof(tbl
.contents
[0]));
3525 tbl
.contents
[0] = ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3528 for (ii
= 0; ii
< hil
.used
; ) {
3529 ary
= malloc(tbl
.width
* sizeof(ary
[0]));
3530 ary
[0] = hil
.list
[ii
]->handle
;
3531 ary
[1] = strtab(hil
.list
[ii
]->opserv_level
);
3532 tbl
.contents
[++ii
] = ary
;
3534 table_send(cmd
->parent
->bot
, user
->nick
, 0, NULL
, tbl
);
3535 reply("MSG_MATCH_COUNT", hil
.used
);
3536 for (ii
= 0; ii
< hil
.used
; ii
++)
3537 free(tbl
.contents
[ii
]);
3542 static NICKSERV_FUNC(cmd_search
)
3544 struct nickserv_discrim
*discrim
;
3545 discrim_search_func action
;
3546 struct svccmd
*subcmd
;
3547 unsigned int matches
;
3550 NICKSERV_MIN_PARMS(3);
3551 sprintf(buf
, "search %s", argv
[1]);
3552 subcmd
= dict_find(nickserv_service
->commands
, buf
, NULL
);
3553 if (!irccasecmp(argv
[1], "print"))
3554 action
= search_print_func
;
3555 else if (!irccasecmp(argv
[1], "count"))
3556 action
= search_count_func
;
3557 else if (!irccasecmp(argv
[1], "unregister"))
3558 action
= search_unregister_func
;
3560 reply("NSMSG_INVALID_ACTION", argv
[1]);
3564 if (subcmd
&& !svccmd_can_invoke(user
, nickserv
, subcmd
, NULL
, SVCCMD_NOISY
))
3567 discrim
= nickserv_discrim_create(user
, argc
-2, argv
+2);
3571 if (action
== search_print_func
)
3572 reply("NSMSG_ACCOUNT_SEARCH_RESULTS");
3573 else if (action
== search_count_func
)
3574 discrim
->limit
= INT_MAX
;
3576 matches
= nickserv_discrim_search(discrim
, action
, user
);
3579 reply("MSG_MATCH_COUNT", matches
);
3581 reply("MSG_NO_MATCHES");
3587 static MODCMD_FUNC(cmd_checkpass
)
3589 struct handle_info
*hi
;
3591 NICKSERV_MIN_PARMS(3);
3592 if (!(hi
= get_handle_info(argv
[1]))) {
3593 reply("MSG_HANDLE_UNKNOWN", argv
[1]);
3596 if (checkpass(argv
[2], hi
->passwd
))
3597 reply("CHECKPASS_YES");
3599 reply("CHECKPASS_NO");
3605 nickserv_db_read_handle(const char *handle
, dict_t obj
)
3608 struct string_list
*masks
, *slist
;
3609 struct handle_info
*hi
;
3610 struct userNode
*authed_users
;
3611 struct userData
*channels
;
3612 unsigned long int id
;
3615 char *setter
, *note
;
3618 str
= database_get_data(obj
, KEY_ID
, RECDB_QSTRING
);
3619 id
= str
? strtoul(str
, NULL
, 0) : 0;
3620 str
= database_get_data(obj
, KEY_PASSWD
, RECDB_QSTRING
);
3622 log_module(NS_LOG
, LOG_WARNING
, "did not find a password for %s -- skipping user.", handle
);
3625 if ((hi
= get_handle_info(handle
))) {
3626 authed_users
= hi
->users
;
3627 channels
= hi
->channels
;
3629 hi
->channels
= NULL
;
3630 dict_remove(nickserv_handle_dict
, hi
->handle
);
3632 authed_users
= NULL
;
3635 hi
= register_handle(handle
, str
, id
);
3637 hi
->users
= authed_users
;
3638 while (authed_users
) {
3639 authed_users
->handle_info
= hi
;
3640 authed_users
= authed_users
->next_authed
;
3643 hi
->channels
= channels
;
3644 masks
= database_get_data(obj
, KEY_MASKS
, RECDB_STRING_LIST
);
3645 hi
->masks
= masks
? string_list_copy(masks
) : alloc_string_list(1);
3646 str
= database_get_data(obj
, KEY_MAXLOGINS
, RECDB_QSTRING
);
3647 hi
->maxlogins
= str
? strtoul(str
, NULL
, 0) : 0;
3648 str
= database_get_data(obj
, KEY_LANGUAGE
, RECDB_QSTRING
);
3649 hi
->language
= language_find(str
? str
: "C");
3650 str
= database_get_data(obj
, KEY_OPSERV_LEVEL
, RECDB_QSTRING
);
3651 hi
->opserv_level
= str
? strtoul(str
, NULL
, 0) : 0;
3652 str
= database_get_data(obj
, KEY_INFO
, RECDB_QSTRING
);
3654 hi
->infoline
= strdup(str
);
3655 str
= database_get_data(obj
, KEY_REGISTER_ON
, RECDB_QSTRING
);
3656 hi
->registered
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3657 str
= database_get_data(obj
, KEY_LAST_SEEN
, RECDB_QSTRING
);
3658 hi
->lastseen
= str
? (time_t)strtoul(str
, NULL
, 0) : hi
->registered
;
3659 /* We want to read the nicks even if disable_nicks is set. This is so
3660 * that we don't lose the nick data entirely. */
3661 slist
= database_get_data(obj
, KEY_NICKS
, RECDB_STRING_LIST
);
3663 for (ii
=0; ii
<slist
->used
; ii
++)
3664 register_nick(slist
->list
[ii
], hi
);
3666 str
= database_get_data(obj
, KEY_FLAGS
, RECDB_QSTRING
);
3668 for (ii
=0; str
[ii
]; ii
++)
3669 hi
->flags
|= 1 << (handle_inverse_flags
[(unsigned char)str
[ii
]] - 1);
3671 str
= database_get_data(obj
, KEY_USERLIST_STYLE
, RECDB_QSTRING
);
3672 hi
->userlist_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
3673 str
= database_get_data(obj
, KEY_ANNOUNCEMENTS
, RECDB_QSTRING
);
3674 hi
->announcements
= str
? str
[0] : '?';
3675 str
= database_get_data(obj
, KEY_SCREEN_WIDTH
, RECDB_QSTRING
);
3676 hi
->screen_width
= str
? strtoul(str
, NULL
, 0) : 0;
3677 str
= database_get_data(obj
, KEY_TABLE_WIDTH
, RECDB_QSTRING
);
3678 hi
->table_width
= str
? strtoul(str
, NULL
, 0) : 0;
3679 str
= database_get_data(obj
, KEY_LAST_QUIT_HOST
, RECDB_QSTRING
);
3681 str
= database_get_data(obj
, KEY_LAST_AUTHED_HOST
, RECDB_QSTRING
);
3683 safestrncpy(hi
->last_quit_host
, str
, sizeof(hi
->last_quit_host
));
3684 str
= database_get_data(obj
, KEY_EMAIL_ADDR
, RECDB_QSTRING
);
3686 nickserv_set_email_addr(hi
, str
);
3687 str
= database_get_data(obj
, KEY_EPITHET
, RECDB_QSTRING
);
3689 hi
->epithet
= strdup(str
);
3690 subdb
= database_get_data(obj
, KEY_NOTE_NOTE
, RECDB_OBJECT
);
3692 setter
= database_get_data(subdb
, KEY_NOTE_SETTER
, RECDB_QSTRING
);
3693 str
= database_get_data(subdb
, KEY_NOTE_DATE
, RECDB_QSTRING
);
3694 date
= str
? (time_t)strtoul(str
, NULL
, 0) : now
;
3695 note
= database_get_data(subdb
, KEY_NOTE_NOTE
, RECDB_QSTRING
);
3696 if (setter
&& date
&& note
)
3698 if (!(hi
->note
= nickserv_add_note(setter
, date
, note
)))
3703 str
= database_get_data(obj
, KEY_FAKEHOST
, RECDB_QSTRING
);
3705 hi
->fakehost
= strdup(str
);
3706 subdb
= database_get_data(obj
, KEY_COOKIE
, RECDB_OBJECT
);
3708 const char *data
, *type
, *expires
, *cookie_str
;
3709 struct handle_cookie
*cookie
;
3711 cookie
= calloc(1, sizeof(*cookie
));
3712 type
= database_get_data(subdb
, KEY_COOKIE_TYPE
, RECDB_QSTRING
);
3713 data
= database_get_data(subdb
, KEY_COOKIE_DATA
, RECDB_QSTRING
);
3714 expires
= database_get_data(subdb
, KEY_COOKIE_EXPIRES
, RECDB_QSTRING
);
3715 cookie_str
= database_get_data(subdb
, KEY_COOKIE
, RECDB_QSTRING
);
3716 if (!type
|| !expires
|| !cookie_str
) {
3717 log_module(NS_LOG
, LOG_ERROR
, "Missing field(s) from cookie for account %s; dropping cookie.", hi
->handle
);
3720 if (!irccasecmp(type
, KEY_ACTIVATION
))
3721 cookie
->type
= ACTIVATION
;
3722 else if (!irccasecmp(type
, KEY_PASSWORD_CHANGE
))
3723 cookie
->type
= PASSWORD_CHANGE
;
3724 else if (!irccasecmp(type
, KEY_EMAIL_CHANGE
))
3725 cookie
->type
= EMAIL_CHANGE
;
3726 else if (!irccasecmp(type
, KEY_ALLOWAUTH
))
3727 cookie
->type
= ALLOWAUTH
;
3729 log_module(NS_LOG
, LOG_ERROR
, "Invalid cookie type %s for account %s; dropping cookie.", type
, handle
);
3732 cookie
->expires
= strtoul(expires
, NULL
, 0);
3733 if (cookie
->expires
< now
)
3736 cookie
->data
= strdup(data
);
3737 safestrncpy(cookie
->cookie
, cookie_str
, sizeof(cookie
->cookie
));
3741 nickserv_bake_cookie(cookie
);
3743 nickserv_free_cookie(cookie
);
3748 nickserv_saxdb_read(dict_t db
) {
3750 struct record_data
*rd
;
3752 for (it
=dict_first(db
); it
; it
=iter_next(it
)) {
3754 nickserv_db_read_handle(iter_key(it
), rd
->d
.object
);
3759 static NICKSERV_FUNC(cmd_mergedb
)
3761 struct timeval start
, stop
;
3764 NICKSERV_MIN_PARMS(2);
3765 gettimeofday(&start
, NULL
);
3766 if (!(db
= parse_database(argv
[1]))) {
3767 reply("NSMSG_DB_UNREADABLE", argv
[1]);
3770 nickserv_saxdb_read(db
);
3772 gettimeofday(&stop
, NULL
);
3773 stop
.tv_sec
-= start
.tv_sec
;
3774 stop
.tv_usec
-= start
.tv_usec
;
3775 if (stop
.tv_usec
< 0) {
3777 stop
.tv_usec
+= 1000000;
3779 reply("NSMSG_DB_MERGED", argv
[1], stop
.tv_sec
, stop
.tv_usec
/1000);
3784 expire_handles(UNUSED_ARG(void *data
))
3786 dict_iterator_t it
, next
;
3788 struct handle_info
*hi
;
3790 for (it
=dict_first(nickserv_handle_dict
); it
; it
=next
) {
3791 next
= iter_next(it
);
3793 if ((hi
->opserv_level
> 0)
3795 || HANDLE_FLAGGED(hi
, FROZEN
)
3796 || HANDLE_FLAGGED(hi
, NODELETE
)) {
3799 expiry
= hi
->channels
? nickserv_conf
.handle_expire_delay
: nickserv_conf
.nochan_handle_expire_delay
;
3800 if ((now
- hi
->lastseen
) > expiry
) {
3801 log_module(NS_LOG
, LOG_INFO
, "Expiring account %s for inactivity.", hi
->handle
);
3802 nickserv_unregister_handle(hi
, NULL
, NULL
);
3806 if (nickserv_conf
.handle_expire_frequency
)
3807 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
3811 nickserv_load_dict(const char *fname
)
3815 if (!(file
= fopen(fname
, "r"))) {
3816 log_module(NS_LOG
, LOG_ERROR
, "Unable to open dictionary file %s: %s", fname
, strerror(errno
));
3819 while (!feof(file
)) {
3820 fgets(line
, sizeof(line
), file
);
3823 if (line
[strlen(line
)-1] == '\n')
3824 line
[strlen(line
)-1] = 0;
3825 dict_insert(nickserv_conf
.weak_password_dict
, strdup(line
), NULL
);
3828 log_module(NS_LOG
, LOG_INFO
, "Loaded %d words into weak password dictionary.", dict_size(nickserv_conf
.weak_password_dict
));
3831 static enum reclaim_action
3832 reclaim_action_from_string(const char *str
) {
3834 return RECLAIM_NONE
;
3835 else if (!irccasecmp(str
, "warn"))
3836 return RECLAIM_WARN
;
3837 else if (!irccasecmp(str
, "svsnick"))
3838 return RECLAIM_SVSNICK
;
3839 else if (!irccasecmp(str
, "kill"))
3840 return RECLAIM_KILL
;
3842 return RECLAIM_NONE
;
3846 nickserv_conf_read(void)
3848 dict_t conf_node
, child
;
3852 if (!(conf_node
= conf_get_data(NICKSERV_CONF_NAME
, RECDB_OBJECT
))) {
3853 log_module(NS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME
);
3856 str
= database_get_data(conf_node
, KEY_VALID_HANDLE_REGEX
, RECDB_QSTRING
);
3858 str
= database_get_data(conf_node
, KEY_VALID_ACCOUNT_REGEX
, RECDB_QSTRING
);
3859 if (nickserv_conf
.valid_handle_regex_set
)
3860 regfree(&nickserv_conf
.valid_handle_regex
);
3862 int err
= regcomp(&nickserv_conf
.valid_handle_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3863 nickserv_conf
.valid_handle_regex_set
= !err
;
3864 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_account_regex (error %d)", err
);
3866 nickserv_conf
.valid_handle_regex_set
= 0;
3868 str
= database_get_data(conf_node
, KEY_VALID_NICK_REGEX
, RECDB_QSTRING
);
3869 if (nickserv_conf
.valid_nick_regex_set
)
3870 regfree(&nickserv_conf
.valid_nick_regex
);
3872 int err
= regcomp(&nickserv_conf
.valid_nick_regex
, str
, REG_EXTENDED
|REG_ICASE
|REG_NOSUB
);
3873 nickserv_conf
.valid_nick_regex_set
= !err
;
3874 if (err
) log_module(NS_LOG
, LOG_ERROR
, "Bad valid_nick_regex (error %d)", err
);
3876 nickserv_conf
.valid_nick_regex_set
= 0;
3878 str
= database_get_data(conf_node
, KEY_NICKS_PER_HANDLE
, RECDB_QSTRING
);
3880 str
= database_get_data(conf_node
, KEY_NICKS_PER_ACCOUNT
, RECDB_QSTRING
);
3881 nickserv_conf
.nicks_per_handle
= str
? strtoul(str
, NULL
, 0) : 4;
3882 str
= database_get_data(conf_node
, KEY_DISABLE_NICKS
, RECDB_QSTRING
);
3883 nickserv_conf
.disable_nicks
= str
? strtoul(str
, NULL
, 0) : 0;
3884 str
= database_get_data(conf_node
, KEY_DEFAULT_HOSTMASK
, RECDB_QSTRING
);
3885 nickserv_conf
.default_hostmask
= str
? !disabled_string(str
) : 0;
3886 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LENGTH
, RECDB_QSTRING
);
3887 nickserv_conf
.password_min_length
= str
? strtoul(str
, NULL
, 0) : 0;
3888 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_DIGITS
, RECDB_QSTRING
);
3889 nickserv_conf
.password_min_digits
= str
? strtoul(str
, NULL
, 0) : 0;
3890 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_UPPER
, RECDB_QSTRING
);
3891 nickserv_conf
.password_min_upper
= str
? strtoul(str
, NULL
, 0) : 0;
3892 str
= database_get_data(conf_node
, KEY_PASSWORD_MIN_LOWER
, RECDB_QSTRING
);
3893 nickserv_conf
.password_min_lower
= str
? strtoul(str
, NULL
, 0) : 0;
3894 str
= database_get_data(conf_node
, KEY_DB_BACKUP_FREQ
, RECDB_QSTRING
);
3895 nickserv_conf
.db_backup_frequency
= str
? ParseInterval(str
) : 7200;
3896 str
= database_get_data(conf_node
, KEY_MODOPER_LEVEL
, RECDB_QSTRING
);
3897 nickserv_conf
.modoper_level
= str
? strtoul(str
, NULL
, 0) : 900;
3898 str
= database_get_data(conf_node
, KEY_SET_EPITHET_LEVEL
, RECDB_QSTRING
);
3899 nickserv_conf
.set_epithet_level
= str
? strtoul(str
, NULL
, 0) : 1;
3900 str
= database_get_data(conf_node
, KEY_SET_TITLE_LEVEL
, RECDB_QSTRING
);
3901 nickserv_conf
.set_title_level
= str
? strtoul(str
, NULL
, 0) : 900;
3902 str
= database_get_data(conf_node
, KEY_SET_FAKEHOST_LEVEL
, RECDB_QSTRING
);
3903 nickserv_conf
.set_fakehost_level
= str
? strtoul(str
, NULL
, 0) : 1000;
3904 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_FREQ
, RECDB_QSTRING
);
3906 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_FREQ
, RECDB_QSTRING
);
3907 nickserv_conf
.handle_expire_frequency
= str
? ParseInterval(str
) : 86400;
3908 str
= database_get_data(conf_node
, KEY_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3910 str
= database_get_data(conf_node
, KEY_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3911 nickserv_conf
.handle_expire_delay
= str
? ParseInterval(str
) : 86400*30;
3912 str
= database_get_data(conf_node
, KEY_NOCHAN_HANDLE_EXPIRE_DELAY
, RECDB_QSTRING
);
3914 str
= database_get_data(conf_node
, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY
, RECDB_QSTRING
);
3915 nickserv_conf
.nochan_handle_expire_delay
= str
? ParseInterval(str
) : 86400*15;
3916 str
= database_get_data(conf_node
, "warn_clone_auth", RECDB_QSTRING
);
3917 nickserv_conf
.warn_clone_auth
= str
? !disabled_string(str
) : 1;
3918 str
= database_get_data(conf_node
, "default_maxlogins", RECDB_QSTRING
);
3919 nickserv_conf
.default_maxlogins
= str
? strtoul(str
, NULL
, 0) : 2;
3920 str
= database_get_data(conf_node
, "hard_maxlogins", RECDB_QSTRING
);
3921 nickserv_conf
.hard_maxlogins
= str
? strtoul(str
, NULL
, 0) : 10;
3922 if (!nickserv_conf
.disable_nicks
) {
3923 str
= database_get_data(conf_node
, "reclaim_action", RECDB_QSTRING
);
3924 nickserv_conf
.reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3925 str
= database_get_data(conf_node
, "warn_nick_owned", RECDB_QSTRING
);
3926 nickserv_conf
.warn_nick_owned
= str
? enabled_string(str
) : 0;
3927 str
= database_get_data(conf_node
, "auto_reclaim_action", RECDB_QSTRING
);
3928 nickserv_conf
.auto_reclaim_action
= str
? reclaim_action_from_string(str
) : RECLAIM_NONE
;
3929 str
= database_get_data(conf_node
, "auto_reclaim_delay", RECDB_QSTRING
);
3930 nickserv_conf
.auto_reclaim_delay
= str
? ParseInterval(str
) : 0;
3932 child
= database_get_data(conf_node
, KEY_FLAG_LEVELS
, RECDB_OBJECT
);
3933 for (it
=dict_first(child
); it
; it
=iter_next(it
)) {
3934 const char *key
= iter_key(it
), *value
;
3938 if (!strncasecmp(key
, "uc_", 3))
3939 flag
= toupper(key
[3]);
3940 else if (!strncasecmp(key
, "lc_", 3))
3941 flag
= tolower(key
[3]);
3945 if ((pos
= handle_inverse_flags
[flag
])) {
3946 value
= GET_RECORD_QSTRING((struct record_data
*)iter_data(it
));
3947 flag_access_levels
[pos
- 1] = strtoul(value
, NULL
, 0);
3950 if (nickserv_conf
.weak_password_dict
)
3951 dict_delete(nickserv_conf
.weak_password_dict
);
3952 nickserv_conf
.weak_password_dict
= dict_new();
3953 dict_set_free_keys(nickserv_conf
.weak_password_dict
, free
);
3954 dict_insert(nickserv_conf
.weak_password_dict
, strdup("password"), NULL
);
3955 dict_insert(nickserv_conf
.weak_password_dict
, strdup("<password>"), NULL
);
3956 str
= database_get_data(conf_node
, KEY_DICT_FILE
, RECDB_QSTRING
);
3958 nickserv_load_dict(str
);
3959 str
= database_get_data(conf_node
, KEY_NICK
, RECDB_QSTRING
);
3960 if (nickserv
&& str
)
3961 NickChange(nickserv
, str
, 0);
3962 str
= database_get_data(conf_node
, KEY_AUTOGAG_ENABLED
, RECDB_QSTRING
);
3963 nickserv_conf
.autogag_enabled
= str
? strtoul(str
, NULL
, 0) : 1;
3964 str
= database_get_data(conf_node
, KEY_AUTOGAG_DURATION
, RECDB_QSTRING
);
3965 nickserv_conf
.autogag_duration
= str
? ParseInterval(str
) : 1800;
3966 str
= database_get_data(conf_node
, KEY_EMAIL_VISIBLE_LEVEL
, RECDB_QSTRING
);
3967 nickserv_conf
.email_visible_level
= str
? strtoul(str
, NULL
, 0) : 800;
3968 str
= database_get_data(conf_node
, KEY_EMAIL_ENABLED
, RECDB_QSTRING
);
3969 nickserv_conf
.email_enabled
= str
? enabled_string(str
) : 0;
3970 str
= database_get_data(conf_node
, KEY_SYNC_LOG
, RECDB_QSTRING
);
3971 nickserv_conf
.sync_log
= str
? enabled_string(str
) : 0;
3972 str
= database_get_data(conf_node
, KEY_COOKIE_TIMEOUT
, RECDB_QSTRING
);
3973 nickserv_conf
.cookie_timeout
= str
? ParseInterval(str
) : 24*3600;
3974 str
= database_get_data(conf_node
, KEY_EMAIL_REQUIRED
, RECDB_QSTRING
);
3975 nickserv_conf
.email_required
= (nickserv_conf
.email_enabled
&& str
) ? enabled_string(str
) : 0;
3976 str
= database_get_data(conf_node
, KEY_ACCOUNTS_PER_EMAIL
, RECDB_QSTRING
);
3977 nickserv_conf
.handles_per_email
= str
? strtoul(str
, NULL
, 0) : 1;
3978 str
= database_get_data(conf_node
, KEY_EMAIL_SEARCH_LEVEL
, RECDB_QSTRING
);
3979 nickserv_conf
.email_search_level
= str
? strtoul(str
, NULL
, 0) : 600;
3980 str
= database_get_data(conf_node
, KEY_TITLEHOST_SUFFIX
, RECDB_QSTRING
);
3981 nickserv_conf
.titlehost_suffix
= str
? str
: "example.net";
3983 str
= database_get_data(conf_node
, KEY_DEFAULT_STYLE
, RECDB_QSTRING
);
3984 nickserv_conf
.default_style
= str
? str
[0] : HI_DEFAULT_STYLE
;
3986 str
= database_get_data(conf_node
, KEY_AUTO_OPER
, RECDB_QSTRING
);
3987 nickserv_conf
.auto_oper
= str
? str
: "";
3989 str
= database_get_data(conf_node
, KEY_AUTO_ADMIN
, RECDB_QSTRING
);
3990 nickserv_conf
.auto_admin
= str
? str
: "";
3992 str
= conf_get_data("server/network", RECDB_QSTRING
);
3993 nickserv_conf
.network_name
= str
? str
: "some IRC network";
3994 if (!nickserv_conf
.auth_policer_params
) {
3995 nickserv_conf
.auth_policer_params
= policer_params_new();
3996 policer_params_set(nickserv_conf
.auth_policer_params
, "size", "5");
3997 policer_params_set(nickserv_conf
.auth_policer_params
, "drain-rate", "0.05");
3999 child
= database_get_data(conf_node
, KEY_AUTH_POLICER
, RECDB_OBJECT
);
4000 for (it
=dict_first(child
); it
; it
=iter_next(it
))
4001 set_policer_param(iter_key(it
), iter_data(it
), nickserv_conf
.auth_policer_params
);
4005 nickserv_reclaim(struct userNode
*user
, struct nick_info
*ni
, enum reclaim_action action
) {
4007 char newnick
[NICKLEN
+1];
4016 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4018 case RECLAIM_SVSNICK
:
4020 snprintf(newnick
, sizeof(newnick
), "Guest%d", rand()%10000
);
4021 } while (GetUserH(newnick
));
4022 irc_svsnick(nickserv
, user
, newnick
);
4025 msg
= user_find_message(user
, "NSMSG_RECLAIM_KILL");
4026 irc_kill(nickserv
, user
, msg
);
4032 nickserv_reclaim_p(void *data
) {
4033 struct userNode
*user
= data
;
4034 struct nick_info
*ni
= get_nick_info(user
->nick
);
4036 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4040 check_user_nick(struct userNode
*user
) {
4041 struct nick_info
*ni
;
4042 user
->modes
&= ~FLAGS_REGNICK
;
4043 if (!(ni
= get_nick_info(user
->nick
)))
4045 if (user
->handle_info
== ni
->owner
) {
4046 user
->modes
|= FLAGS_REGNICK
;
4050 if (nickserv_conf
.warn_nick_owned
)
4051 send_message(user
, nickserv
, "NSMSG_RECLAIM_WARN", ni
->nick
, ni
->owner
->handle
);
4052 if (nickserv_conf
.auto_reclaim_action
== RECLAIM_NONE
)
4054 if (nickserv_conf
.auto_reclaim_delay
)
4055 timeq_add(now
+ nickserv_conf
.auto_reclaim_delay
, nickserv_reclaim_p
, user
);
4057 nickserv_reclaim(user
, ni
, nickserv_conf
.auto_reclaim_action
);
4062 handle_new_user(struct userNode
*user
)
4064 return check_user_nick(user
);
4068 handle_account(struct userNode
*user
, const char *stamp
)
4070 struct handle_info
*hi
;
4073 #ifdef WITH_PROTOCOL_P10
4074 time_t timestamp
= 0;
4076 colon
= strchr(stamp
, ':');
4077 if(colon
&& colon
[1])
4080 timestamp
= atoi(colon
+1);
4082 hi
= dict_find(nickserv_handle_dict
, stamp
, NULL
);
4083 if(hi
&& timestamp
&& hi
->registered
!= timestamp
)
4085 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
);
4089 hi
= dict_find(nickserv_id_dict
, stamp
, NULL
);
4090 log_module(MAIN_LOG
, LOG_WARNING
, "Using non-P10 code in accounts, not tested at all!");
4094 if (HANDLE_FLAGGED(hi
, SUSPENDED
)) {
4097 set_user_handle_info(user
, hi
, 0);
4099 log_module(MAIN_LOG
, LOG_WARNING
, "%s had unknown account stamp %s.", user
->nick
, stamp
);
4104 handle_nick_change(struct userNode
*user
, const char *old_nick
)
4106 struct handle_info
*hi
;
4108 if ((hi
= dict_find(nickserv_allow_auth_dict
, old_nick
, 0))) {
4109 dict_remove(nickserv_allow_auth_dict
, old_nick
);
4110 dict_insert(nickserv_allow_auth_dict
, user
->nick
, hi
);
4112 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4113 check_user_nick(user
);
4117 nickserv_remove_user(struct userNode
*user
, UNUSED_ARG(struct userNode
*killer
), UNUSED_ARG(const char *why
))
4119 dict_remove(nickserv_allow_auth_dict
, user
->nick
);
4120 timeq_del(0, nickserv_reclaim_p
, user
, TIMEQ_IGNORE_WHEN
);
4121 set_user_handle_info(user
, NULL
, 0);
4124 static struct modcmd
*
4125 nickserv_define_func(const char *name
, modcmd_func_t func
, int min_level
, int must_auth
, int must_be_qualified
)
4127 if (min_level
> 0) {
4129 sprintf(buf
, "%u", min_level
);
4130 if (must_be_qualified
) {
4131 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, "flags", "+qualified,+loghostmask", NULL
);
4133 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "level", buf
, NULL
);
4135 } else if (min_level
== 0) {
4136 if (must_be_qualified
) {
4137 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4139 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+helping", NULL
);
4142 if (must_be_qualified
) {
4143 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), "flags", "+qualified,+loghostmask", NULL
);
4145 return modcmd_register(nickserv_module
, name
, func
, 1, (must_auth
? MODCMD_REQUIRE_AUTHED
: 0), NULL
);
4151 nickserv_db_cleanup(void)
4153 unreg_del_user_func(nickserv_remove_user
);
4154 userList_clean(&curr_helpers
);
4155 policer_params_delete(nickserv_conf
.auth_policer_params
);
4156 dict_delete(nickserv_handle_dict
);
4157 dict_delete(nickserv_nick_dict
);
4158 dict_delete(nickserv_opt_dict
);
4159 dict_delete(nickserv_allow_auth_dict
);
4160 dict_delete(nickserv_email_dict
);
4161 dict_delete(nickserv_id_dict
);
4162 dict_delete(nickserv_conf
.weak_password_dict
);
4163 free(auth_func_list
);
4164 free(unreg_func_list
);
4166 free(allowauth_func_list
);
4167 free(handle_merge_func_list
);
4168 free(failpw_func_list
);
4169 if (nickserv_conf
.valid_handle_regex_set
)
4170 regfree(&nickserv_conf
.valid_handle_regex
);
4171 if (nickserv_conf
.valid_nick_regex_set
)
4172 regfree(&nickserv_conf
.valid_nick_regex
);
4176 init_nickserv(const char *nick
)
4179 NS_LOG
= log_register_type("NickServ", "file:nickserv.log");
4180 reg_new_user_func(handle_new_user
);
4181 reg_nick_change_func(handle_nick_change
);
4182 reg_del_user_func(nickserv_remove_user
);
4183 reg_account_func(handle_account
);
4185 /* set up handle_inverse_flags */
4186 memset(handle_inverse_flags
, 0, sizeof(handle_inverse_flags
));
4187 for (i
=0; handle_flags
[i
]; i
++) {
4188 handle_inverse_flags
[(unsigned char)handle_flags
[i
]] = i
+ 1;
4189 flag_access_levels
[i
] = 0;
4192 conf_register_reload(nickserv_conf_read
);
4193 nickserv_opt_dict
= dict_new();
4194 nickserv_email_dict
= dict_new();
4195 dict_set_free_keys(nickserv_email_dict
, free
);
4196 dict_set_free_data(nickserv_email_dict
, nickserv_free_email_addr
);
4198 nickserv_module
= module_register("NickServ", NS_LOG
, "nickserv.help", NULL
);
4199 /* Removed qualified_host as default requirement for AUTH, REGISTER, PASS, etc. nets
4200 * can enable it per command using modcmd. (its a shitty default IMO, and now in 1.3
4201 * a big pain to disable since its nolonger in the config file. ) -Rubin
4203 modcmd_register(nickserv_module
, "AUTH", cmd_auth
, 2, MODCMD_KEEP_BOUND
, "flags", "+loghostmask", NULL
);
4204 nickserv_define_func("ALLOWAUTH", cmd_allowauth
, 0, 1, 0);
4205 nickserv_define_func("REGISTER", cmd_register
, -1, 0, 0);
4206 nickserv_define_func("OREGISTER", cmd_oregister
, 0, 1, 0);
4207 nickserv_define_func("UNREGISTER", cmd_unregister
, -1, 1, 0);
4208 nickserv_define_func("OUNREGISTER", cmd_ounregister
, 0, 1, 0);
4209 nickserv_define_func("ADDMASK", cmd_addmask
, -1, 1, 0);
4210 nickserv_define_func("OADDMASK", cmd_oaddmask
, 0, 1, 0);
4211 nickserv_define_func("DELMASK", cmd_delmask
, -1, 1, 0);
4212 nickserv_define_func("ODELMASK", cmd_odelmask
, 0, 1, 0);
4213 nickserv_define_func("PASS", cmd_pass
, -1, 1, 0);
4214 nickserv_define_func("SET", cmd_set
, -1, 1, 0);
4215 nickserv_define_func("OSET", cmd_oset
, 0, 1, 0);
4216 nickserv_define_func("ACCOUNTINFO", cmd_handleinfo
, -1, 0, 0);
4217 nickserv_define_func("USERINFO", cmd_userinfo
, -1, 1, 0);
4218 nickserv_define_func("RENAME", cmd_rename_handle
, -1, 1, 0);
4219 nickserv_define_func("VACATION", cmd_vacation
, -1, 1, 0);
4220 nickserv_define_func("MERGE", cmd_merge
, 0, 1, 0);
4221 if (!nickserv_conf
.disable_nicks
) {
4222 /* nick management commands */
4223 nickserv_define_func("REGNICK", cmd_regnick
, -1, 1, 0);
4224 nickserv_define_func("OREGNICK", cmd_oregnick
, 0, 1, 0);
4225 nickserv_define_func("UNREGNICK", cmd_unregnick
, -1, 1, 0);
4226 nickserv_define_func("OUNREGNICK", cmd_ounregnick
, 0, 1, 0);
4227 nickserv_define_func("NICKINFO", cmd_nickinfo
, -1, 1, 0);
4228 nickserv_define_func("RECLAIM", cmd_reclaim
, -1, 1, 0);
4230 if (nickserv_conf
.email_enabled
) {
4231 nickserv_define_func("AUTHCOOKIE", cmd_authcookie
, -1, 0, 0);
4232 nickserv_define_func("RESETPASS", cmd_resetpass
, -1, 0, 0);
4233 nickserv_define_func("COOKIE", cmd_cookie
, -1, 0, 0);
4234 nickserv_define_func("DELCOOKIE", cmd_delcookie
, -1, 1, 0);
4235 nickserv_define_func("ODELCOOKIE", cmd_odelcookie
, 0, 1, 0);
4236 dict_insert(nickserv_opt_dict
, "EMAIL", opt_email
);
4238 nickserv_define_func("GHOST", cmd_ghost
, -1, 1, 0);
4239 /* miscellaneous commands */
4240 nickserv_define_func("STATUS", cmd_status
, -1, 0, 0);
4241 nickserv_define_func("SEARCH", cmd_search
, 100, 1, 0);
4242 nickserv_define_func("SEARCH UNREGISTER", NULL
, 800, 1, 0);
4243 nickserv_define_func("MERGEDB", cmd_mergedb
, 999, 1, 0);
4244 nickserv_define_func("CHECKPASS", cmd_checkpass
, 601, 1, 0);
4246 dict_insert(nickserv_opt_dict
, "INFO", opt_info
);
4247 dict_insert(nickserv_opt_dict
, "WIDTH", opt_width
);
4248 dict_insert(nickserv_opt_dict
, "TABLEWIDTH", opt_tablewidth
);
4249 dict_insert(nickserv_opt_dict
, "COLOR", opt_color
);
4250 dict_insert(nickserv_opt_dict
, "PRIVMSG", opt_privmsg
);
4251 dict_insert(nickserv_opt_dict
, "AUTOHIDE", opt_autohide
);
4252 dict_insert(nickserv_opt_dict
, "STYLE", opt_style
);
4253 dict_insert(nickserv_opt_dict
, "PASS", opt_password
);
4254 dict_insert(nickserv_opt_dict
, "PASSWORD", opt_password
);
4255 dict_insert(nickserv_opt_dict
, "FLAGS", opt_flags
);
4256 dict_insert(nickserv_opt_dict
, "ACCESS", opt_level
);
4257 dict_insert(nickserv_opt_dict
, "LEVEL", opt_level
);
4258 dict_insert(nickserv_opt_dict
, "EPITHET", opt_epithet
);
4259 dict_insert(nickserv_opt_dict
, "NOTE", opt_note
);
4260 if (nickserv_conf
.titlehost_suffix
) {
4261 dict_insert(nickserv_opt_dict
, "TITLE", opt_title
);
4262 dict_insert(nickserv_opt_dict
, "FAKEHOST", opt_fakehost
);
4264 dict_insert(nickserv_opt_dict
, "ANNOUNCEMENTS", opt_announcements
);
4265 dict_insert(nickserv_opt_dict
, "MAXLOGINS", opt_maxlogins
);
4266 dict_insert(nickserv_opt_dict
, "LANGUAGE", opt_language
);
4268 nickserv_handle_dict
= dict_new();
4269 dict_set_free_keys(nickserv_handle_dict
, free
);
4270 dict_set_free_data(nickserv_handle_dict
, free_handle_info
);
4272 nickserv_id_dict
= dict_new();
4273 dict_set_free_keys(nickserv_id_dict
, free
);
4275 nickserv_nick_dict
= dict_new();
4276 dict_set_free_data(nickserv_nick_dict
, free
);
4278 nickserv_allow_auth_dict
= dict_new();
4280 userList_init(&curr_helpers
);
4283 const char *modes
= conf_get_data("services/nickserv/modes", RECDB_QSTRING
);
4284 nickserv
= AddService(nick
, modes
? modes
: NULL
, "Nick Services", NULL
);
4285 nickserv_service
= service_register(nickserv
);
4287 saxdb_register("NickServ", nickserv_saxdb_read
, nickserv_saxdb_write
);
4288 reg_exit_func(nickserv_db_cleanup
);
4289 if(nickserv_conf
.handle_expire_frequency
)
4290 timeq_add(now
+ nickserv_conf
.handle_expire_frequency
, expire_handles
, NULL
);
4291 message_register_table(msgtab
);